diff options
author | Jan Kara <jack@suse.cz> | 2008-04-15 17:34:43 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-15 22:35:41 -0400 |
commit | 335e92e8a515420bd47a6b0f01cb9a206c0ed6e4 (patch) | |
tree | 1518f9afa7ac7047be2c86481b3dbc12f8cc9282 | |
parent | 423bec43079a2942a3004034df7aad76469758d8 (diff) |
vfs: fix possible deadlock in ext2, ext3, ext4 when using xattrs
mb_cache_entry_alloc() was allocating cache entries with GFP_KERNEL. But
filesystems are calling this function while holding xattr_sem so possible
recursion into the fs violates locking ordering of xattr_sem and transaction
start / i_mutex for ext2-4. Change mb_cache_entry_alloc() so that filesystems
can specify desired gfp mask and use GFP_NOFS from all of them.
Signed-off-by: Jan Kara <jack@suse.cz>
Reported-by: Dave Jones <davej@redhat.com>
Cc: <linux-ext4@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | fs/ext2/xattr.c | 2 | ||||
-rw-r--r-- | fs/ext3/xattr.c | 2 | ||||
-rw-r--r-- | fs/ext4/xattr.c | 2 | ||||
-rw-r--r-- | fs/mbcache.c | 4 | ||||
-rw-r--r-- | include/linux/mbcache.h | 2 |
5 files changed, 6 insertions, 6 deletions
diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c index 3e8683dbb13f..a99d46f3b26e 100644 --- a/fs/ext2/xattr.c +++ b/fs/ext2/xattr.c | |||
@@ -835,7 +835,7 @@ ext2_xattr_cache_insert(struct buffer_head *bh) | |||
835 | struct mb_cache_entry *ce; | 835 | struct mb_cache_entry *ce; |
836 | int error; | 836 | int error; |
837 | 837 | ||
838 | ce = mb_cache_entry_alloc(ext2_xattr_cache); | 838 | ce = mb_cache_entry_alloc(ext2_xattr_cache, GFP_NOFS); |
839 | if (!ce) | 839 | if (!ce) |
840 | return -ENOMEM; | 840 | return -ENOMEM; |
841 | error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, &hash); | 841 | error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, &hash); |
diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c index a6ea4d6a8bb2..42856541e9a5 100644 --- a/fs/ext3/xattr.c +++ b/fs/ext3/xattr.c | |||
@@ -1126,7 +1126,7 @@ ext3_xattr_cache_insert(struct buffer_head *bh) | |||
1126 | struct mb_cache_entry *ce; | 1126 | struct mb_cache_entry *ce; |
1127 | int error; | 1127 | int error; |
1128 | 1128 | ||
1129 | ce = mb_cache_entry_alloc(ext3_xattr_cache); | 1129 | ce = mb_cache_entry_alloc(ext3_xattr_cache, GFP_NOFS); |
1130 | if (!ce) { | 1130 | if (!ce) { |
1131 | ea_bdebug(bh, "out of memory"); | 1131 | ea_bdebug(bh, "out of memory"); |
1132 | return; | 1132 | return; |
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index d7962139c010..e9054c1c7d93 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c | |||
@@ -1386,7 +1386,7 @@ ext4_xattr_cache_insert(struct buffer_head *bh) | |||
1386 | struct mb_cache_entry *ce; | 1386 | struct mb_cache_entry *ce; |
1387 | int error; | 1387 | int error; |
1388 | 1388 | ||
1389 | ce = mb_cache_entry_alloc(ext4_xattr_cache); | 1389 | ce = mb_cache_entry_alloc(ext4_xattr_cache, GFP_NOFS); |
1390 | if (!ce) { | 1390 | if (!ce) { |
1391 | ea_bdebug(bh, "out of memory"); | 1391 | ea_bdebug(bh, "out of memory"); |
1392 | return; | 1392 | return; |
diff --git a/fs/mbcache.c b/fs/mbcache.c index eb31b73e7d69..ec88ff3d04a9 100644 --- a/fs/mbcache.c +++ b/fs/mbcache.c | |||
@@ -399,11 +399,11 @@ mb_cache_destroy(struct mb_cache *cache) | |||
399 | * if no more memory was available. | 399 | * if no more memory was available. |
400 | */ | 400 | */ |
401 | struct mb_cache_entry * | 401 | struct mb_cache_entry * |
402 | mb_cache_entry_alloc(struct mb_cache *cache) | 402 | mb_cache_entry_alloc(struct mb_cache *cache, gfp_t gfp_flags) |
403 | { | 403 | { |
404 | struct mb_cache_entry *ce; | 404 | struct mb_cache_entry *ce; |
405 | 405 | ||
406 | ce = kmem_cache_alloc(cache->c_entry_cache, GFP_KERNEL); | 406 | ce = kmem_cache_alloc(cache->c_entry_cache, gfp_flags); |
407 | if (ce) { | 407 | if (ce) { |
408 | atomic_inc(&cache->c_entry_count); | 408 | atomic_inc(&cache->c_entry_count); |
409 | INIT_LIST_HEAD(&ce->e_lru_list); | 409 | INIT_LIST_HEAD(&ce->e_lru_list); |
diff --git a/include/linux/mbcache.h b/include/linux/mbcache.h index 99e044b4efc6..a09b84e4fdb4 100644 --- a/include/linux/mbcache.h +++ b/include/linux/mbcache.h | |||
@@ -34,7 +34,7 @@ void mb_cache_destroy(struct mb_cache *); | |||
34 | 34 | ||
35 | /* Functions on cache entries */ | 35 | /* Functions on cache entries */ |
36 | 36 | ||
37 | struct mb_cache_entry *mb_cache_entry_alloc(struct mb_cache *); | 37 | struct mb_cache_entry *mb_cache_entry_alloc(struct mb_cache *, gfp_t); |
38 | int mb_cache_entry_insert(struct mb_cache_entry *, struct block_device *, | 38 | int mb_cache_entry_insert(struct mb_cache_entry *, struct block_device *, |
39 | sector_t, unsigned int[]); | 39 | sector_t, unsigned int[]); |
40 | void mb_cache_entry_release(struct mb_cache_entry *); | 40 | void mb_cache_entry_release(struct mb_cache_entry *); |