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 <zab@versity.com>
This commit is contained in:
Zach Brown
2018-03-06 10:32:33 -08:00
committed by Zach Brown
parent 241b52d55a
commit 6adb24f0f5
+4 -1
View File
@@ -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);
}
}