xfs: reclaim bug fixes
cover xfs: reclaim bug fixes
The following patches fix excessive CPU consumption during inode cache shrinking when filesystems have lots of allocation groups as well as prevent a couple of lockdep reports that were found during testing. Also included is a fix for a reclaim recursion deadlock when allocating memory during inode initialisation.
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
PATCH 1/5 xfs: track AGs with reclaimable inodes in per-ag radix tree
From: Dave Chinner <[email protected]>
https://bugzilla.kernel.org/show_bug.cgi?id=16348
When the filesystem grows to a large number of allocation groups, the summing of recalimable inodes gets expensive. In many cases, most AGs won't have any reclaimable inodes and so we are wasting CPU time aggregating over these AGs. This is particularly important for the inode shrinker that gets called frequently under memory pressure.
To avoid the overhead, track AGs with reclaimable inodes in the per-ag radix tree so that we can find all the AGs with reclaimable inodes via a simple gang tag lookup. This involves setting the tag when the first reclaimable inode is tracked in the AG, and removing the tag when the last reclaimable inode is removed from the tree. Then the summation process becomes a loop walking the radix tree summing AGs with the reclaim tag set.
This significantly reduces the overhead of scanning - a 6400 AG filesystea now only uses about 25% of a cpu in kswapd while slab reclaim progresses instead of being permanently stuck at 100% CPU and making little progress. Clean filesystems filesystems will see no overhead and the overhead only increases linearly with the number of dirty AGs.
--- fs/xfs/linux-2.6/xfs_sync.c | 71 +++++++++++++++++++++++++++++++++++++---- fs/xfs/linux-2.6/xfs_trace.h | 3 ++ 2 files changed, 67 insertions(+), 7 deletions(-)
fs/xfs/linux-2.6/xfs_sync.c +64 -7
@@ -133,6 +133,41 @@ restart:return last_error; } +/* +* Select the next per-ag structure to iterate during the walk. The reclaim +* walk is optimised only to walk AGs with reclaimable inodes in them. +*/ +static struct xfs_perag * +xfs_inode_ag_iter_next_pag ( +struct xfs_mount *mp, +xfs_agnumber_t *first, +int tag) +{ +struct xfs_perag *pag =NULL ; + +if (tag ==XFS_ICI_RECLAIM_TAG ) { +int found; +int ref; + +spin_lock (&mp->m_perag_lock); + found =radix_tree_gang_lookup_tag (&mp->m_perag_tree, + (void **)&pag, *first,1 , tag); +if (found <=0 ) { +spin_unlock (&mp->m_perag_lock); +return NULL ; + } + *first = pag->pag_agno +1 ; +/* open coded pag reference increment */ + ref =atomic_inc_return (&pag->pag_ref); +spin_unlock (&mp->m_perag_lock); +trace_xfs_perag_get_reclaim (mp, pag->pag_agno, ref, _RET_IP_); + }else { + pag =xfs_perag_get (mp, *first); + (*first)++; + } +return pag; +} + int xfs_inode_ag_iterator( struct xfs_mount *mp,
@@ -143,16 +178,15 @@ xfs_inode_ag_iterator(int exclusive, int *nr_to_scan) { + struct xfs_perag *pag;int error =0 ;int last_error =0 ;xfs_agnumber_t ag;int nr; nr = nr_to_scan ? *nr_to_scan :INT_MAX ; -for (ag =0 ; ag < mp->m_sb.sb_agcount; ag++) { -struct xfs_perag *pag; - - pag =xfs_perag_get (mp, ag); + ag =0 ; +while ((pag =xfs_inode_ag_iter_next_pag (mp, &ag, tag))) { error =xfs_inode_ag_walk (mp, pag, execute, flags, tag, exclusive, &nr);xfs_perag_put (pag);
@@ -628,6 +662,17 @@ __xfs_inode_set_reclaim_tag(radix_tree_tag_set (&pag->pag_ici_root,XFS_INO_TO_AGINO (ip->i_mount, ip->i_ino),XFS_ICI_RECLAIM_TAG ); + +if (!pag->pag_ici_reclaimable) { +/* propagate the reclaim tag up into the perag radix tree */ +spin_lock (&ip->i_mount->m_perag_lock); +radix_tree_tag_set (&ip->i_mount->m_perag_tree, +XFS_INO_TO_AGNO (ip->i_mount, ip->i_ino), +XFS_ICI_RECLAIM_TAG ); +spin_unlock (&ip->i_mount->m_perag_lock); +trace_xfs_perag_set_reclaim (ip->i_mount, pag->pag_agno, +-1 , _RET_IP_); + } pag->pag_ici_reclaimable++; }
@@ -662,6 +707,16 @@ __xfs_inode_clear_reclaim_tag(radix_tree_tag_clear (&pag->pag_ici_root,XFS_INO_TO_AGINO (mp, ip->i_ino),XFS_ICI_RECLAIM_TAG ); pag->pag_ici_reclaimable--; +if (!pag->pag_ici_reclaimable) { +/* clear the reclaim tag from the perag radix tree */ +spin_lock (&ip->i_mount->m_perag_lock); +radix_tree_tag_clear (&ip->i_mount->m_perag_tree, +XFS_INO_TO_AGNO (ip->i_mount, ip->i_ino), +XFS_ICI_RECLAIM_TAG ); +spin_unlock (&ip->i_mount->m_perag_lock); +trace_xfs_perag_clear_reclaim (ip->i_mount, pag->pag_agno, +-1 , _RET_IP_); + } }/*
@@ -832,7 +887,7 @@ xfs_reclaim_inode_shrink(struct xfs_mount *mp;struct xfs_perag *pag;xfs_agnumber_t ag; -int reclaimable =0 ; +int reclaimable;if (nr_to_scan) {if (!(gfp_mask & __GFP_FS))
@@ -849,9 +904,11 @@ xfs_reclaim_inode_shrink( }down_read (&xfs_mount_list_lock); + reclaimable =0 ;list_for_each_entry (mp, &xfs_mount_list, m_mplist) { -for (ag =0 ; ag < mp->m_sb.sb_agcount; ag++) { - pag =xfs_perag_get (mp, ag); + ag =0 ; +while ((pag =xfs_inode_ag_iter_next_pag (mp, &ag, +XFS_ICI_RECLAIM_TAG ))) { reclaimable += pag->pag_ici_reclaimable;xfs_perag_put (pag); }
fs/xfs/linux-2.6/xfs_trace.h +3 -0
@@ -124,7 +124,10 @@ DEFINE_EVENT(xfs_perag_class, name, \ unsigned long caller_ip), \ TP_ARGS(mp, agno, refcount, caller_ip)) DEFINE_PERAG_REF_EVENT(xfs_perag_get); +DEFINE_PERAG_REF_EVENT (xfs_perag_get_reclaim);DEFINE_PERAG_REF_EVENT (xfs_perag_put); +DEFINE_PERAG_REF_EVENT (xfs_perag_set_reclaim); +DEFINE_PERAG_REF_EVENT (xfs_perag_clear_reclaim); TRACE_EVENT(xfs_attr_list_node_descend, TP_PROTO(struct xfs_attr_list_context *ctx,
Signature · 6 lines
1.7.1 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 1/5] xfs: track AGs with reclaimable inodes in per-ag radix tree
Quoted 19 lines · Dave Chinner
From: Dave Chinner <[email protected]>
https://bugzilla.kernel.org/show_bug.cgi?id=16348
When the filesystem grows to a large number of allocation groups, the summing of recalimable inodes gets expensive. In many cases, most AGs won't have any reclaimable inodes and so we are wasting CPU time aggregating over these AGs. This is particularly important for the inode shrinker that gets called frequently under memory pressure.
To avoid the overhead, track AGs with reclaimable inodes in the per-ag radix tree so that we can find all the AGs with reclaimable inodes via a simple gang tag lookup. This involves setting the tag when the first reclaimable inode is tracked in the AG, and removing the tag when the last reclaimable inode is removed from the tree. Then the summation process becomes a loop walking the radix tree summing AGs with the reclaim tag set.
Quoted 5 lines
This significantly reduces the overhead of scanning - a 6400 AG filesystea now only uses about 25% of a cpu in kswapd while slab reclaim progresses instead of being permanently stuck at 100% CPU and making little progress. Clean filesystems filesystems will see no overhead and the overhead only increases linearly with the number of dirty AGs.
Using the same tag represent a perag with reclaimable inodes as the tag representing an inode is reclaimable is nicely consistent...
I have a few comments below for your consideration but they are minor (and don't even require a response).
Overall this looks good.
Quoted 28 lines
Signed-off-by Dave Chinner <[email protected]>--- fs/xfs/linux-2.6/xfs_sync.c | 71 +++++++++++++++++++++++++++++++++++++---- fs/xfs/linux-2.6/xfs_trace.h | 3 ++ 2 files changed, 67 insertions(+), 7 deletions(-)fs/xfs/linux-2.6/xfs_sync.c +14
-0@@ -133,6 +133,41 @@ restart:return last_error; } +/* +* Select the next per-ag structure to iterate during the walk. The reclaim +* walk is optimised only to walk AGs with reclaimable inodes in them. +*/ +static struct xfs_perag * +xfs_inode_ag_iter_next_pag ( +struct xfs_mount *mp, +xfs_agnumber_t *first, +int tag) +{ +struct xfs_perag *pag =NULL ; + +if (tag ==XFS_ICI_RECLAIM_TAG ) { +int found;
fs/xfs/linux-2.6/xfs_sync.c restart: · line 159
Quoted 10 lines
fs/xfs/linux-2.6/xfs_sync.c +10
-0+int ref; + +spin_lock (&mp->m_perag_lock); + found =radix_tree_gang_lookup_tag (&mp->m_perag_tree, + (void **)&pag, *first,1 , tag); +if (found <=0 ) { +spin_unlock (&mp->m_perag_lock); +return NULL ; + } + *first = pag->pag_agno +1 ;
Maybe move this below, just before the return. I.e.:
if (pag) *first = pag->pag_agno + 1;
To me it's slightly clearer that we're just setting up to search next time with the perag following the one returned.
fs/xfs/linux-2.6/xfs_sync.c restart: · line 160
Quoted 1 line
fs/xfs/linux-2.6/xfs_sync.c +1
-0+/* open coded pag reference increment */
By open-coding here you miss the assertions in xfs_perag_get(). (Though a common inline encapsulating them would have to be in a header because the two functions reside in different files.)
fs/xfs/linux-2.6/xfs_sync.c restart: · line 173
Quoted 13 lines
fs/xfs/linux-2.6/xfs_sync.c +10
-0+ ref =atomic_inc_return (&pag->pag_ref); +spin_unlock (&mp->m_perag_lock); +trace_xfs_perag_get_reclaim (mp, pag->pag_agno, ref, _RET_IP_); + }else { + pag =xfs_perag_get (mp, *first); + (*first)++; + } +return pag; +} + int xfs_inode_ag_iterator( struct xfs_mount *mp,
. . .
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 1/5] xfs: track AGs with reclaimable inodes in per-ag radix tree
Quoted 3 lines · Alex Elder
Using the same tag represent a perag with reclaimable inodes as the tag representing an inode is reclaimable is nicely consistent...
Oh, didn't notice that when reviewing it. Not sure I like it too much. If we ever grow more tags on the perag tree this might get rather confusing.
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 1/5] xfs: track AGs with reclaimable inodes in per-ag radix tree
Quoted 8 lines · Christoph Hellwig
Quoted 3 lines · Alex Elder
Using the same tag represent a perag with reclaimable inodes as the tag representing an inode is reclaimable is nicely consistent...
Oh, didn't notice that when reviewing it. Not sure I like it too much. If we ever grow more tags on the perag tree this might get rather confusing.
Sure. But it's an in-memory flag so we can change it whenever we need to. If we grow another tag on the perag tree, we can sort it out then....
Cheers,
Dave.
Signature · 7 lines
Dave Chinner [email protected] _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 1/5] xfs: track AGs with reclaimable inodes in per-ag radix tree
In reply to Alex ElderQuoted 77 lines · Alex Elder
Quoted 19 lines · Dave Chinner
From: Dave Chinner <[email protected]>
https://bugzilla.kernel.org/show_bug.cgi?id=16348
When the filesystem grows to a large number of allocation groups, the summing of recalimable inodes gets expensive. In many cases, most AGs won't have any reclaimable inodes and so we are wasting CPU time aggregating over these AGs. This is particularly important for the inode shrinker that gets called frequently under memory pressure.
To avoid the overhead, track AGs with reclaimable inodes in the per-ag radix tree so that we can find all the AGs with reclaimable inodes via a simple gang tag lookup. This involves setting the tag when the first reclaimable inode is tracked in the AG, and removing the tag when the last reclaimable inode is removed from the tree. Then the summation process becomes a loop walking the radix tree summing AGs with the reclaim tag set.
Quoted 5 lines
This significantly reduces the overhead of scanning - a 6400 AG filesystea now only uses about 25% of a cpu in kswapd while slab reclaim progresses instead of being permanently stuck at 100% CPU and making little progress. Clean filesystems filesystems will see no overhead and the overhead only increases linearly with the number of dirty AGs.
Using the same tag represent a perag with reclaimable inodes as the tag representing an inode is reclaimable is nicely consistent...
I have a few comments below for your consideration but they are minor (and don't even require a response).
Overall this looks good.
Reviewed-by Alex Elder <[email protected]>Quoted 28 lines
Signed-off-by Dave Chinner <[email protected]>--- fs/xfs/linux-2.6/xfs_sync.c | 71 +++++++++++++++++++++++++++++++++++++---- fs/xfs/linux-2.6/xfs_trace.h | 3 ++ 2 files changed, 67 insertions(+), 7 deletions(-)fs/xfs/linux-2.6/xfs_sync.c +14
-0@@ -133,6 +133,41 @@ restart:return last_error; } +/* +* Select the next per-ag structure to iterate during the walk. The reclaim +* walk is optimised only to walk AGs with reclaimable inodes in them. +*/ +static struct xfs_perag * +xfs_inode_ag_iter_next_pag ( +struct xfs_mount *mp, +xfs_agnumber_t *first, +int tag) +{ +struct xfs_perag *pag =NULL ; + +if (tag ==XFS_ICI_RECLAIM_TAG ) { +int found;fs/xfs/linux-2.6/xfs_sync.c restart: · line 159
Quoted 10 lines
fs/xfs/linux-2.6/xfs_sync.c +10
-0+int ref; + +spin_lock (&mp->m_perag_lock); + found =radix_tree_gang_lookup_tag (&mp->m_perag_tree, + (void **)&pag, *first,1 , tag); +if (found <=0 ) { +spin_unlock (&mp->m_perag_lock); +return NULL ; + } + *first = pag->pag_agno +1 ;Maybe move this below, just before the return. I.e.:
Quoted 6 lines
if (pag) *first = pag->pag_agno + 1;To me it's slightly clearer that we're just setting up to search next time with the perag following the one returned.
If found <=0, we didn't find anything in the tree. I don't know what the value of pag is going to be in this case, so we have to check the return value to determine if pag is valid or not.
The other gang lookups in XFS use the same convention...
Quoted 6 lines
fs/xfs/linux-2.6/xfs_sync.c restart: · line 160
Quoted 2 lines
fs/xfs/linux-2.6/xfs_sync.c +1
-0+/* open coded pag reference increment */ By open-coding here you miss the assertions in
xfs_perag_get(). (Though a common inline encapsulating them would have to be in a header because the two functions reside in different files.)
Yes, it misses them, but we do sufficient calls to xfs_perag_get() elsewhere that I don't think it makes much difference - we'll still get the ASSERT()s tripping, and the tracing will still point out where the problem is...
Cheers,
Dave.
Signature · 7 lines
Dave Chinner [email protected] _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH 2/5 xfs: simplify and remove xfs_ireclaim
In reply to Dave ChinnerFrom: Dave Chinner <[email protected]>
xfs_ireclaim has to get and put te pag structure because it is only called with the inode to reclaim. The one caller of this function already has a reference on the pag and a pointer to is, so move the radix tree delete to the caller and remove xfs_ireclaim completely. This avoids a xfs_perag_get/put on every inode being reclaimed.
The overhead was noticed in a bug report at:
https://bugzilla.kernel.org/show_bug.cgi?id=16348
--- fs/xfs/linux-2.6/xfs_sync.c | 31 ++++++++++++++++++++++++- fs/xfs/xfs_iget.c | 53 +------------------------------------------ fs/xfs/xfs_inode.h | 2 +- 3 files changed, 32 insertions(+), 54 deletions(-)
fs/xfs/linux-2.6/xfs_sync.c +30 -1
@@ -855,7 +855,36 @@ out: reclaim:xfs_ifunlock (ip);xfs_iunlock (ip,XFS_ILOCK_EXCL ); -xfs_ireclaim (ip); + +XFS_STATS_INC (xs_ig_reclaims); +/* +* Remove the inode from the per-AG radix tree. +* +* Because radix_tree_delete won't complain even if the item was never +* added to the tree assert that it's been there before to catch +* problems with the inode life time early on. +*/ +write_lock (&pag->pag_ici_lock); +if (!radix_tree_delete (&pag->pag_ici_root, +XFS_INO_TO_AGINO (ip->i_mount, ip->i_ino))) +ASSERT (0 ); +write_unlock (&pag->pag_ici_lock); + +/* +* Here we do an (almost) spurious inode lock in order to coordinate +* with inode cache radix tree lookups. This is because the lookup +* can reference the inodes in the cache without taking references. +* +* We make that OK here by ensuring that we wait until the inode is +* unlocked after the lookup before we go ahead and free it. We get +* both the ilock and the iolock because the code may need to drop the +* ilock one but will still hold the iolock. +*/ +xfs_ilock (ip,XFS_ILOCK_EXCL |XFS_IOLOCK_EXCL ); +xfs_qm_dqdetach (ip); +xfs_iunlock (ip,XFS_ILOCK_EXCL |XFS_IOLOCK_EXCL ); + +xfs_inode_free (ip);return error; }
fs/xfs/xfs_iget.c +1 -52
65 lines not on this page · raw message
fs/xfs/xfs_inode.h +1 -1
@@ -450,7 +450,7 @@ void xfs_ilock_demote(xfs_inode_t *, uint);int xfs_isilocked (xfs_inode_t *,uint );uint xfs_ilock_map_shared (xfs_inode_t *);void xfs_iunlock_map_shared (xfs_inode_t *,uint ); -void xfs_ireclaim (xfs_inode_t *); +void xfs_inode_free (struct xfs_inode *ip);/* * xfs_inode.c prototypes.
Signature · 6 lines
1.7.1 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 2/5] xfs: simplify and remove xfs_ireclaim
Quoted 11 lines · Dave Chinner
From: Dave Chinner <[email protected]>
xfs_ireclaimhas to get and put te pag structure because it is only called with the inode to reclaim. The one caller of this function already has a reference on the pag and a pointer to is, so move the radix tree delete to the caller and removexfs_ireclaimcompletely. This avoids a xfs_perag_get/put on every inode being reclaimed.The overhead was noticed in a bug report at:
Looks good.
Quoted 6 lines
Signed-off-by Dave Chinner <[email protected]>--- fs/xfs/linux-2.6/xfs_sync.c | 31 ++++++++++++++++++++++++- fs/xfs/xfs_iget.c | 53 +------------------------------------------ fs/xfs/xfs_inode.h | 2 +- 3 files changed, 32 insertions(+), 54 deletions(-)
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 2/5] xfs: simplify and remove xfs_ireclaim
In reply to Dave ChinnerQuoted 11 lines · Dave Chinner
From: Dave Chinner <[email protected]>
xfs_ireclaimhas to get and put te pag structure because it is only called with the inode to reclaim. The one caller of this function already has a reference on the pag and a pointer to is, so move the radix tree delete to the caller and removexfs_ireclaimcompletely. This avoids a xfs_perag_get/put on every inode being reclaimed.The overhead was noticed in a bug report at:
Looks good, I had looked into this earlier but never finished it.
There's also some opportunity to optimize roundtrips on the ilock in this path.
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
PATCH 3/5 xfs: fix xfs_trans_add_item() lockdep warnings
In reply to Dave ChinnerFrom: Dave Chinner <[email protected]>
xfs_trans_add_item() is called with ip->i_ilock held, which means it is unsafe for memory reclaim to recurse back into the filesystem (ilock is required in writeback). Hence the allocation needs to be KM_NOFS to avoid recursion.
Lockdep report indicating memory allocation being called with the ip->i_ilock held is as follows:
[ 1749.866796] =================================
[ 1749.867788] [ INFO: inconsistent lock state ]
[ 1749.868327] 2.6.35-rc3-dgc+ #25
[ 1749.868741] ---------------------------------
[ 1749.868741] inconsistent {IN-RECLAIM_FS-W} -> {RECLAIM_FS-ON-W} usage.
[ 1749.868741] dd/2835 [HC0[0]:SC0[0]:HE1:SE1] takes:
[ 1749.868741] (&(&ip->i_lock)->mr_lock){++++?.}, at: [<ffffffff813170fb>] xfs_ilock+0x10b/0x190
[ 1749.868741] {IN-RECLAIM_FS-W} state was registered at:
[ 1749.868741] [<ffffffff810b3a97>] __lock_acquire+0x437/0x1450
[ 1749.868741] [<ffffffff810b4b56>] lock_acquire+0xa6/0x160
[ 1749.868741] [<ffffffff810a20b5>] down_write_nested+0x65/0xb0
[ 1749.868741] [<ffffffff813170fb>] xfs_ilock+0x10b/0x190
[ 1749.868741] [<ffffffff8134e819>] xfs_reclaim_inode+0x99/0x310
[ 1749.868741] [<ffffffff8134f56b>] xfs_inode_ag_walk+0x8b/0x150
[ 1749.868741] [<ffffffff8134f6bb>] xfs_inode_ag_iterator+0x8b/0xf0
[ 1749.868741] [<ffffffff8134f7a8>] xfs_reclaim_inode_shrink+0x88/0x90
[ 1749.868741] [<ffffffff81119d07>] shrink_slab+0x137/0x1a0
[ 1749.868741] [<ffffffff8111bbe1>] balance_pgdat+0x421/0x6a0
[ 1749.868741] [<ffffffff8111bf7d>] kswapd+0x11d/0x320
[ 1749.868741] [<ffffffff8109ce56>] kthread+0x96/0xa0
[ 1749.868741] [<ffffffff81035de4>] kernel_thread_helper+0x4/0x10
[ 1749.868741] irq event stamp: 4234335
[ 1749.868741] hardirqs last enabled at (4234335): [<ffffffff81147d25>] kmem_cache_free+0x115/0x220
[ 1749.868741] hardirqs last disabled at (4234334): [<ffffffff81147c4d>] kmem_cache_free+0x3d/0x220
[ 1749.868741] softirqs last enabled at (4233112): [<ffffffff81084dd2>] __do_softirq+0x142/0x260
[ 1749.868741] softirqs last disabled at (4233095): [<ffffffff81035edc>] call_softirq+0x1c/0x50
[ 1749.868741]
[ 1749.868741] other info that might help us debug this:
[ 1749.868741] 2 locks held by dd/2835:
[ 1749.868741] #0: (&(&ip->i_iolock)->mr_lock#2){+.+.+.}, at: [<ffffffff81316edd>] xfs_ilock_nowait+0xed/0x200
[ 1749.868741] #1: (&(&ip->i_lock)->mr_lock){++++?.}, at: [<ffffffff813170fb>] xfs_ilock+0x10b/0x190
[ 1749.868741]
[ 1749.868741] stack backtrace:
[ 1749.868741] Pid: 2835, comm: dd Not tainted 2.6.35-rc3-dgc+ #25
[ 1749.868741] Call Trace:
[ 1749.868741] [<ffffffff810b1faa>] print_usage_bug+0x18a/0x190
[ 1749.868741] [<ffffffff8104264f>] ? save_stack_trace+0x2f/0x50
[ 1749.868741] [<ffffffff810b2400>] ? check_usage_backwards+0x0/0xf0
[ 1749.868741] [<ffffffff810b2f11>] mark_lock+0x331/0x400
[ 1749.868741] [<ffffffff810b3047>] mark_held_locks+0x67/0x90
[ 1749.868741] [<ffffffff810b3111>] lockdep_trace_alloc+0xa1/0xe0
[ 1749.868741] [<ffffffff81147419>] kmem_cache_alloc+0x39/0x1e0
[ 1749.868741] [<ffffffff8133f954>] kmem_zone_alloc+0x94/0xe0
[ 1749.868741] [<ffffffff8133f9be>] kmem_zone_zalloc+0x1e/0x50
[ 1749.868741] [<ffffffff81335f02>] xfs_trans_add_item+0x72/0xb0
[ 1749.868741] [<ffffffff81339e41>] xfs_trans_ijoin+0xa1/0xd0
[ 1749.868741] [<ffffffff81319f82>] xfs_itruncate_finish+0x312/0x5d0
[ 1749.868741] [<ffffffff8133cb87>] xfs_free_eofblocks+0x227/0x280
[ 1749.868741] [<ffffffff8133cd18>] xfs_release+0x138/0x190
[ 1749.868741] [<ffffffff813464c5>] xfs_file_release+0x15/0x20
[ 1749.868741] [<ffffffff81150ebf>] fput+0x13f/0x260
[ 1749.868741] [<ffffffff8114d8c2>] filp_close+0x52/0x80
[ 1749.868741] [<ffffffff8114d9a9>] sys_close+0xb9/0x120
[ 1749.868741] [<ffffffff81034ff2>] system_call_fastpath+0x16/0x1b--- fs/xfs/xfs_trans.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
fs/xfs/xfs_trans.c +1 -1
@@ -1134,7 +1134,7 @@ xfs_trans_add_item(ASSERT (lip->li_mountp = tp->t_mountp);ASSERT (lip->li_ailp = tp->t_mountp->m_ail); - lidp =kmem_zone_zalloc (xfs_log_item_desc_zone,KM_SLEEP ); + lidp =kmem_zone_zalloc (xfs_log_item_desc_zone,KM_SLEEP |KM_NOFS ); lidp->lid_item = lip; lidp->lid_flags =0 ;
Signature · 6 lines
1.7.1 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 3/5] xfs: fix xfs_trans_add_item() lockdep warnings
Quoted 6 lines · Dave Chinner
From: Dave Chinner <[email protected]>
xfs_trans_add_item()is called withip->i_ilockheld, which means it is unsafe for memory reclaim to recurse back into the filesystem (ilock is required in writeback). Hence the allocation needs to beKM_NOFSto avoid recursion.
Looks good.
Quoted 2 lines
Lockdep report indicating memory allocation being called with the
ip->i_ilockheld is as follows:
. . .
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 3/5] xfs: fix xfs_trans_add_item() lockdep warnings
In reply to Dave Chinnerfs/xfs/xfs_trans.c xfs_trans_add_item( · line 1137
Quoted 2 lines
fs/xfs/xfs_trans.c +1
-1- lidp =kmem_zone_zalloc (xfs_log_item_desc_zone,KM_SLEEP ); + lidp =kmem_zone_zalloc (xfs_log_item_desc_zone,KM_SLEEP |KM_NOFS );
KM_NOFS by itself actually is sufficiant. If you want to keep the KM_SLEEP for documentation purposes at least add some spaces to make it more redable.
lidp = kmem_zone_zalloc(xfs_log_item_desc_zone, KM_SLEEP | KM_NOFS);
Once getting outside of nitpicking territory this looks good to me:
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 3/5] xfs: fix xfs_trans_add_item() lockdep warnings
Quoted 8 lines · Christoph Hellwig
fs/xfs/xfs_trans.c xfs_trans_add_item( · line 1137
Quoted 2 lines
fs/xfs/xfs_trans.c +1
-1- lidp =kmem_zone_zalloc (xfs_log_item_desc_zone,KM_SLEEP ); + lidp =kmem_zone_zalloc (xfs_log_item_desc_zone,KM_SLEEP |KM_NOFS );
KM_NOFSby itself actually is sufficiant. If you want to keep theKM_SLEEPfor documentation purposes at least add some spaces to make it more redable.lidp = kmem_zone_zalloc(xfs_log_item_desc_zone, KM_SLEEP | KM_NOFS);
Will do.
Cheers,
Dave.
Signature · 7 lines
Dave Chinner [email protected] _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH 4/5 xfs: use GFP_NOFS for page cache allocation
In reply to Dave ChinnerFrom: Dave Chinner <[email protected]>
Avoid a lockdep warning by preventing page cache allocation from recursing back into the filesystem during memory reclaim.
--- fs/xfs/linux-2.6/xfs_aops.c | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-)
fs/xfs/linux-2.6/xfs_aops.c +3 -2
@@ -1501,8 +1501,9 @@ xfs_vm_write_begin( void **fsdata) { *pagep =NULL ; -return block_write_begin (file, mapping, pos, len, flags, pagep, fsdata, - xfs_get_blocks); +return block_write_begin (file, mapping, pos, len, + (flags |AOP_FLAG_NOFS ), + pagep, fsdata, xfs_get_blocks); }STATIC sector_t
Signature · 6 lines
1.7.1 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 4/5] xfs: use GFP_NOFS for page cache allocation
Quoted 4 lines · Dave Chinner
From: Dave Chinner <[email protected]>
Avoid a lockdep warning by preventing page cache allocation from recursing back into the filesystem during memory reclaim.
Looks good.
Quoted 10 lines
Signed-off-by Dave Chinner <[email protected]>--- fs/xfs/linux-2.6/xfs_aops.c | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-)fs/xfs/linux-2.6/xfs_aops.c +0
-0
fs/xfs/linux-2.6/xfs_aops.c xfs_vm_write_begin( · line 1505
Quoted 7 lines
fs/xfs/linux-2.6/xfs_aops.c +2
-2@@ -1501,8 +1501,9 @@ xfs_vm_write_begin( void **fsdata) { *pagep =NULL ; -return block_write_begin (file, mapping, pos, len, flags, pagep, fsdata, - xfs_get_blocks); + return block_write_begin(file, mapping, pos, len, + (flags | AOP_FLAG_NOFS),
Why the parentheses?
fs/xfs/linux-2.6/xfs_aops.c xfs_vm_write_begin( · line 1509
Quoted 4 lines
fs/xfs/linux-2.6/xfs_aops.c +1
-0+ pagep, fsdata, xfs_get_blocks); }STATIC sector_t
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 4/5] xfs: use GFP_NOFS for page cache allocation
In reply to Dave ChinnerQuoted 4 lines · Dave Chinner
From: Dave Chinner <[email protected]>
Avoid a lockdep warning by preventing page cache allocation from recursing back into the filesystem during memory reclaim.
Yeah, I already have this in my queue too. Noticed that we don't need it because of i_mutex as suggested in the stack overflow thread, but for the XFS ilock.
fs/xfs/linux-2.6/xfs_aops.c xfs_vm_write_begin( · line 1506
Quoted 9 lines
fs/xfs/linux-2.6/xfs_aops.c +3
-2@@ -1501,8 +1501,9 @@ xfs_vm_write_begin( void **fsdata) { *pagep =NULL ; -return block_write_begin (file, mapping, pos, len, flags, pagep, fsdata, - xfs_get_blocks); +return block_write_begin (file, mapping, pos, len, + (flags |AOP_FLAG_NOFS ), + pagep, fsdata, xfs_get_blocks);
No need for the bracing:
return block_write_begin(file, mapping, pos, len, flags | AOP_FLAG_NOFS, pagep, fsdata, xfs_get_blocks);
And with my truncate rework in the vfs tree we'll get rejection galore in linux-next, but Stephen has been pretty good at handling these..
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
PATCH 5/5 xfs: fix memory reclaim recursion deadlock on locked inode buffer
In reply to Dave ChinnerFrom: Dave Chinner <[email protected]>
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.
--- fs/xfs/xfs_inode.c | 20 +++++++++++--------- 1 files changed, 11 insertions(+), 9 deletions(-)
fs/xfs/xfs_inode.c +11 -9
@@ -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); }
Signature · 6 lines
1.7.1 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 5/5] xfs: fix memory reclaim recursion deadlock on locked inode buffer
Quoted 6 lines · Dave Chinner
From: Dave Chinner <[email protected]>
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_NOFSto avoid this deadlock condition.
Looks good. I wasn't able to find the paths that led to xfs_iroot_realloc() and xfs_idata_realloc() but I'm sure they're there...
Quoted 79 lines
Reported-by Peter Watkins <[email protected]>Signed-off-by Dave Chinner <[email protected]>--- fs/xfs/xfs_inode.c | 20 +++++++++++--------- 1 files changed, 11 insertions(+), 9 deletions(-)fs/xfs/xfs_inode.c +8
-8@@ -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 );
fs/xfs/xfs_inode.c xfs_idata_realloc( · line 2360
Quoted 10 lines
fs/xfs/xfs_inode.c +3
-1+ 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); }
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 5/5] xfs: fix memory reclaim recursion deadlock on locked inode buffer
In reply to Dave ChinnerQuoted 6 lines · Dave Chinner
From: Dave Chinner <[email protected]>
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_NOFSto avoid this deadlock condition.
Looks good, although the same style nitpicks as for patch 3 apply.
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Quoted 5 lines · Dave Chinner
The following patches fix excessive CPU consumption during inode cache shrinking when filesystems have lots of allocation groups as well as prevent a couple of lockdep reports that were found during testing. Also included is a fix for a reclaim recursion deadlock when allocating memory during inode initialisation.
Wa the overlap of patch 1 with the for-2.6.35 shrinker series intentional? In addition to patch 1 patches 3 to 5 are also for-2.6.35 material in my opinion.
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Quoted 10 lines · Christoph Hellwig
Quoted 5 lines · Dave Chinner
The following patches fix excessive CPU consumption during inode cache shrinking when filesystems have lots of allocation groups as well as prevent a couple of lockdep reports that were found during testing. Also included is a fix for a reclaim recursion deadlock when allocating memory during inode initialisation.
Wa the overlap of patch 1 with the for-2.6.35 shrinker series intentional? In addition to patch 1 patches 3 to 5 are also for-2.6.35 material in my opinion.
I realised that we'd get a messy, messy conflict if I separated the per-ag tree reclaim tracking from the shrinker patchset, so I included it in that one as it was also part of fixing reported XFS shrinker regressions to avoid such conflicts.
But yes, i think that all the lockdep fixes are probably 2.6.35 material.
Cheers,
Dave.
Signature · 7 lines
Dave Chinner [email protected] _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs