aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2010-07-20 03:53:59 -0400
committerAlex Elder <aelder@sgi.com>2010-07-26 14:16:49 -0400
commit4a7edddcb5b14ddb5962e6906b6fd6b500d7a361 (patch)
treee62253cc40f36bfa631f0dd316a16ac987d11dd4
parent438697064aaa2f64e0fcc6586582a3e7ec36005b (diff)
xfs: fix memory reclaim recursion deadlock on locked inode buffer
Calling into memory reclaim with a locked inode buffer can deadlock if memory reclaim tries to lock the inode buffer during inode teardown. Convert the relevant memory allocations to use KM_NOFS to avoid this deadlock condition. Reported-by: Peter Watkins <treestem@gmail.com> Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Alex Elder <aelder@sgi.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
-rw-r--r--fs/xfs/xfs_inode.c20
1 files changed, 11 insertions, 9 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 5715a9d8bcd6..4a08c91dc976 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -422,7 +422,7 @@ xfs_iformat(
422 if (!XFS_DFORK_Q(dip)) 422 if (!XFS_DFORK_Q(dip))
423 return 0; 423 return 0;
424 ASSERT(ip->i_afp == NULL); 424 ASSERT(ip->i_afp == NULL);
425 ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP); 425 ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP | KM_NOFS);
426 ip->i_afp->if_ext_max = 426 ip->i_afp->if_ext_max =
427 XFS_IFORK_ASIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); 427 XFS_IFORK_ASIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t);
428 switch (dip->di_aformat) { 428 switch (dip->di_aformat) {
@@ -505,7 +505,7 @@ xfs_iformat_local(
505 ifp->if_u1.if_data = ifp->if_u2.if_inline_data; 505 ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
506 else { 506 else {
507 real_size = roundup(size, 4); 507 real_size = roundup(size, 4);
508 ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP); 508 ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP | KM_NOFS);
509 } 509 }
510 ifp->if_bytes = size; 510 ifp->if_bytes = size;
511 ifp->if_real_bytes = real_size; 511 ifp->if_real_bytes = real_size;
@@ -632,7 +632,7 @@ xfs_iformat_btree(
632 } 632 }
633 633
634 ifp->if_broot_bytes = size; 634 ifp->if_broot_bytes = size;
635 ifp->if_broot = kmem_alloc(size, KM_SLEEP); 635 ifp->if_broot = kmem_alloc(size, KM_SLEEP | KM_NOFS);
636 ASSERT(ifp->if_broot != NULL); 636 ASSERT(ifp->if_broot != NULL);
637 /* 637 /*
638 * Copy and convert from the on-disk structure 638 * Copy and convert from the on-disk structure
@@ -2191,7 +2191,7 @@ xfs_iroot_realloc(
2191 */ 2191 */
2192 if (ifp->if_broot_bytes == 0) { 2192 if (ifp->if_broot_bytes == 0) {
2193 new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(rec_diff); 2193 new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(rec_diff);
2194 ifp->if_broot = kmem_alloc(new_size, KM_SLEEP); 2194 ifp->if_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS);
2195 ifp->if_broot_bytes = (int)new_size; 2195 ifp->if_broot_bytes = (int)new_size;
2196 return; 2196 return;
2197 } 2197 }
@@ -2207,7 +2207,7 @@ xfs_iroot_realloc(
2207 new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(new_max); 2207 new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(new_max);
2208 ifp->if_broot = kmem_realloc(ifp->if_broot, new_size, 2208 ifp->if_broot = kmem_realloc(ifp->if_broot, new_size,
2209 (size_t)XFS_BMAP_BROOT_SPACE_CALC(cur_max), /* old size */ 2209 (size_t)XFS_BMAP_BROOT_SPACE_CALC(cur_max), /* old size */
2210 KM_SLEEP); 2210 KM_SLEEP | KM_NOFS);
2211 op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1, 2211 op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
2212 ifp->if_broot_bytes); 2212 ifp->if_broot_bytes);
2213 np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1, 2213 np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
@@ -2233,7 +2233,7 @@ xfs_iroot_realloc(
2233 else 2233 else
2234 new_size = 0; 2234 new_size = 0;
2235 if (new_size > 0) { 2235 if (new_size > 0) {
2236 new_broot = kmem_alloc(new_size, KM_SLEEP); 2236 new_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS);
2237 /* 2237 /*
2238 * First copy over the btree block header. 2238 * First copy over the btree block header.
2239 */ 2239 */
@@ -2337,7 +2337,8 @@ xfs_idata_realloc(
2337 real_size = roundup(new_size, 4); 2337 real_size = roundup(new_size, 4);
2338 if (ifp->if_u1.if_data == NULL) { 2338 if (ifp->if_u1.if_data == NULL) {
2339 ASSERT(ifp->if_real_bytes == 0); 2339 ASSERT(ifp->if_real_bytes == 0);
2340 ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP); 2340 ifp->if_u1.if_data = kmem_alloc(real_size,
2341 KM_SLEEP | KM_NOFS);
2341 } else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) { 2342 } else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) {
2342 /* 2343 /*
2343 * Only do the realloc if the underlying size 2344 * Only do the realloc if the underlying size
@@ -2348,11 +2349,12 @@ xfs_idata_realloc(
2348 kmem_realloc(ifp->if_u1.if_data, 2349 kmem_realloc(ifp->if_u1.if_data,
2349 real_size, 2350 real_size,
2350 ifp->if_real_bytes, 2351 ifp->if_real_bytes,
2351 KM_SLEEP); 2352 KM_SLEEP | KM_NOFS);
2352 } 2353 }
2353 } else { 2354 } else {
2354 ASSERT(ifp->if_real_bytes == 0); 2355 ASSERT(ifp->if_real_bytes == 0);
2355 ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP); 2356 ifp->if_u1.if_data = kmem_alloc(real_size,
2357 KM_SLEEP | KM_NOFS);
2356 memcpy(ifp->if_u1.if_data, ifp->if_u2.if_inline_data, 2358 memcpy(ifp->if_u1.if_data, ifp->if_u2.if_inline_data,
2357 ifp->if_bytes); 2359 ifp->if_bytes);
2358 } 2360 }