diff options
| author | Alexander Viro <viro@www.linux.org.uk> | 2004-03-17 21:24:22 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-03-17 21:24:22 -0800 |
| commit | 9c96c8be372e7e3ce26e7b0e14ab9e7ff22cf068 (patch) | |
| tree | e5979abffc5fc3903a9ca2ac510b25c0ccd6de92 /include/linux | |
| parent | d9013aaeb1258b30e169e904b5d4229118507b42 (diff) | |
[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.
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/hpfs_fs_i.h | 3 |
1 files changed, 2 insertions, 1 deletions
diff --git a/include/linux/hpfs_fs_i.h b/include/linux/hpfs_fs_i.h index ab72ea5b5248..2a0d784fea40 100644 --- a/include/linux/hpfs_fs_i.h +++ b/include/linux/hpfs_fs_i.h @@ -16,7 +16,8 @@ struct hpfs_inode_info { unsigned i_ea_uid : 1; /* file's uid is stored in ea */ unsigned i_ea_gid : 1; /* file's gid is stored in ea */ unsigned i_dirty : 1; - struct semaphore i_sem; /* semaphore */ + struct semaphore i_sem; + struct semaphore i_parent; loff_t **i_rddir_off; struct inode vfs_inode; }; |
