1) ->statfs() changed. Now it takes _kernelspace_ pointer to struct statfs
(and doesn't have to call copy_to_user()). It also expects the buffer filled
with -1's (default value for fields unsupported by filesystem). It _doesn't_
get 'bufsize' argument anymore.

2) vfs_statfs() function is provided. Prototype:
        int vfs_statfs(struct super_block *sb, struct statfs *buf);
It does sanity checks, fills the buffer and calls the method. Please, use it
instead of raw ->statfs().

Rationale:
        All instances of statfs() used local struct statfs and ended with
copy_to_user(). It was not needed by majority of callers (as the matter of
fact, it had hurt, because they had to play with setfs() and stuff). So moving
the call of copy_to_user() into the 3 callers that needed it was a pure win.
Now, gathering sanity checks was also an obvious step - we had a lot of
inconsistent stuff here, up to oopsable _lack_ of said checks. After that we
didn't need 'bufsize' anymore, since all initialization could be done by
vfs_statfs(). Result: lots of crud went away.

3) rename() now _may_ be done over the busy empty directory. If filesystem
doesn't want to support such thing - check for d_unhashed(new_dentry) in
foofs_rename(). If it returns true - fine, you are the sole owner of dentry.
Otherwise it's busy. Due to new locking in fs/namei.c (see below) we are
protected against creation/removal of links in the target of rename. So the
question being whether your fs can deal with removed-but-opened directories.
See minix/namei.c for example of changes needed if you _don't_ want to
support that stuff.

4) Full set of vfs_<operation>() is provided for directories. Well, almost -
no vfs_lookup() so far. Yes, it's a bunch of analogs to VOP_FOOBAR() in 4.4.

5) New locking scheme in fs/namei.c. This one deserves more detailed
description.
        We got an additional semaphore - ->i_zombie.
        It gets grabbed only after all ->i_sem's are already taken.
        It gets grabbed on parent(s) during anything that
creates/removes/renames links.
        It also gets grabbed on the victim in rmdir() and in
directory-overwriting rename().
        If several inodes need ->i_zombie to be grabbed that is done in
memory order (sorted by address of semaphore). Yup, in the worst case it's
triple_down(). It _did_ hurt...
        In case of rmdir() we don't take ->i_sem on victim as we used to
do - ->i_zombie provides enough protection.

Rationale:
        That way we always know all inodes we need ->i_sem for from the
very beginning. Once ->i_sem is taken on parent we are guaranteed that
its immediate children will not change their status. So we can safely
decide what locking we need _after_ that. ->i_zombie taken on an object
guarantees that nobody else will come and create/remove something there.
So foo_rmdir()/foo_rename() may safely do emptiness checks and be sure
that nothing evil will race with them.
        That way we can finally remove the wart in rename() - -EBUSY if
we were renaming a directory and target (a) existed and (b) was in use.
Now this behaviour is not mandatory. If filesystem can handle such case it's
welcome to do so.
        It also allows to do checks for directory being removed in safe
way _from_ _VFS_. I.e. we can put the semantics of that case into VFS (which
will increase the number of filesystems being able to cope with it big way
_and_ remove bloat from ext2/ufs).
        Contention on ->i_zombie is going to be minimal - normally we grab
->i_sem immediately before.
        Moreover, we now can start taking nfsfh.c code into filesystems -
darn rename() target locking was a major PITA and now rename() doesn't depend
on the dentry being invisible.

Reply via email to