xfs: use dedicated log worker wq to avoid deadlock with cil wq
commitsteinar/wifi_calib_4_9_kernel696a562072
upstream. The log covering background task used to be part of the xfssyncd workqueue. That workqueue was removed as of commit5889608df
("xfs: syncd workqueue is no more") and the associated work item scheduled to the xfs-log wq. The latter is used for log buffer I/O completion. Since xfs_log_worker() can invoke a log flush, a deadlock is possible between the xfs-log and xfs-cil workqueues. Consider the following codepath from xfs_log_worker(): xfs_log_worker() xfs_log_force() _xfs_log_force() xlog_cil_force() xlog_cil_force_lsn() xlog_cil_push_now() flush_work() The above is in xfs-log wq context and blocked waiting on the completion of an xfs-cil work item. Concurrently, the cil push in progress can end up blocked here: xlog_cil_push_work() xlog_cil_push() xlog_write() xlog_state_get_iclog_space() xlog_wait(&log->l_flush_wait, ...) The above is in xfs-cil context waiting on log buffer I/O completion, which executes in xfs-log wq context. In this scenario both workqueues are deadlocked waiting on eachother. Add a new workqueue specifically for the high level log covering and ail pushing worker, as was the case prior to commit5889608df
. Diagnosed-by: David Jeffery <djeffery@redhat.com> Signed-off-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
parent
3890d83805
commit
c2ad2dc3d2
|
@ -1293,7 +1293,7 @@ void
|
|||
xfs_log_work_queue(
|
||||
struct xfs_mount *mp)
|
||||
{
|
||||
queue_delayed_work(mp->m_log_workqueue, &mp->m_log->l_work,
|
||||
queue_delayed_work(mp->m_sync_workqueue, &mp->m_log->l_work,
|
||||
msecs_to_jiffies(xfs_syncd_centisecs * 10));
|
||||
}
|
||||
|
||||
|
|
|
@ -183,6 +183,7 @@ typedef struct xfs_mount {
|
|||
struct workqueue_struct *m_reclaim_workqueue;
|
||||
struct workqueue_struct *m_log_workqueue;
|
||||
struct workqueue_struct *m_eofblocks_workqueue;
|
||||
struct workqueue_struct *m_sync_workqueue;
|
||||
|
||||
/*
|
||||
* Generation of the filesysyem layout. This is incremented by each
|
||||
|
|
|
@ -872,8 +872,15 @@ xfs_init_mount_workqueues(
|
|||
if (!mp->m_eofblocks_workqueue)
|
||||
goto out_destroy_log;
|
||||
|
||||
mp->m_sync_workqueue = alloc_workqueue("xfs-sync/%s", WQ_FREEZABLE, 0,
|
||||
mp->m_fsname);
|
||||
if (!mp->m_sync_workqueue)
|
||||
goto out_destroy_eofb;
|
||||
|
||||
return 0;
|
||||
|
||||
out_destroy_eofb:
|
||||
destroy_workqueue(mp->m_eofblocks_workqueue);
|
||||
out_destroy_log:
|
||||
destroy_workqueue(mp->m_log_workqueue);
|
||||
out_destroy_reclaim:
|
||||
|
@ -894,6 +901,7 @@ STATIC void
|
|||
xfs_destroy_mount_workqueues(
|
||||
struct xfs_mount *mp)
|
||||
{
|
||||
destroy_workqueue(mp->m_sync_workqueue);
|
||||
destroy_workqueue(mp->m_eofblocks_workqueue);
|
||||
destroy_workqueue(mp->m_log_workqueue);
|
||||
destroy_workqueue(mp->m_reclaim_workqueue);
|
||||
|
|
Loading…
Reference in New Issue