summaryrefslogtreecommitdiff
path: root/include/linux
diff options
context:
space:
mode:
authorAlexander Viro <viro@www.linux.org.uk>2004-03-17 21:24:22 -0800
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-03-17 21:24:22 -0800
commit9c96c8be372e7e3ce26e7b0e14ab9e7ff22cf068 (patch)
treee5979abffc5fc3903a9ca2ac510b25c0ccd6de92 /include/linux
parentd9013aaeb1258b30e169e904b5d4229118507b42 (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.h3
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;
};