Commit af7cf057 authored by Trond Myklebust's avatar Trond Myklebust

NFS: Allow multiple commit requests in flight per file

Allow synchronous RPC calls to wait for pending RPC calls to finish,
but also allow asynchronous ones to just fire off another commit.

With this patch, the xfstests generic/074 test completes in 226s
instead of 242s
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
parent dc602dd7
...@@ -721,14 +721,8 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data) ...@@ -721,14 +721,8 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data)
nfs_direct_write_complete(dreq, data->inode); nfs_direct_write_complete(dreq, data->inode);
} }
static void nfs_direct_error_cleanup(struct nfs_inode *nfsi)
{
/* There is no lock to clear */
}
static const struct nfs_commit_completion_ops nfs_direct_commit_completion_ops = { static const struct nfs_commit_completion_ops nfs_direct_commit_completion_ops = {
.completion = nfs_direct_commit_complete, .completion = nfs_direct_commit_complete,
.error_cleanup = nfs_direct_error_cleanup,
}; };
static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq)
......
...@@ -514,7 +514,7 @@ static void nfs_check_dirty_writeback(struct page *page, ...@@ -514,7 +514,7 @@ static void nfs_check_dirty_writeback(struct page *page,
* so it will not block due to pages that will shortly be freeable. * so it will not block due to pages that will shortly be freeable.
*/ */
nfsi = NFS_I(mapping->host); nfsi = NFS_I(mapping->host);
if (test_bit(NFS_INO_COMMIT, &nfsi->flags)) { if (atomic_read(&nfsi->commit_info.rpcs_out)) {
*writeback = true; *writeback = true;
return; return;
} }
......
...@@ -39,7 +39,6 @@ ...@@ -39,7 +39,6 @@
{ 1 << NFS_INO_INVALIDATING, "INVALIDATING" }, \ { 1 << NFS_INO_INVALIDATING, "INVALIDATING" }, \
{ 1 << NFS_INO_FLUSHING, "FLUSHING" }, \ { 1 << NFS_INO_FLUSHING, "FLUSHING" }, \
{ 1 << NFS_INO_FSCACHE, "FSCACHE" }, \ { 1 << NFS_INO_FSCACHE, "FSCACHE" }, \
{ 1 << NFS_INO_COMMIT, "COMMIT" }, \
{ 1 << NFS_INO_LAYOUTCOMMIT, "NEED_LAYOUTCOMMIT" }, \ { 1 << NFS_INO_LAYOUTCOMMIT, "NEED_LAYOUTCOMMIT" }, \
{ 1 << NFS_INO_LAYOUTCOMMITTING, "LAYOUTCOMMIT" }) { 1 << NFS_INO_LAYOUTCOMMITTING, "LAYOUTCOMMIT" })
......
...@@ -266,17 +266,14 @@ pnfs_generic_commit_pagelist(struct inode *inode, struct list_head *mds_pages, ...@@ -266,17 +266,14 @@ pnfs_generic_commit_pagelist(struct inode *inode, struct list_head *mds_pages,
} else { } else {
nfs_retry_commit(mds_pages, NULL, cinfo, 0); nfs_retry_commit(mds_pages, NULL, cinfo, 0);
pnfs_generic_retry_commit(cinfo, 0); pnfs_generic_retry_commit(cinfo, 0);
cinfo->completion_ops->error_cleanup(NFS_I(inode));
return -ENOMEM; return -ENOMEM;
} }
} }
nreq += pnfs_generic_alloc_ds_commits(cinfo, &list); nreq += pnfs_generic_alloc_ds_commits(cinfo, &list);
if (nreq == 0) { if (nreq == 0)
cinfo->completion_ops->error_cleanup(NFS_I(inode));
goto out; goto out;
}
atomic_add(nreq, &cinfo->mds->rpcs_out); atomic_add(nreq, &cinfo->mds->rpcs_out);
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
#include <linux/nfs_page.h> #include <linux/nfs_page.h>
#include <linux/backing-dev.h> #include <linux/backing-dev.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/freezer.h>
#include <linux/wait.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -1535,27 +1537,29 @@ static void nfs_writeback_result(struct rpc_task *task, ...@@ -1535,27 +1537,29 @@ static void nfs_writeback_result(struct rpc_task *task,
} }
} }
static int nfs_wait_atomic_killable(atomic_t *key)
{
if (fatal_signal_pending(current))
return -ERESTARTSYS;
freezable_schedule_unsafe();
return 0;
}
static int nfs_commit_set_lock(struct nfs_inode *nfsi, int may_wait) static int wait_on_commit(struct nfs_mds_commit_info *cinfo)
{ {
int ret; return wait_on_atomic_t(&cinfo->rpcs_out,
nfs_wait_atomic_killable, TASK_KILLABLE);
}
if (!test_and_set_bit(NFS_INO_COMMIT, &nfsi->flags)) static void nfs_commit_begin(struct nfs_mds_commit_info *cinfo)
return 1; {
if (!may_wait) atomic_inc(&cinfo->rpcs_out);
return 0;
ret = out_of_line_wait_on_bit_lock(&nfsi->flags,
NFS_INO_COMMIT,
nfs_wait_bit_killable,
TASK_KILLABLE);
return (ret < 0) ? ret : 1;
} }
static void nfs_commit_clear_lock(struct nfs_inode *nfsi) static void nfs_commit_end(struct nfs_mds_commit_info *cinfo)
{ {
clear_bit(NFS_INO_COMMIT, &nfsi->flags); if (atomic_dec_and_test(&cinfo->rpcs_out))
smp_mb__after_atomic(); wake_up_atomic_t(&cinfo->rpcs_out);
wake_up_bit(&nfsi->flags, NFS_INO_COMMIT);
} }
void nfs_commitdata_release(struct nfs_commit_data *data) void nfs_commitdata_release(struct nfs_commit_data *data)
...@@ -1693,7 +1697,6 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how, ...@@ -1693,7 +1697,6 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how,
data->mds_ops, how, 0); data->mds_ops, how, 0);
out_bad: out_bad:
nfs_retry_commit(head, NULL, cinfo, 0); nfs_retry_commit(head, NULL, cinfo, 0);
cinfo->completion_ops->error_cleanup(NFS_I(inode));
return -ENOMEM; return -ENOMEM;
} }
...@@ -1755,8 +1758,7 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data) ...@@ -1755,8 +1758,7 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data)
clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC);
nfs_init_cinfo(&cinfo, data->inode, data->dreq); nfs_init_cinfo(&cinfo, data->inode, data->dreq);
if (atomic_dec_and_test(&cinfo.mds->rpcs_out)) nfs_commit_end(cinfo.mds);
nfs_commit_clear_lock(NFS_I(data->inode));
} }
static void nfs_commit_release(void *calldata) static void nfs_commit_release(void *calldata)
...@@ -1775,7 +1777,6 @@ static const struct rpc_call_ops nfs_commit_ops = { ...@@ -1775,7 +1777,6 @@ static const struct rpc_call_ops nfs_commit_ops = {
static const struct nfs_commit_completion_ops nfs_commit_completion_ops = { static const struct nfs_commit_completion_ops nfs_commit_completion_ops = {
.completion = nfs_commit_release_pages, .completion = nfs_commit_release_pages,
.error_cleanup = nfs_commit_clear_lock,
}; };
int nfs_generic_commit_list(struct inode *inode, struct list_head *head, int nfs_generic_commit_list(struct inode *inode, struct list_head *head,
...@@ -1794,30 +1795,25 @@ int nfs_commit_inode(struct inode *inode, int how) ...@@ -1794,30 +1795,25 @@ int nfs_commit_inode(struct inode *inode, int how)
LIST_HEAD(head); LIST_HEAD(head);
struct nfs_commit_info cinfo; struct nfs_commit_info cinfo;
int may_wait = how & FLUSH_SYNC; int may_wait = how & FLUSH_SYNC;
int error = 0;
int res; int res;
res = nfs_commit_set_lock(NFS_I(inode), may_wait);
if (res <= 0)
goto out_mark_dirty;
nfs_init_cinfo_from_inode(&cinfo, inode); nfs_init_cinfo_from_inode(&cinfo, inode);
nfs_commit_begin(cinfo.mds);
res = nfs_scan_commit(inode, &head, &cinfo); res = nfs_scan_commit(inode, &head, &cinfo);
if (res) { if (res)
int error;
error = nfs_generic_commit_list(inode, &head, how, &cinfo); error = nfs_generic_commit_list(inode, &head, how, &cinfo);
if (error < 0) nfs_commit_end(cinfo.mds);
return error; if (error < 0)
if (!may_wait) goto out_error;
goto out_mark_dirty; if (!may_wait)
error = wait_on_bit_action(&NFS_I(inode)->flags, goto out_mark_dirty;
NFS_INO_COMMIT, error = wait_on_commit(cinfo.mds);
nfs_wait_bit_killable, if (error < 0)
TASK_KILLABLE); return error;
if (error < 0)
return error;
} else
nfs_commit_clear_lock(NFS_I(inode));
return res; return res;
out_error:
res = error;
/* Note: If we exit without ensuring that the commit is complete, /* Note: If we exit without ensuring that the commit is complete,
* we must mark the inode as dirty. Otherwise, future calls to * we must mark the inode as dirty. Otherwise, future calls to
* sync_inode() with the WB_SYNC_ALL flag set will fail to ensure * sync_inode() with the WB_SYNC_ALL flag set will fail to ensure
......
...@@ -216,7 +216,6 @@ struct nfs_inode { ...@@ -216,7 +216,6 @@ struct nfs_inode {
#define NFS_INO_FLUSHING (4) /* inode is flushing out data */ #define NFS_INO_FLUSHING (4) /* inode is flushing out data */
#define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */ #define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */
#define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */ #define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */
#define NFS_INO_COMMIT (7) /* inode is committing unstable writes */
#define NFS_INO_LAYOUTCOMMIT (9) /* layoutcommit required */ #define NFS_INO_LAYOUTCOMMIT (9) /* layoutcommit required */
#define NFS_INO_LAYOUTCOMMITTING (10) /* layoutcommit inflight */ #define NFS_INO_LAYOUTCOMMITTING (10) /* layoutcommit inflight */
#define NFS_INO_LAYOUTSTATS (11) /* layoutstats inflight */ #define NFS_INO_LAYOUTSTATS (11) /* layoutstats inflight */
......
...@@ -1423,7 +1423,6 @@ struct nfs_mds_commit_info { ...@@ -1423,7 +1423,6 @@ struct nfs_mds_commit_info {
struct nfs_commit_data; struct nfs_commit_data;
struct nfs_inode; struct nfs_inode;
struct nfs_commit_completion_ops { struct nfs_commit_completion_ops {
void (*error_cleanup) (struct nfs_inode *nfsi);
void (*completion) (struct nfs_commit_data *data); void (*completion) (struct nfs_commit_data *data);
}; };
......
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