diff options
author | Dave Chinner <dchinner@redhat.com> | 2010-07-20 03:53:59 -0400 |
---|---|---|
committer | Alex Elder <aelder@sgi.com> | 2010-07-26 14:16:49 -0400 |
commit | 4a7edddcb5b14ddb5962e6906b6fd6b500d7a361 (patch) | |
tree | e62253cc40f36bfa631f0dd316a16ac987d11dd4 /fs/xfs/xfs_inode.c | |
parent | 438697064aaa2f64e0fcc6586582a3e7ec36005b (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>
Diffstat (limited to 'fs/xfs/xfs_inode.c')
-rw-r--r-- | fs/xfs/xfs_inode.c | 20 |
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 | } |