From 257c2728e91a64c618591de50d1a41f40882ceea Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Wed, 23 May 2018 17:25:44 -0700 Subject: [PATCH] hammer2 - Fix kmalloc pool blowout on low-memory machines * Fix a kmalloc pool blown that can occur on low-memory machines due to too many disconnected hammer2_inode structures building up. * Was previously fixed for things like rm -rf and bulk renames, but not for setattr (aka chown/chmod -R ops). Reported-by: gjs278 --- sys/vfs/hammer2/hammer2.h | 2 +- sys/vfs/hammer2/hammer2_bulkfree.c | 2 +- sys/vfs/hammer2/hammer2_flush.c | 16 ++++++++++++++-- sys/vfs/hammer2/hammer2_ioctl.c | 12 ++++++------ sys/vfs/hammer2/hammer2_strategy.c | 2 +- sys/vfs/hammer2/hammer2_synchro.c | 2 +- sys/vfs/hammer2/hammer2_vfsops.c | 10 +++++----- sys/vfs/hammer2/hammer2_vnops.c | 28 ++++++++++++---------------- 8 files changed, 41 insertions(+), 33 deletions(-) diff --git a/sys/vfs/hammer2/hammer2.h b/sys/vfs/hammer2/hammer2.h index 3d070dc3b8..af77f242aa 100644 --- a/sys/vfs/hammer2/hammer2.h +++ b/sys/vfs/hammer2/hammer2.h @@ -1582,7 +1582,7 @@ void hammer2_delayed_flush(hammer2_chain_t *chain); */ void hammer2_trans_init(hammer2_pfs_t *pmp, uint32_t flags); hammer2_tid_t hammer2_trans_sub(hammer2_pfs_t *pmp); -void hammer2_trans_done(hammer2_pfs_t *pmp); +void hammer2_trans_done(hammer2_pfs_t *pmp, int quicksideq); hammer2_tid_t hammer2_trans_newinum(hammer2_pfs_t *pmp); void hammer2_trans_assert_strategy(hammer2_pfs_t *pmp); void hammer2_dedup_record(hammer2_chain_t *chain, hammer2_io_t *dio, diff --git a/sys/vfs/hammer2/hammer2_bulkfree.c b/sys/vfs/hammer2/hammer2_bulkfree.c index 2b12604120..0bc3d81d53 100644 --- a/sys/vfs/hammer2/hammer2_bulkfree.c +++ b/sys/vfs/hammer2/hammer2_bulkfree.c @@ -521,7 +521,7 @@ hammer2_bulkfree_pass(hammer2_dev_t *hmp, hammer2_chain_t *vchain, * Cleanup for next loop. */ #ifdef HAMMER2_BULKFREE_TRANS - hammer2_trans_done(hmp->spmp); + hammer2_trans_done(hmp->spmp, 0); #endif if (error) break; diff --git a/sys/vfs/hammer2/hammer2_flush.c b/sys/vfs/hammer2/hammer2_flush.c index 0bad0a1717..6c7054d6ca 100644 --- a/sys/vfs/hammer2/hammer2_flush.c +++ b/sys/vfs/hammer2/hammer2_flush.c @@ -240,11 +240,23 @@ hammer2_trans_sub(hammer2_pfs_t *pmp) } void -hammer2_trans_done(hammer2_pfs_t *pmp) +hammer2_trans_done(hammer2_pfs_t *pmp, int quicksideq) { uint32_t oflags; uint32_t nflags; + /* + * Modifying ops on the front-end can cause dirty inodes to + * build up in the sideq. We don't flush these on inactive/reclaim + * due to potential deadlocks, so we have to deal with them from + * inside other nominal modifying front-end transactions. + */ + if (quicksideq && pmp->sideq_count > (pmp->inum_count >> 3)) + hammer2_inode_run_sideq(pmp, 0); + + /* + * Clean-up the transaction + */ for (;;) { oflags = pmp->trans.flags; cpu_ccfence(); @@ -1546,7 +1558,7 @@ hammer2_inode_xop_flush(hammer2_thread_t *thr, hammer2_xop_t *arg) if (fsync_error) total_error = hammer2_errno_to_error(fsync_error); - hammer2_trans_done(hmp->spmp); /* spmp trans */ + hammer2_trans_done(hmp->spmp, 0); /* spmp trans */ skip: hammer2_xop_feed(&xop->head, NULL, thr->clindex, total_error); } diff --git a/sys/vfs/hammer2/hammer2_ioctl.c b/sys/vfs/hammer2/hammer2_ioctl.c index 69a4851c52..23db254954 100644 --- a/sys/vfs/hammer2/hammer2_ioctl.c +++ b/sys/vfs/hammer2/hammer2_ioctl.c @@ -681,7 +681,7 @@ hammer2_ioctl_pfs_create(hammer2_inode_t *ip, void *data) hammer2_chain_drop(nchain); } - hammer2_trans_done(hmp->spmp); + hammer2_trans_done(hmp->spmp, 1); return (error); } @@ -778,7 +778,7 @@ hammer2_ioctl_pfs_delete(hammer2_inode_t *ip, void *data) #endif hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP); - hammer2_trans_done(spmp); + hammer2_trans_done(spmp, 1); return (hammer2_error_to_errno(error)); } @@ -930,7 +930,7 @@ hammer2_ioctl_pfs_snapshot(hammer2_inode_t *ip, void *data) hammer2_chain_drop(chain); hammer2_inode_unlock(ip); - hammer2_trans_done(pmp); + hammer2_trans_done(pmp, 1); lockmgr(&hmp->bulklk, LK_RELEASE); @@ -1018,7 +1018,7 @@ hammer2_ioctl_inode_set(hammer2_inode_t *ip, void *data) ip->meta.ncopies = ino->ip_data.meta.ncopies; } hammer2_inode_unlock(ip); - hammer2_trans_done(ip->pmp); + hammer2_trans_done(ip->pmp, 1); return (hammer2_error_to_errno(error)); } @@ -1123,7 +1123,7 @@ hammer2_ioctl_bulkfree_scan(hammer2_inode_t *ip, void *data) hammer2_chain_bulkdrop(vchain); } else { hammer2_chain_drop(vchain); - hammer2_trans_done(pmp); + hammer2_trans_done(pmp, 1); } error = hammer2_error_to_errno(error); @@ -1181,7 +1181,7 @@ hammer2_ioctl_destroy(hammer2_inode_t *ip, void *data) error = hammer2_error_to_errno(error); hammer2_inode_unlock(ip); hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP); - hammer2_trans_done(pmp); + hammer2_trans_done(pmp, 1); } break; case HAMMER2_DELETE_INUM: diff --git a/sys/vfs/hammer2/hammer2_strategy.c b/sys/vfs/hammer2/hammer2_strategy.c index dafd2a0b30..309b9b3105 100644 --- a/sys/vfs/hammer2/hammer2_strategy.c +++ b/sys/vfs/hammer2/hammer2_strategy.c @@ -668,7 +668,7 @@ hammer2_strategy_xop_write(hammer2_thread_t *thr, hammer2_xop_t *arg) hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP); hammer2_trans_assert_strategy(ip->pmp); hammer2_lwinprog_drop(ip->pmp); - hammer2_trans_done(ip->pmp); + hammer2_trans_done(ip->pmp, 0); } /* diff --git a/sys/vfs/hammer2/hammer2_synchro.c b/sys/vfs/hammer2/hammer2_synchro.c index 81b0b0f42f..4c066aacfb 100644 --- a/sys/vfs/hammer2/hammer2_synchro.c +++ b/sys/vfs/hammer2/hammer2_synchro.c @@ -239,7 +239,7 @@ hammer2_primary_sync_thread(void *arg) } hammer2_inode_drop(pmp->iroot); - hammer2_trans_done(pmp); + hammer2_trans_done(pmp, 0); if (error && error != HAMMER2_ERROR_EINPROGRESS) kprintf("hammer2_sync_slaves: error %d\n", error); diff --git a/sys/vfs/hammer2/hammer2_vfsops.c b/sys/vfs/hammer2/hammer2_vfsops.c index 1db125a3c9..8df5ed4279 100644 --- a/sys/vfs/hammer2/hammer2_vfsops.c +++ b/sys/vfs/hammer2/hammer2_vfsops.c @@ -738,7 +738,7 @@ again: hammer2_trans_init(pmp, HAMMER2_TRANS_ISFLUSH); hammer2_inode_run_sideq(pmp, 1); hammer2_bioq_sync(pmp); - hammer2_trans_done(pmp); + hammer2_trans_done(pmp, 0); /* * Determine if this PFS is affected. If it is we must @@ -2157,7 +2157,7 @@ hammer2_recovery(hammer2_dev_t *hmp) hammer2_chain_drop(parent); /* drop elm->chain ref */ } - hammer2_trans_done(hmp->spmp); + hammer2_trans_done(hmp->spmp, 0); return error; } @@ -2360,7 +2360,7 @@ hammer2_fixup_pfses(hammer2_dev_t *hmp) } hammer2_flush(chain, HAMMER2_FLUSH_TOP | HAMMER2_FLUSH_ALL); - hammer2_trans_done(hmp->spmp); + hammer2_trans_done(hmp->spmp, 0); } chain = hammer2_chain_next(&parent, chain, &key_next, key_next, HAMMER2_KEY_MAX, @@ -2444,7 +2444,7 @@ hammer2_vfs_sync(struct mount *mp, int waitfor) * as the vnode scan will not see these. */ hammer2_inode_run_sideq(pmp, 1); - hammer2_trans_done(pmp); + hammer2_trans_done(pmp, 0); /* * Start our flush transaction and flush the root topology down to @@ -2508,7 +2508,7 @@ hammer2_vfs_sync(struct mount *mp, int waitfor) } else { error = 0; } - hammer2_trans_done(pmp); + hammer2_trans_done(pmp, 0); return (error); } diff --git a/sys/vfs/hammer2/hammer2_vnops.c b/sys/vfs/hammer2/hammer2_vnops.c index cd720d3b52..aec0d4fc63 100644 --- a/sys/vfs/hammer2/hammer2_vnops.c +++ b/sys/vfs/hammer2/hammer2_vnops.c @@ -273,7 +273,7 @@ hammer2_vop_fsync(struct vop_fsync_args *ap) vclrisdirty(vp); } hammer2_inode_unlock(ip); - hammer2_trans_done(ip->pmp); + hammer2_trans_done(ip->pmp, 0); return (error1); } @@ -517,7 +517,7 @@ done: * Cleanup. */ hammer2_inode_unlock(ip); - hammer2_trans_done(ip->pmp); + hammer2_trans_done(ip->pmp, 1); hammer2_knote(ip->vp, kflags); return (error); @@ -828,7 +828,7 @@ hammer2_vop_write(struct vop_write_args *ap) hammer2_trans_init(ip->pmp, 0); } error = hammer2_write_file(ip, uio, ioflag, seqcount); - hammer2_trans_done(ip->pmp); + hammer2_trans_done(ip->pmp, 1); return (error); } @@ -1431,7 +1431,7 @@ hammer2_vop_nmkdir(struct vop_nmkdir_args *ap) hammer2_inode_unlock(dip); } - hammer2_trans_done(dip->pmp); + hammer2_trans_done(dip->pmp, 1); if (error == 0) { cache_setunresolved(ap->a_nch); @@ -1554,7 +1554,7 @@ hammer2_vop_nlink(struct vop_nlink_args *ap) hammer2_inode_unlock(ip); hammer2_inode_unlock(tdip); - hammer2_trans_done(ip->pmp); + hammer2_trans_done(ip->pmp, 1); hammer2_knote(ap->a_vp, NOTE_LINK); hammer2_knote(ap->a_dvp, NOTE_WRITE); @@ -1634,7 +1634,7 @@ hammer2_vop_ncreate(struct vop_ncreate_args *ap) hammer2_inode_unlock(dip); } - hammer2_trans_done(dip->pmp); + hammer2_trans_done(dip->pmp, 1); if (error == 0) { cache_setunresolved(ap->a_nch); @@ -1708,7 +1708,7 @@ hammer2_vop_nmknod(struct vop_nmknod_args *ap) hammer2_inode_unlock(dip); } - hammer2_trans_done(dip->pmp); + hammer2_trans_done(dip->pmp, 1); if (error == 0) { cache_setunresolved(ap->a_nch); @@ -1768,7 +1768,7 @@ hammer2_vop_nsymlink(struct vop_nsymlink_args *ap) nip = NULL; } *ap->a_vpp = NULL; - hammer2_trans_done(dip->pmp); + hammer2_trans_done(dip->pmp, 1); return error; } *ap->a_vpp = hammer2_igetv(nip, &error); @@ -1814,7 +1814,7 @@ hammer2_vop_nsymlink(struct vop_nsymlink_args *ap) hammer2_inode_unlock(dip); } - hammer2_trans_done(dip->pmp); + hammer2_trans_done(dip->pmp, 1); /* * Finalize namecache @@ -1910,8 +1910,7 @@ hammer2_vop_nremove(struct vop_nremove_args *ap) hammer2_inode_unlock(dip); } - hammer2_inode_run_sideq(dip->pmp, 0); - hammer2_trans_done(dip->pmp); + hammer2_trans_done(dip->pmp, 1); if (error == 0) { cache_unlink(ap->a_nch); hammer2_knote(ap->a_dvp, NOTE_WRITE); @@ -1988,8 +1987,7 @@ hammer2_vop_nrmdir(struct vop_nrmdir_args *ap) hammer2_inode_unlock(dip); } - hammer2_inode_run_sideq(dip->pmp, 0); - hammer2_trans_done(dip->pmp); + hammer2_trans_done(dip->pmp, 1); if (error == 0) { cache_unlink(ap->a_nch); hammer2_knote(ap->a_dvp, NOTE_WRITE | NOTE_LINK); @@ -2257,9 +2255,7 @@ done2: hammer2_inode_unlock(tdip); hammer2_inode_unlock(fdip); hammer2_inode_drop(ip); - hammer2_inode_run_sideq(fdip->pmp, 0); - - hammer2_trans_done(tdip->pmp); + hammer2_trans_done(tdip->pmp, 1); /* * Issue the namecache update after unlocking all the internal -- 2.11.4.GIT