From 6adb24f0f52291b81d3a770d83646efb08f4f638 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Thu, 1 Mar 2018 17:32:21 -0800 Subject: [PATCH] scoutfs: clean up compaction destruction We're seeing warnings from trying to destroy the server work queue while it's still active. Auditing shows that almost all of the sources of queued work are shutdown before we destroy the work queue. Except for the compaction func. It queues itself via the sneaky call to scoutfs_compact_kick() inside scoutfs_client_finish_compaction(). What a mess. We only wait for work to finish running in scoutfs_compact_destroy(), we don't forbid further queueing. So with just the right races it looks possible to have the compact func executing after we return from _destroy(). It can then later try to queue the commit_work in the server workqueue. It's pretty hard to imagine this race, but it's made a bit easier by the startling fact that we don't free the compact info struct. That makes it a little easier to imagine use-after-destroy not exploding. So let's forcibly forbid chain queueing during compaction shutdown by using cancel_work_sync(). It marks the work canceling while flushing so the queue_work in the work func won't do anything. This should ensure that the compaction func isn't running when destroy returns. Also while we're at it actually free the allocated compaction info struct! Cool cool cool. Signed-off-by: Zach Brown --- kmod/src/compact.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kmod/src/compact.c b/kmod/src/compact.c index 428346a0..96a38952 100644 --- a/kmod/src/compact.c +++ b/kmod/src/compact.c @@ -666,8 +666,11 @@ void scoutfs_compact_destroy(struct super_block *sb) DECLARE_COMPACT_INFO(sb, ci); if (ci) { - flush_work(&ci->work); + /* stop compaction from requeueing itself */ + cancel_work_sync(&ci->work); destroy_workqueue(ci->workq); sbi->compact_info = NULL; + + kfree(ci); } }