aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAndrew Morton <akpm@osdl.org>2004-07-02 20:03:25 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-07-02 20:03:25 -0700
commitb10be47da1539321703a76763a27b373324a92f9 (patch)
tree99112e214879afbf68c97a911a135cad96a586f6 /fs
parent114a8aeca85db43a29a6cce7e27c5ce1dc919a69 (diff)
downloadhistory-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.c8
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) {