Skip to content

Commit

Permalink
NFS: Allow multiple commit requests in flight per file
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Trond Myklebust committed Dec 31, 2015
1 parent dc602dd commit af7cf05
Show file tree
Hide file tree
Showing 7 changed files with 35 additions and 51 deletions.
6 changes: 0 additions & 6 deletions fs/nfs/direct.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion fs/nfs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
1 change: 0 additions & 1 deletion fs/nfs/nfstrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -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" })

Expand Down
5 changes: 1 addition & 4 deletions fs/nfs/pnfs_nfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
70 changes: 33 additions & 37 deletions fs/nfs/write.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down Expand Up @@ -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))
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;
static void nfs_commit_begin(struct nfs_mds_commit_info *cinfo)
{
atomic_inc(&cinfo->rpcs_out);
}

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);
smp_mb__after_atomic();
wake_up_bit(&nfsi->flags, NFS_INO_COMMIT);
if (atomic_dec_and_test(&cinfo->rpcs_out))
wake_up_atomic_t(&cinfo->rpcs_out);
}

void nfs_commitdata_release(struct nfs_commit_data *data)
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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)
Expand All @@ -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,
Expand All @@ -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
Expand Down
1 change: 0 additions & 1 deletion include/linux/nfs_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
1 change: 0 additions & 1 deletion include/linux/nfs_xdr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};

Expand Down

0 comments on commit af7cf05

Please sign in to comment.