From: Al Viro <viro@zeniv.linux.org.uk>
To: linux-fsdevel@vger.kernel.org
Cc: Christian Brauner <brauner@kernel.org>, Jan Kara <jack@suse.cz>,
Amir Goldstein <amir73il@gmail.com>,
Miklos Szeredi <miklos@szeredi.hu>
Subject: [RFC][PATCHES] struct fderr
Date: Fri, 4 Oct 2024 00:45:34 +0100 [thread overview]
Message-ID: <20241003234534.GM4017910@ZenIV> (raw)
overlayfs uses struct fd for the things where it does not quite
fit. There we want not "file reference or nothing" - it's "file reference
or an error". For pointers we can do that by use of ERR_PTR(); strictly
speaking, that's an abuse of C pointers, but the kernel does make sure
that the uppermost page worth of virtual addresses never gets mapped
and no architecture we care about has those as trap representations.
It might be possible to use the same trick for struct fd; however, for
most of the regular struct fd users that would be a pointless headache -
it would pessimize the code generation for no real benefit. I considered
a possibility of using represenation of ERR_PTR(-EBADF) for empty struct
fd, but that's far from being consistent among the struct fd users and
that ends up with bad code generation even for the users that want to
treat empty as "fail with -EBADF".
It's better to introduce a separate type, say, struct fderr.
Representable values:
* borrowed file reference (address of struct file instance)
* cloned file reference (address of struct file instance)
* error (a small negative integer).
With sane constructors we get rid of the field-by-field mess in
ovl_real_fdget{,_meta}() and have them serve as initializers, always
returning a valid struct fderr value.
That results in mostly sane code; however, there are several
places where we run into an unpleasant problem - the intended scope
is nested inside inode_lock()/inode_unlock(), with problematic gotos.
Possible solutions:
1) turn inode_lock() into guard-based thing. No, with the side of
"fuck, no". guard() has its uses, but
* the area covered by it should be _very_ easy to see
* it should not be mixed with gotos, now *OR* later, so
any subsequent changes in the area should remember not to use those.
* it should never fall into hands of Markus-level entities.
inode_lock fails all those; guard-based variant _will_ be abstracted
away by well-meaning folks, and it will start spreading. And existing
users are often long, have non-trivial amounts of goto-based cleanups
in them and lifetimes of the objects involved are not particularly
easy to convert to __cleanup-based variants (to put it very mildly).
We might eventually need to reconsider that, but for now the only sane
policy is "no guard-based variants of VFS locks".
2) turn the scopes into explicit compound statements.
3) take them into helper functions.
The series (in viro/vfs.git #work.fderr) tries both (2) and (3) (the
latter as incremental to the former); I would like to hear opinions
on the relative attractiveness of those variants, first and foremost
from overlayfs folks. If (3) is preferred, the last two commits of
that branch will be collapsed together; if not - the last commit
simply gets dropped.
Please, review. Individual patches are in followups.
Changes since the last time it had been posted:
* s/fd_error/fd_err/, to avoid a conflict
* s/FD_ERR/FDERR_ERR/, to have constructor names consistent
* add a followup converting the problematic scopes into
helper calls.
Al Viro (3):
introduce struct fderr, convert overlayfs uses to that
experimental: convert fs/overlayfs/file.c to CLASS(...)
[experimental] another way to deal with scopes for overlayfs real_fd-under-inode_lock
fs/overlayfs/file.c | 211 +++++++++++++++++++++++----------------------------
include/linux/file.h | 37 +++++++--
2 files changed, 128 insertions(+), 120 deletions(-)
1/3) introduce struct fderr, convert overlayfs uses to that
Similar to struct fd; unlike struct fd, it can represent
error values.
Accessors:
* fd_empty(f): true if f represents an error
* fd_file(f): just as for struct fd it yields a pointer to
struct file if fd_empty(f) is false. If
fd_empty(f) is true, fd_file(f) is guaranteed
_not_ to be an address of any object (IS_ERR()
will be true in that case)
* fd_err(f): if f represents an error, returns that error,
otherwise the return value is junk.
Constructors:
* ERR_FDERR(-E...): an instance encoding given error [ERR_FDERR, perhaps?]
* BORROWED_FDERR(file): if file points to a struct file instance,
return a struct fderr representing that file
reference with no flags set.
if file is an ERR_PTR(-E...), return a struct
fderr representing that error.
file MUST NOT be NULL.
* CLONED_FDERR(file): similar, but in case when file points to
a struct file instance, set FDPUT_FPUT in flags.
Same destructor as for struct fd; I'm not entirely convinced that
playing with _Generic is a good idea here, but for now let's go
that way...
2/3) experimental: convert fs/overlayfs/file.c to CLASS(...)
There are four places where we end up adding an extra scope
covering just the range from constructor to destructor;
not sure if that's the best way to handle that.
The functions in question are ovl_write_iter(), ovl_splice_write(),
ovl_fadvise() and ovl_copyfile().
I still don't like the way we have to deal with the scopes, but...
use of guard() for inode_lock()/inode_unlock() is a gutter too deep,
as far as I'm concerned.
3/3) [experimental] another way to deal with scopes for overlayfs real_fd-under-inode_lock
Takes the 4 scopes mentioned in the previous commit into helper
functions. To be folded into the previous if both go in.
next reply other threads:[~2024-10-03 23:45 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-10-03 23:45 Al Viro [this message]
2024-10-03 23:47 ` [RFC][PATCHES] struct fderr Al Viro
2024-10-03 23:47 ` introduce struct fderr, convert overlayfs uses to that Al Viro
2024-10-04 9:43 ` Christian Brauner
2024-10-04 10:47 ` Amir Goldstein
2024-10-17 19:47 ` Al Viro
2024-10-03 23:48 ` [PATCH 2/3] experimental: convert fs/overlayfs/file.c to CLASS(...) Al Viro
2024-10-04 9:40 ` Christian Brauner
2024-10-03 23:48 ` [PATCH 3/3] [experimental] another way to deal with scopes for overlayfs real_fd-under-inode_lock Al Viro
2024-10-04 10:32 ` [RFC][PATCHES] struct fderr Amir Goldstein
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20241003234534.GM4017910@ZenIV \
--to=viro@zeniv.linux.org.uk \
--cc=amir73il@gmail.com \
--cc=brauner@kernel.org \
--cc=jack@suse.cz \
--cc=linux-fsdevel@vger.kernel.org \
--cc=miklos@szeredi.hu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).