diff options
author | Andrew Morton <akpm@osdl.org> | 2004-07-02 20:03:25 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-07-02 20:03:25 -0700 |
commit | b10be47da1539321703a76763a27b373324a92f9 (patch) | |
tree | 99112e214879afbf68c97a911a135cad96a586f6 /fs | |
parent | 114a8aeca85db43a29a6cce7e27c5ce1dc919a69 (diff) | |
download | history-b10be47da1539321703a76763a27b373324a92f9.tar.gz |
[PATCH] err1-40: sysvfs locking fix
Found by the new Stanford locking checker.
Minimal fix for a deadlock in sysvfs: get_branch() can take
read_lock(&pointers_lock), but one caller already has a write_lock.
Perhaps some of the "oh we raced, drop everything and try again" logic in
there can go away now, but this is enugh to fix the obvious deadlock.
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/sysv/itree.c | 8 |
1 files changed, 5 insertions, 3 deletions
diff --git a/fs/sysv/itree.c b/fs/sysv/itree.c index 60b40506748dab..490188b38e41df 100644 --- a/fs/sysv/itree.c +++ b/fs/sysv/itree.c @@ -81,6 +81,9 @@ static inline u32 *block_end(struct buffer_head *bh) return (u32*)((char*)bh->b_data + bh->b_size); } +/* + * Requires read_lock(&pointers_lock) or write_lock(&pointers_lock) + */ static Indirect *get_branch(struct inode *inode, int depth, int offsets[], @@ -100,18 +103,15 @@ static Indirect *get_branch(struct inode *inode, bh = sb_bread(sb, block); if (!bh) goto failure; - read_lock(&pointers_lock); if (!verify_chain(chain, p)) goto changed; add_chain(++p, bh, (u32*)bh->b_data + *++offsets); - read_unlock(&pointers_lock); if (!p->key) goto no_block; } return NULL; changed: - read_unlock(&pointers_lock); brelse(bh); *err = -EAGAIN; goto no_block; @@ -213,7 +213,9 @@ static int get_block(struct inode *inode, sector_t iblock, struct buffer_head *b goto out; reread: + read_lock(&pointers_lock); partial = get_branch(inode, depth, offsets, chain, &err); + read_unlock(&pointers_lock); /* Simplest case - block found, no allocation needed */ if (!partial) { |