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>
This commit is contained in:
parent
438697064a
commit
4a7edddcb5
1 changed files with 11 additions and 9 deletions
|
@ -422,7 +422,7 @@ xfs_iformat(
|
|||
if (!XFS_DFORK_Q(dip))
|
||||
return 0;
|
||||
ASSERT(ip->i_afp == NULL);
|
||||
ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP);
|
||||
ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP | KM_NOFS);
|
||||
ip->i_afp->if_ext_max =
|
||||
XFS_IFORK_ASIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t);
|
||||
switch (dip->di_aformat) {
|
||||
|
@ -505,7 +505,7 @@ xfs_iformat_local(
|
|||
ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
|
||||
else {
|
||||
real_size = roundup(size, 4);
|
||||
ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP);
|
||||
ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP | KM_NOFS);
|
||||
}
|
||||
ifp->if_bytes = size;
|
||||
ifp->if_real_bytes = real_size;
|
||||
|
@ -632,7 +632,7 @@ xfs_iformat_btree(
|
|||
}
|
||||
|
||||
ifp->if_broot_bytes = size;
|
||||
ifp->if_broot = kmem_alloc(size, KM_SLEEP);
|
||||
ifp->if_broot = kmem_alloc(size, KM_SLEEP | KM_NOFS);
|
||||
ASSERT(ifp->if_broot != NULL);
|
||||
/*
|
||||
* Copy and convert from the on-disk structure
|
||||
|
@ -2191,7 +2191,7 @@ xfs_iroot_realloc(
|
|||
*/
|
||||
if (ifp->if_broot_bytes == 0) {
|
||||
new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(rec_diff);
|
||||
ifp->if_broot = kmem_alloc(new_size, KM_SLEEP);
|
||||
ifp->if_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS);
|
||||
ifp->if_broot_bytes = (int)new_size;
|
||||
return;
|
||||
}
|
||||
|
@ -2207,7 +2207,7 @@ xfs_iroot_realloc(
|
|||
new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(new_max);
|
||||
ifp->if_broot = kmem_realloc(ifp->if_broot, new_size,
|
||||
(size_t)XFS_BMAP_BROOT_SPACE_CALC(cur_max), /* old size */
|
||||
KM_SLEEP);
|
||||
KM_SLEEP | KM_NOFS);
|
||||
op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
|
||||
ifp->if_broot_bytes);
|
||||
np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
|
||||
|
@ -2233,7 +2233,7 @@ xfs_iroot_realloc(
|
|||
else
|
||||
new_size = 0;
|
||||
if (new_size > 0) {
|
||||
new_broot = kmem_alloc(new_size, KM_SLEEP);
|
||||
new_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS);
|
||||
/*
|
||||
* First copy over the btree block header.
|
||||
*/
|
||||
|
@ -2337,7 +2337,8 @@ xfs_idata_realloc(
|
|||
real_size = roundup(new_size, 4);
|
||||
if (ifp->if_u1.if_data == NULL) {
|
||||
ASSERT(ifp->if_real_bytes == 0);
|
||||
ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP);
|
||||
ifp->if_u1.if_data = kmem_alloc(real_size,
|
||||
KM_SLEEP | KM_NOFS);
|
||||
} else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) {
|
||||
/*
|
||||
* Only do the realloc if the underlying size
|
||||
|
@ -2348,11 +2349,12 @@ xfs_idata_realloc(
|
|||
kmem_realloc(ifp->if_u1.if_data,
|
||||
real_size,
|
||||
ifp->if_real_bytes,
|
||||
KM_SLEEP);
|
||||
KM_SLEEP | KM_NOFS);
|
||||
}
|
||||
} else {
|
||||
ASSERT(ifp->if_real_bytes == 0);
|
||||
ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP);
|
||||
ifp->if_u1.if_data = kmem_alloc(real_size,
|
||||
KM_SLEEP | KM_NOFS);
|
||||
memcpy(ifp->if_u1.if_data, ifp->if_u2.if_inline_data,
|
||||
ifp->if_bytes);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue