ufs: don't use lock_ufs() for block pointers tree protection
authorAl Viro <viro@zeniv.linux.org.uk>
Wed, 17 Jun 2015 16:02:56 +0000 (12:02 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Mon, 6 Jul 2015 21:39:25 +0000 (17:39 -0400)
commit724bb09fdc06d4ff03757b25d6dba9ef1b133e8f
tree5ef4441867f681e132d820c78948b34c0f0ca1df
parent4af7b2c080715b9452fdaefb7ada72b4dc79593e
ufs: don't use lock_ufs() for block pointers tree protection

* stores to block pointers are under per-inode seqlock (meta_lock) and
mutex (truncate_mutex)
* fetches of block pointers are either under truncate_mutex, or wrapped
into seqretry loop on meta_lock
* all changes of ->i_size are under truncate_mutex and i_mutex
* all changes of ->i_lastfrag are under truncate_mutex

It's similar to what ext2 is doing; the main difference is that unlike
ext2 we can't rely upon the atomicity of stores into block pointers -
on UFS2 they are 64bit.  So we can't cut the corner when switching
a pointer from NULL to non-NULL as we could in ext2_splice_branch()
and need to use meta_lock on all modifications.

We use seqlock where ext2 uses rwlock; ext2 could probably also benefit
from such change...

Another non-trivial difference is that with UFS we *cannot* have reader
grab truncate_mutex in case of race - it has to keep retrying.  That
might be possible to change, but not until we lift tail unpacking
several levels up in call chain.

After that commit we do *NOT* hold fs-wide serialization on accesses
to block pointers anymore.  Moreover, lock_ufs() can become a normal
mutex now - it's only used on statfs, remount and sync_fs and none
of those uses are recursive.  As the matter of fact, *now* it can be
collapsed with ->s_lock, and be eventually replaced with saner
per-cylinder-group spinlocks, but that's a separate story.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/ufs/balloc.c
fs/ufs/inode.c
fs/ufs/super.c
fs/ufs/truncate.c
fs/ufs/ufs.h