]> git.hungrycats.org Git - linux/commit
[PATCH] hpfs: fix locking scheme
authorAlexander Viro <viro@www.linux.org.uk>
Thu, 18 Mar 2004 05:24:22 +0000 (21:24 -0800)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Thu, 18 Mar 2004 05:24:22 +0000 (21:24 -0800)
commit9c96c8be372e7e3ce26e7b0e14ab9e7ff22cf068
treee5979abffc5fc3903a9ca2ac510b25c0ccd6de92
parentd9013aaeb1258b30e169e904b5d4229118507b42
[PATCH] hpfs: fix locking scheme

Fixed the locking scheme.  The need of extra locking was caused by
the fact that hpfs_write_inode() must update directory entry; since HPFS
directories are implemented as b-trees, we must provide protection both
against rename() (to make sure that we update the entry in right directory)
and against rebalancing of the parent.

Old scheme had both deadlocks and races - to start with, we had no
protection against rename()/unlink()/rmdir(), since (a) locking parent
was done without any warranties that it will remain our parent and (b)
check that we still have a directory entry (== have positive nlink) was
done before we tried to lock the parent.  Moreover, iget serialization
killed two steps ago gave immediate deadlocks if iget() of parent had
triggered another hpfs_write_inode().

New scheme introduces another per-inode semaphore (hpfs-only,
obviously) protecting the reference to parent.  It's taken on
rename/rmdir/unlink victims and inode being moved by rename.  Old semaphores
are taken only on parent(s) and only after we grab one(s) of the new kind.
hpfs_write_inode() gets the new semaphore on our inode, checks nlink and
if it's non-zero grabs parent and takes the old semaphore on it.

Order among the semaphores of the same kind is arbitrary - the only
function that might take more than one of the same kind is hpfs_rename()
and it's serialized by VFS.

We might get away with only one semaphore, but then the ordering
issues would bite us big way - we would have to make sure that child is
always locked before parent (hpfs_write_inode() leaves no other choice)
and while that's easy to do for almost all operations, rename() is a bitch -
as always.  And per-superblock rwsem giving rename() vs. write_inode()
exclusion on hpfs would make the entire thing too baroque for my taste.
->readdir() takes no locks at all (protection against directory
modifications is provided by VFS exclusion), ditto for ->lookup().
->llseek() on directories switched to use of (VFS) ->i_sem, so
it's safe from directory modifications and ->readdir() is safe from it -
no hpfs locks are needed here.
fs/hpfs/buffer.c
fs/hpfs/dir.c
fs/hpfs/file.c
fs/hpfs/hpfs_fn.h
fs/hpfs/inode.c
fs/hpfs/namei.c
fs/hpfs/super.c
include/linux/hpfs_fs_i.h