[PATCH v3 1/5] task_work: export task_work_add()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Commit 322c4293ecc58110 ("loop: make autoclear operation asynchronous")
silenced a circular locking dependency warning by moving autoclear
operation to WQ context.

Then, it was reported that WQ context is too late to run autoclear
operation; some userspace programs (e.g. xfstest) assume that the autoclear
operation already completed by the moment close() returns to user mode
so that they can immediately call umount() of a partition containing a
backing file which the autoclear operation should have closed.

Then, Jan Kara found that fundamental problem is that waiting for I/O
completion (from blk_mq_freeze_queue() or flush_workqueue()) with
disk->open_mutex held has possibility of deadlock.

Then, I found that since disk->open_mutex => lo->lo_mutex dependency is
recorded by lo_open() and lo_release(), and blk_mq_freeze_queue() by e.g.
loop_set_status() waits for I/O completion with lo->lo_mutex held, from
locking dependency chain perspective we need to avoid holding lo->lo_mutex
 from lo_open() and lo_release(). And we can avoid holding lo->lo_mutex
 from lo_open(), for we can instead use a spinlock dedicated for
Lo_deleting check.

But we cannot avoid holding lo->lo_mutex from lo_release(), for WQ context
was too late to run autoclear operation. We need to make whole lo_release()
operation start without disk->open_mutex and complete before returning to
user mode. One of approaches that can meet such requirement is to use the
task_work context. Thus, export task_work_add() for the loop driver.

Cc: Jan Kara <jack@xxxxxxx>
Cc: Christoph Hellwig <hch@xxxxxx>
Signed-off-by: Tetsuo Handa <penguin-kernel@xxxxxxxxxxxxxxxxxxx>
---
 kernel/task_work.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/kernel/task_work.c b/kernel/task_work.c
index 1698fbe6f0e1..2a1644189182 100644
--- a/kernel/task_work.c
+++ b/kernel/task_work.c
@@ -60,6 +60,7 @@ int task_work_add(struct task_struct *task, struct callback_head *work,
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(task_work_add);
 
 /**
  * task_work_cancel_match - cancel a pending work added by task_work_add()
-- 
2.32.0




[Index of Archives]     [Linux RAID]     [Linux SCSI]     [Linux ATA RAID]     [IDE]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Device Mapper]

  Powered by Linux