Commit e43afd72 authored by Dave Chinner's avatar Dave Chinner Committed by Christoph Hellwig

xfs: block callers of xfs_flush_inodes() correctly

xfs_flush_inodes() currently uses a magic timeout to wait for
some inodes to be flushed before returning. This isn't
really reliable but used to be the best that could be done
due to deadlock potential of waiting for the entire flush.

Now the inode flush is safe to execute while we hold page
and inode locks, we can wait for all the inodes to flush
synchronously. Convert the wait mechanism to a completion
to do this efficiently. This should remove all remaining
spurious ENOSPC errors from the delayed allocation reservation
path.

This is extracted almost line for line from a larger patch
from Mikulas Patocka.
Signed-off-by: default avatarMikulas Patocka <mpatocka@redhat.com>
Signed-off-by: default avatarDave Chinner <david@fromorbit.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent 5825294e
...@@ -404,7 +404,8 @@ STATIC void ...@@ -404,7 +404,8 @@ STATIC void
xfs_syncd_queue_work( xfs_syncd_queue_work(
struct xfs_mount *mp, struct xfs_mount *mp,
void *data, void *data,
void (*syncer)(struct xfs_mount *, void *)) void (*syncer)(struct xfs_mount *, void *),
struct completion *completion)
{ {
struct xfs_sync_work *work; struct xfs_sync_work *work;
...@@ -413,6 +414,7 @@ xfs_syncd_queue_work( ...@@ -413,6 +414,7 @@ xfs_syncd_queue_work(
work->w_syncer = syncer; work->w_syncer = syncer;
work->w_data = data; work->w_data = data;
work->w_mount = mp; work->w_mount = mp;
work->w_completion = completion;
spin_lock(&mp->m_sync_lock); spin_lock(&mp->m_sync_lock);
list_add_tail(&work->w_list, &mp->m_sync_list); list_add_tail(&work->w_list, &mp->m_sync_list);
spin_unlock(&mp->m_sync_lock); spin_unlock(&mp->m_sync_lock);
...@@ -441,10 +443,11 @@ xfs_flush_inodes( ...@@ -441,10 +443,11 @@ xfs_flush_inodes(
xfs_inode_t *ip) xfs_inode_t *ip)
{ {
struct inode *inode = VFS_I(ip); struct inode *inode = VFS_I(ip);
DECLARE_COMPLETION_ONSTACK(completion);
igrab(inode); igrab(inode);
xfs_syncd_queue_work(ip->i_mount, inode, xfs_flush_inodes_work); xfs_syncd_queue_work(ip->i_mount, inode, xfs_flush_inodes_work, &completion);
delay(msecs_to_jiffies(500)); wait_for_completion(&completion);
xfs_log_force(ip->i_mount, (xfs_lsn_t)0, XFS_LOG_FORCE|XFS_LOG_SYNC); xfs_log_force(ip->i_mount, (xfs_lsn_t)0, XFS_LOG_FORCE|XFS_LOG_SYNC);
} }
...@@ -514,6 +517,8 @@ xfssyncd( ...@@ -514,6 +517,8 @@ xfssyncd(
list_del(&work->w_list); list_del(&work->w_list);
if (work == &mp->m_sync_work) if (work == &mp->m_sync_work)
continue; continue;
if (work->w_completion)
complete(work->w_completion);
kmem_free(work); kmem_free(work);
} }
} }
...@@ -527,6 +532,7 @@ xfs_syncd_init( ...@@ -527,6 +532,7 @@ xfs_syncd_init(
{ {
mp->m_sync_work.w_syncer = xfs_sync_worker; mp->m_sync_work.w_syncer = xfs_sync_worker;
mp->m_sync_work.w_mount = mp; mp->m_sync_work.w_mount = mp;
mp->m_sync_work.w_completion = NULL;
mp->m_sync_task = kthread_run(xfssyncd, mp, "xfssyncd"); mp->m_sync_task = kthread_run(xfssyncd, mp, "xfssyncd");
if (IS_ERR(mp->m_sync_task)) if (IS_ERR(mp->m_sync_task))
return -PTR_ERR(mp->m_sync_task); return -PTR_ERR(mp->m_sync_task);
......
...@@ -26,6 +26,7 @@ typedef struct xfs_sync_work { ...@@ -26,6 +26,7 @@ typedef struct xfs_sync_work {
struct xfs_mount *w_mount; struct xfs_mount *w_mount;
void *w_data; /* syncer routine argument */ void *w_data; /* syncer routine argument */
void (*w_syncer)(struct xfs_mount *, void *); void (*w_syncer)(struct xfs_mount *, void *);
struct completion *w_completion;
} xfs_sync_work_t; } xfs_sync_work_t;
#define SYNC_ATTR 0x0001 /* sync attributes */ #define SYNC_ATTR 0x0001 /* sync attributes */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment