Commit b1355604 authored by Trond Myklebust's avatar Trond Myklebust

NFSv2/v3/v4: Add support for asynchronous writes even if wsize<PAGE_CACHE_SIZE.

parent 7e19d190
......@@ -259,6 +259,7 @@ nfs_direct_write_seg(struct inode *inode, struct file *file,
.inode = inode,
.args = {
.fh = NFS_FH(inode),
.lockowner = current->files,
},
.res = {
.fattr = &wdata.fattr,
......
......@@ -763,11 +763,10 @@ nfs3_write_done(struct rpc_task *task)
}
static void
nfs3_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how)
nfs3_proc_write_setup(struct nfs_write_data *data, int how)
{
struct rpc_task *task = &data->task;
struct inode *inode = data->inode;
struct nfs_page *req;
int stable;
int flags;
struct rpc_message msg = {
......@@ -784,28 +783,14 @@ nfs3_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how)
stable = NFS_DATA_SYNC;
} else
stable = NFS_UNSTABLE;
req = nfs_list_entry(data->pages.next);
data->args.fh = NFS_FH(inode);
data->args.offset = req_offset(req);
data->args.pgbase = req->wb_pgbase;
data->args.count = count;
data->args.stable = stable;
data->args.pages = data->pagevec;
data->res.fattr = &data->fattr;
data->res.count = count;
data->res.verf = &data->verf;
/* Set the initial flags for the task. */
flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
/* Finalize the task. */
rpc_init_task(task, NFS_CLIENT(inode), nfs3_write_done, flags);
task->tk_calldata = data;
/* Release requests */
task->tk_release = nfs_writedata_release;
rpc_call_setup(&data->task, &msg, 0);
rpc_call_setup(task, &msg, 0);
}
static void
......@@ -822,7 +807,7 @@ nfs3_commit_done(struct rpc_task *task)
}
static void
nfs3_proc_commit_setup(struct nfs_write_data *data, u64 start, u32 len, int how)
nfs3_proc_commit_setup(struct nfs_write_data *data, int how)
{
struct rpc_task *task = &data->task;
struct inode *inode = data->inode;
......@@ -834,23 +819,12 @@ nfs3_proc_commit_setup(struct nfs_write_data *data, u64 start, u32 len, int how)
.rpc_cred = data->cred,
};
data->args.fh = NFS_FH(data->inode);
data->args.offset = start;
data->args.count = len;
data->res.count = len;
data->res.fattr = &data->fattr;
data->res.verf = &data->verf;
/* Set the initial flags for the task. */
flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
/* Finalize the task. */
rpc_init_task(task, NFS_CLIENT(inode), nfs3_commit_done, flags);
task->tk_calldata = data;
/* Release requests */
task->tk_release = nfs_commit_release;
rpc_call_setup(&data->task, &msg, 0);
rpc_call_setup(task, &msg, 0);
}
/*
......
......@@ -1134,10 +1134,10 @@ nfs4_proc_write(struct nfs_write_data *wdata, struct file *filp)
if (filp) {
struct nfs4_state *state;
state = (struct nfs4_state *)filp->private_data;
nfs4_copy_stateid(&wdata->args.stateid, state, wdata->lockowner);
wdata->args.state = state;
msg.rpc_cred = state->owner->so_cred;
} else {
memcpy(&wdata->args.stateid, &zero_stateid, sizeof(wdata->args.stateid));
wdata->args.state = NULL;
msg.rpc_cred = NFS_I(inode)->mm_cred;
}
......@@ -1166,15 +1166,10 @@ nfs4_proc_commit(struct nfs_write_data *cdata, struct file *filp)
/*
* Try first to use O_WRONLY, then O_RDWR stateid.
*/
if (filp) {
struct nfs4_state *state;
state = (struct nfs4_state *)filp->private_data;
nfs4_copy_stateid(&cdata->args.stateid, state, cdata->lockowner);
msg.rpc_cred = state->owner->so_cred;
} else {
memcpy(&cdata->args.stateid, &zero_stateid, sizeof(cdata->args.stateid));
if (filp)
msg.rpc_cred = ((struct nfs4_state *)filp->private_data)->owner->so_cred;
else
msg.rpc_cred = NFS_I(inode)->mm_cred;
}
fattr->valid = 0;
status = rpc_call_sync(server->client, &msg, 0);
......@@ -1548,20 +1543,6 @@ nfs4_proc_read_setup(struct nfs_read_data *data)
rpc_call_setup(task, &msg, 0);
}
static void
nfs4_restart_write(struct rpc_task *task)
{
struct nfs_write_data *data = (struct nfs_write_data *)task->tk_calldata;
struct nfs_page *req;
rpc_restart_call(task);
req = nfs_list_entry(data->pages.next);
if (req->wb_state)
nfs4_copy_stateid(&data->args.stateid, req->wb_state, req->wb_lockowner);
else
memcpy(&data->args.stateid, &zero_stateid, sizeof(data->args.stateid));
}
static void
nfs4_write_done(struct rpc_task *task)
{
......@@ -1569,7 +1550,7 @@ nfs4_write_done(struct rpc_task *task)
struct inode *inode = data->inode;
if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) {
task->tk_action = nfs4_restart_write;
rpc_restart_call(task);
return;
}
if (task->tk_status >= 0)
......@@ -1579,7 +1560,7 @@ nfs4_write_done(struct rpc_task *task)
}
static void
nfs4_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how)
nfs4_proc_write_setup(struct nfs_write_data *data, int how)
{
struct rpc_task *task = &data->task;
struct rpc_message msg = {
......@@ -1589,7 +1570,6 @@ nfs4_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how)
.rpc_cred = data->cred,
};
struct inode *inode = data->inode;
struct nfs_page *req = nfs_list_entry(data->pages.next);
int stable;
int flags;
......@@ -1600,33 +1580,15 @@ nfs4_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how)
stable = NFS_DATA_SYNC;
} else
stable = NFS_UNSTABLE;
data->args.fh = NFS_FH(inode);
data->args.offset = req_offset(req);
data->args.pgbase = req->wb_pgbase;
data->args.count = count;
data->args.stable = stable;
data->args.pages = data->pagevec;
data->res.fattr = &data->fattr;
data->res.count = count;
data->res.verf = &data->verf;
data->timestamp = jiffies;
data->lockowner = req->wb_lockowner;
if (req->wb_state)
nfs4_copy_stateid(&data->args.stateid, req->wb_state, req->wb_lockowner);
else
memcpy(&data->args.stateid, &zero_stateid, sizeof(data->args.stateid));
data->timestamp = jiffies;
/* Set the initial flags for the task. */
flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
/* Finalize the task. */
rpc_init_task(task, NFS_CLIENT(inode), nfs4_write_done, flags);
task->tk_calldata = data;
/* Release requests */
task->tk_release = nfs_writedata_release;
rpc_call_setup(task, &msg, 0);
}
......@@ -1637,7 +1599,7 @@ nfs4_commit_done(struct rpc_task *task)
struct inode *inode = data->inode;
if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) {
task->tk_action = nfs4_restart_write;
rpc_restart_call(task);
return;
}
/* Call back common NFS writeback processing */
......@@ -1645,7 +1607,7 @@ nfs4_commit_done(struct rpc_task *task)
}
static void
nfs4_proc_commit_setup(struct nfs_write_data *data, u64 start, u32 len, int how)
nfs4_proc_commit_setup(struct nfs_write_data *data, int how)
{
struct rpc_task *task = &data->task;
struct rpc_message msg = {
......@@ -1657,22 +1619,11 @@ nfs4_proc_commit_setup(struct nfs_write_data *data, u64 start, u32 len, int how)
struct inode *inode = data->inode;
int flags;
data->args.fh = NFS_FH(data->inode);
data->args.offset = start;
data->args.count = len;
data->res.count = len;
data->res.fattr = &data->fattr;
data->res.verf = &data->verf;
/* Set the initial flags for the task. */
flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
/* Finalize the task. */
rpc_init_task(task, NFS_CLIENT(inode), nfs4_commit_done, flags);
task->tk_calldata = data;
/* Release requests */
task->tk_release = nfs_commit_release;
rpc_call_setup(task, &msg, 0);
}
......
......@@ -1075,9 +1075,12 @@ encode_write(struct xdr_stream *xdr, struct nfs_writeargs *args)
{
uint32_t *p;
RESERVE_SPACE(36);
RESERVE_SPACE(4);
WRITE32(OP_WRITE);
WRITEMEM(args->stateid.data, sizeof(args->stateid.data));
encode_stateid(xdr, args->state, args->lockowner);
RESERVE_SPACE(16);
WRITE64(args->offset);
WRITE32(args->stable);
WRITE32(args->count);
......
......@@ -590,11 +590,10 @@ nfs_write_done(struct rpc_task *task)
}
static void
nfs_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how)
nfs_proc_write_setup(struct nfs_write_data *data, int how)
{
struct rpc_task *task = &data->task;
struct inode *inode = data->inode;
struct nfs_page *req;
int flags;
struct rpc_message msg = {
.rpc_proc = &nfs_procedures[NFSPROC_WRITE],
......@@ -604,32 +603,18 @@ nfs_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how)
};
/* Note: NFSv2 ignores @stable and always uses NFS_FILE_SYNC */
req = nfs_list_entry(data->pages.next);
data->args.fh = NFS_FH(inode);
data->args.offset = req_offset(req);
data->args.pgbase = req->wb_pgbase;
data->args.count = count;
data->args.stable = NFS_FILE_SYNC;
data->args.pages = data->pagevec;
data->res.fattr = &data->fattr;
data->res.count = count;
data->res.verf = &data->verf;
/* Set the initial flags for the task. */
flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
/* Finalize the task. */
rpc_init_task(task, NFS_CLIENT(inode), nfs_write_done, flags);
task->tk_calldata = data;
/* Release requests */
task->tk_release = nfs_writedata_release;
rpc_call_setup(&data->task, &msg, 0);
rpc_call_setup(task, &msg, 0);
}
static void
nfs_proc_commit_setup(struct nfs_write_data *data, u64 start, u32 len, int how)
nfs_proc_commit_setup(struct nfs_write_data *data, int how)
{
BUG();
}
......
This diff is collapsed.
......@@ -335,10 +335,8 @@ extern int nfs_writepages(struct address_space *, struct writeback_control *);
extern int nfs_flush_incompatible(struct file *file, struct page *page);
extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int);
extern void nfs_writeback_done(struct rpc_task *task);
extern void nfs_writedata_release(struct rpc_task *task);
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
extern void nfs_commit_release(struct rpc_task *task);
extern void nfs_commit_done(struct rpc_task *);
#endif
......
......@@ -253,7 +253,8 @@ struct nfs_readres {
struct nfs_writeargs {
struct nfs_fh * fh;
nfs4_stateid stateid;
fl_owner_t lockowner;
struct nfs4_state * state;
__u64 offset;
__u32 count;
enum nfs3_stable_how stable;
......@@ -681,7 +682,6 @@ struct nfs_write_data {
struct rpc_task task;
struct inode *inode;
struct rpc_cred *cred;
fl_owner_t lockowner;
struct nfs_fattr fattr;
struct nfs_writeverf verf;
struct list_head pages; /* Coalesced requests we wish to flush */
......@@ -742,8 +742,8 @@ struct nfs_rpc_ops {
struct nfs_pathconf *);
u32 * (*decode_dirent)(u32 *, struct nfs_entry *, int plus);
void (*read_setup) (struct nfs_read_data *);
void (*write_setup) (struct nfs_write_data *, unsigned int count, int how);
void (*commit_setup) (struct nfs_write_data *, u64 start, u32 len, int how);
void (*write_setup) (struct nfs_write_data *, int how);
void (*commit_setup) (struct nfs_write_data *, int how);
int (*file_open) (struct inode *, struct file *);
int (*file_release) (struct inode *, struct file *);
void (*request_init)(struct nfs_page *, struct file *);
......
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