Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Jan Kara and committed by
Linus Torvalds
335e92e8 423bec43

+6 -6
+1 -1
fs/ext2/xattr.c
··· 835 835 struct mb_cache_entry *ce; 836 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 839 if (!ce) 840 840 return -ENOMEM; 841 841 error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, &hash);
+1 -1
fs/ext3/xattr.c
··· 1126 1126 struct mb_cache_entry *ce; 1127 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 1130 if (!ce) { 1131 1131 ea_bdebug(bh, "out of memory"); 1132 1132 return;
+1 -1
fs/ext4/xattr.c
··· 1386 1386 struct mb_cache_entry *ce; 1387 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 1390 if (!ce) { 1391 1391 ea_bdebug(bh, "out of memory"); 1392 1392 return;
+2 -2
fs/mbcache.c
··· 399 399 * if no more memory was available. 400 400 */ 401 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 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 407 if (ce) { 408 408 atomic_inc(&cache->c_entry_count); 409 409 INIT_LIST_HEAD(&ce->e_lru_list);
+1 -1
include/linux/mbcache.h
··· 34 34 35 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 38 int mb_cache_entry_insert(struct mb_cache_entry *, struct block_device *, 39 39 sector_t, unsigned int[]); 40 40 void mb_cache_entry_release(struct mb_cache_entry *);