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: Trond Myklebust <trond.myklebust@primarydata.com>
This commit is contained in:
parent
dc602dd706
commit
af7cf05793
|
@ -721,14 +721,8 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data)
|
|||
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 = {
|
||||
.completion = nfs_direct_commit_complete,
|
||||
.error_cleanup = nfs_direct_error_cleanup,
|
||||
};
|
||||
|
||||
static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq)
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
nfsi = NFS_I(mapping->host);
|
||||
if (test_bit(NFS_INO_COMMIT, &nfsi->flags)) {
|
||||
if (atomic_read(&nfsi->commit_info.rpcs_out)) {
|
||||
*writeback = true;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
{ 1 << NFS_INO_INVALIDATING, "INVALIDATING" }, \
|
||||
{ 1 << NFS_INO_FLUSHING, "FLUSHING" }, \
|
||||
{ 1 << NFS_INO_FSCACHE, "FSCACHE" }, \
|
||||
{ 1 << NFS_INO_COMMIT, "COMMIT" }, \
|
||||
{ 1 << NFS_INO_LAYOUTCOMMIT, "NEED_LAYOUTCOMMIT" }, \
|
||||
{ 1 << NFS_INO_LAYOUTCOMMITTING, "LAYOUTCOMMIT" })
|
||||
|
||||
|
|
|
@ -266,17 +266,14 @@ pnfs_generic_commit_pagelist(struct inode *inode, struct list_head *mds_pages,
|
|||
} else {
|
||||
nfs_retry_commit(mds_pages, NULL, cinfo, 0);
|
||||
pnfs_generic_retry_commit(cinfo, 0);
|
||||
cinfo->completion_ops->error_cleanup(NFS_I(inode));
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
nreq += pnfs_generic_alloc_ds_commits(cinfo, &list);
|
||||
|
||||
if (nreq == 0) {
|
||||
cinfo->completion_ops->error_cleanup(NFS_I(inode));
|
||||
if (nreq == 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
atomic_add(nreq, &cinfo->mds->rpcs_out);
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include <linux/nfs_page.h>
|
||||
#include <linux/backing-dev.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
|
@ -1535,27 +1537,29 @@ static void nfs_writeback_result(struct rpc_task *task,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static int nfs_commit_set_lock(struct nfs_inode *nfsi, int may_wait)
|
||||
static int nfs_wait_atomic_killable(atomic_t *key)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!test_and_set_bit(NFS_INO_COMMIT, &nfsi->flags))
|
||||
return 1;
|
||||
if (!may_wait)
|
||||
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;
|
||||
if (fatal_signal_pending(current))
|
||||
return -ERESTARTSYS;
|
||||
freezable_schedule_unsafe();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nfs_commit_clear_lock(struct nfs_inode *nfsi)
|
||||
static int wait_on_commit(struct nfs_mds_commit_info *cinfo)
|
||||
{
|
||||
clear_bit(NFS_INO_COMMIT, &nfsi->flags);
|
||||
smp_mb__after_atomic();
|
||||
wake_up_bit(&nfsi->flags, NFS_INO_COMMIT);
|
||||
return wait_on_atomic_t(&cinfo->rpcs_out,
|
||||
nfs_wait_atomic_killable, TASK_KILLABLE);
|
||||
}
|
||||
|
||||
static void nfs_commit_begin(struct nfs_mds_commit_info *cinfo)
|
||||
{
|
||||
atomic_inc(&cinfo->rpcs_out);
|
||||
}
|
||||
|
||||
static void nfs_commit_end(struct nfs_mds_commit_info *cinfo)
|
||||
{
|
||||
if (atomic_dec_and_test(&cinfo->rpcs_out))
|
||||
wake_up_atomic_t(&cinfo->rpcs_out);
|
||||
}
|
||||
|
||||
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,
|
|||
data->mds_ops, how, 0);
|
||||
out_bad:
|
||||
nfs_retry_commit(head, NULL, cinfo, 0);
|
||||
cinfo->completion_ops->error_cleanup(NFS_I(inode));
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
nfs_init_cinfo(&cinfo, data->inode, data->dreq);
|
||||
if (atomic_dec_and_test(&cinfo.mds->rpcs_out))
|
||||
nfs_commit_clear_lock(NFS_I(data->inode));
|
||||
nfs_commit_end(cinfo.mds);
|
||||
}
|
||||
|
||||
static void nfs_commit_release(void *calldata)
|
||||
|
@ -1775,7 +1777,6 @@ static const struct rpc_call_ops nfs_commit_ops = {
|
|||
|
||||
static const struct nfs_commit_completion_ops nfs_commit_completion_ops = {
|
||||
.completion = nfs_commit_release_pages,
|
||||
.error_cleanup = nfs_commit_clear_lock,
|
||||
};
|
||||
|
||||
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)
|
|||
LIST_HEAD(head);
|
||||
struct nfs_commit_info cinfo;
|
||||
int may_wait = how & FLUSH_SYNC;
|
||||
int error = 0;
|
||||
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_commit_begin(cinfo.mds);
|
||||
res = nfs_scan_commit(inode, &head, &cinfo);
|
||||
if (res) {
|
||||
int error;
|
||||
|
||||
if (res)
|
||||
error = nfs_generic_commit_list(inode, &head, how, &cinfo);
|
||||
if (error < 0)
|
||||
return error;
|
||||
if (!may_wait)
|
||||
goto out_mark_dirty;
|
||||
error = wait_on_bit_action(&NFS_I(inode)->flags,
|
||||
NFS_INO_COMMIT,
|
||||
nfs_wait_bit_killable,
|
||||
TASK_KILLABLE);
|
||||
if (error < 0)
|
||||
return error;
|
||||
} else
|
||||
nfs_commit_clear_lock(NFS_I(inode));
|
||||
nfs_commit_end(cinfo.mds);
|
||||
if (error < 0)
|
||||
goto out_error;
|
||||
if (!may_wait)
|
||||
goto out_mark_dirty;
|
||||
error = wait_on_commit(cinfo.mds);
|
||||
if (error < 0)
|
||||
return error;
|
||||
return res;
|
||||
out_error:
|
||||
res = error;
|
||||
/* Note: If we exit without ensuring that the commit is complete,
|
||||
* we must mark the inode as dirty. Otherwise, future calls to
|
||||
* sync_inode() with the WB_SYNC_ALL flag set will fail to ensure
|
||||
|
|
|
@ -216,7 +216,6 @@ struct nfs_inode {
|
|||
#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_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_LAYOUTCOMMITTING (10) /* layoutcommit inflight */
|
||||
#define NFS_INO_LAYOUTSTATS (11) /* layoutstats inflight */
|
||||
|
|
|
@ -1423,7 +1423,6 @@ struct nfs_mds_commit_info {
|
|||
struct nfs_commit_data;
|
||||
struct nfs_inode;
|
||||
struct nfs_commit_completion_ops {
|
||||
void (*error_cleanup) (struct nfs_inode *nfsi);
|
||||
void (*completion) (struct nfs_commit_data *data);
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue