[RFC][PATCHES] struct fderr

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



	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.




[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [NTFS 3]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [NTFS 3]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux