Commit c44ca040 authored by Trond Myklebust's avatar Trond Myklebust

[PATCH] A basic NFSv4 client for 2.5.x

This is a nontrivial change to the NFS client.

This patch does for the async WRITE and COMMIT paths what patch 15
did for the async READ path, by defining new nfs_rpc_ops ->setup_write()
and ->setup_commit().
parent 5dfe032f
...@@ -692,6 +692,101 @@ nfs3_proc_read_setup(struct nfs_read_data *data, unsigned int count) ...@@ -692,6 +692,101 @@ nfs3_proc_read_setup(struct nfs_read_data *data, unsigned int count)
rpc_call_setup(&data->task, &msg, 0); rpc_call_setup(&data->task, &msg, 0);
} }
static void
nfs3_write_done(struct rpc_task *task)
{
struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
if (nfs_async_handle_jukebox(task))
return;
nfs_writeback_done(task, data->u.v3.args.stable,
data->u.v3.args.count, data->u.v3.res.count);
}
static void
nfs3_proc_write_setup(struct nfs_write_data *data, unsigned int count, 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;
if (how & FLUSH_STABLE) {
if (!NFS_I(inode)->ncommit)
stable = NFS_FILE_SYNC;
else
stable = NFS_DATA_SYNC;
} else
stable = NFS_UNSTABLE;
req = nfs_list_entry(data->pages.next);
data->u.v3.args.fh = NFS_FH(inode);
data->u.v3.args.offset = req_offset(req) + req->wb_offset;
data->u.v3.args.pgbase = req->wb_offset;
data->u.v3.args.count = count;
data->u.v3.args.stable = stable;
data->u.v3.args.pages = data->pagevec;
data->u.v3.res.fattr = &data->fattr;
data->u.v3.res.count = count;
data->u.v3.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;
msg.rpc_proc = NFS3PROC_WRITE;
msg.rpc_argp = &data->u.v3.args;
msg.rpc_resp = &data->u.v3.res;
msg.rpc_cred = data->cred;
rpc_call_setup(&data->task, &msg, 0);
}
static void
nfs3_commit_done(struct rpc_task *task)
{
if (nfs_async_handle_jukebox(task))
return;
nfs_commit_done(task);
}
static void
nfs3_proc_commit_setup(struct nfs_write_data *data, u64 start, u32 len, int how)
{
struct rpc_task *task = &data->task;
struct inode *inode = data->inode;
int flags;
struct rpc_message msg;
data->u.v3.args.fh = NFS_FH(data->inode);
data->u.v3.args.offset = start;
data->u.v3.args.count = len;
data->u.v3.res.count = len;
data->u.v3.res.fattr = &data->fattr;
data->u.v3.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_writedata_release;
msg.rpc_proc = NFS3PROC_COMMIT;
msg.rpc_argp = &data->u.v3.args;
msg.rpc_resp = &data->u.v3.res;
msg.rpc_cred = data->cred;
rpc_call_setup(&data->task, &msg, 0);
}
struct nfs_rpc_ops nfs_v3_clientops = { struct nfs_rpc_ops nfs_v3_clientops = {
.version = 3, /* protocol version */ .version = 3, /* protocol version */
.getroot = nfs3_proc_get_root, .getroot = nfs3_proc_get_root,
...@@ -716,4 +811,6 @@ struct nfs_rpc_ops nfs_v3_clientops = { ...@@ -716,4 +811,6 @@ struct nfs_rpc_ops nfs_v3_clientops = {
.statfs = nfs3_proc_statfs, .statfs = nfs3_proc_statfs,
.decode_dirent = nfs3_decode_dirent, .decode_dirent = nfs3_decode_dirent,
.read_setup = nfs3_proc_read_setup, .read_setup = nfs3_proc_read_setup,
.write_setup = nfs3_proc_write_setup,
.commit_setup = nfs3_proc_commit_setup,
}; };
...@@ -512,6 +512,58 @@ nfs_proc_read_setup(struct nfs_read_data *data, unsigned int count) ...@@ -512,6 +512,58 @@ nfs_proc_read_setup(struct nfs_read_data *data, unsigned int count)
rpc_call_setup(&data->task, &msg, 0); rpc_call_setup(&data->task, &msg, 0);
} }
static void
nfs_write_done(struct rpc_task *task)
{
struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
nfs_writeback_done(task, data->u.v3.args.stable,
data->u.v3.args.count, data->u.v3.res.count);
}
static void
nfs_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how)
{
struct rpc_task *task = &data->task;
struct inode *inode = data->inode;
struct nfs_page *req;
int flags;
struct rpc_message msg;
/* Note: NFSv2 ignores @stable and always uses NFS_FILE_SYNC */
req = nfs_list_entry(data->pages.next);
data->u.v3.args.fh = NFS_FH(inode);
data->u.v3.args.offset = req_offset(req) + req->wb_offset;
data->u.v3.args.pgbase = req->wb_offset;
data->u.v3.args.count = count;
data->u.v3.args.stable = NFS_FILE_SYNC;
data->u.v3.args.pages = data->pagevec;
data->u.v3.res.fattr = &data->fattr;
data->u.v3.res.count = count;
data->u.v3.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;
msg.rpc_proc = NFSPROC_WRITE;
msg.rpc_argp = &data->u.v3.args;
msg.rpc_resp = &data->u.v3.res;
msg.rpc_cred = data->cred;
rpc_call_setup(&data->task, &msg, 0);
}
static void
nfs_proc_commit_setup(struct nfs_write_data *data, u64 start, u32 len, int how)
{
BUG();
}
struct nfs_rpc_ops nfs_v2_clientops = { struct nfs_rpc_ops nfs_v2_clientops = {
.version = 2, /* protocol version */ .version = 2, /* protocol version */
.getroot = nfs_proc_get_root, .getroot = nfs_proc_get_root,
...@@ -537,4 +589,6 @@ struct nfs_rpc_ops nfs_v2_clientops = { ...@@ -537,4 +589,6 @@ struct nfs_rpc_ops nfs_v2_clientops = {
.statfs = nfs_proc_statfs, .statfs = nfs_proc_statfs,
.decode_dirent = nfs_decode_dirent, .decode_dirent = nfs_decode_dirent,
.read_setup = nfs_proc_read_setup, .read_setup = nfs_proc_read_setup,
.write_setup = nfs_proc_write_setup,
.commit_setup = nfs_proc_commit_setup,
}; };
...@@ -63,30 +63,6 @@ ...@@ -63,30 +63,6 @@
#define NFSDBG_FACILITY NFSDBG_PAGECACHE #define NFSDBG_FACILITY NFSDBG_PAGECACHE
/*
* Local structures
*
* This is the struct where the WRITE/COMMIT arguments go.
*/
struct nfs_write_data {
struct rpc_task task;
struct inode *inode;
struct rpc_cred *cred;
struct nfs_fattr fattr;
struct nfs_writeverf verf;
struct list_head pages; /* Coalesced requests we wish to flush */
struct page *pagevec[NFS_WRITE_MAXIOV];
union {
struct {
struct nfs_writeargs args;
struct nfs_writeres res;
} v3;
#ifdef CONFIG_NFS_V4
/* NFSv4 data to come here... */
#endif
} u;
};
/* /*
* Local function declarations * Local function declarations
*/ */
...@@ -94,15 +70,6 @@ static struct nfs_page * nfs_update_request(struct file*, struct inode *, ...@@ -94,15 +70,6 @@ static struct nfs_page * nfs_update_request(struct file*, struct inode *,
struct page *, struct page *,
unsigned int, unsigned int); unsigned int, unsigned int);
static void nfs_strategy(struct inode *inode); static void nfs_strategy(struct inode *inode);
static void nfs_writeback_done(struct rpc_task *);
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
static void nfs_commit_done(struct rpc_task *);
#endif
/* Hack for future NFS swap support */
#ifndef IS_SWAPFILE
# define IS_SWAPFILE(inode) (0)
#endif
static kmem_cache_t *nfs_wdata_cachep; static kmem_cache_t *nfs_wdata_cachep;
...@@ -113,7 +80,6 @@ static __inline__ struct nfs_write_data *nfs_writedata_alloc(void) ...@@ -113,7 +80,6 @@ static __inline__ struct nfs_write_data *nfs_writedata_alloc(void)
if (p) { if (p) {
memset(p, 0, sizeof(*p)); memset(p, 0, sizeof(*p));
INIT_LIST_HEAD(&p->pages); INIT_LIST_HEAD(&p->pages);
p->u.v3.args.pages = p->pagevec;
} }
return p; return p;
} }
...@@ -123,7 +89,7 @@ static __inline__ void nfs_writedata_free(struct nfs_write_data *p) ...@@ -123,7 +89,7 @@ static __inline__ void nfs_writedata_free(struct nfs_write_data *p)
kmem_cache_free(nfs_wdata_cachep, p); kmem_cache_free(nfs_wdata_cachep, p);
} }
static void nfs_writedata_release(struct rpc_task *task) void nfs_writedata_release(struct rpc_task *task)
{ {
struct nfs_write_data *wdata = (struct nfs_write_data *)task->tk_calldata; struct nfs_write_data *wdata = (struct nfs_write_data *)task->tk_calldata;
nfs_writedata_free(wdata); nfs_writedata_free(wdata);
...@@ -867,8 +833,10 @@ nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsign ...@@ -867,8 +833,10 @@ nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsign
* Set up the argument/result storage required for the RPC call. * Set up the argument/result storage required for the RPC call.
*/ */
static void static void
nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data) nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data, int how)
{ {
struct rpc_task *task = &data->task;
struct inode *inode;
struct nfs_page *req; struct nfs_page *req;
struct page **pages; struct page **pages;
unsigned int count; unsigned int count;
...@@ -876,7 +844,7 @@ nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data) ...@@ -876,7 +844,7 @@ nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data)
/* Set up the RPC argument and reply structs /* Set up the RPC argument and reply structs
* NB: take care not to mess about with data->commit et al. */ * NB: take care not to mess about with data->commit et al. */
pages = data->u.v3.args.pages; pages = data->pagevec;
count = 0; count = 0;
while (!list_empty(head)) { while (!list_empty(head)) {
req = nfs_list_entry(head->next); req = nfs_list_entry(head->next);
...@@ -886,17 +854,18 @@ nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data) ...@@ -886,17 +854,18 @@ nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data)
count += req->wb_bytes; count += req->wb_bytes;
} }
req = nfs_list_entry(data->pages.next); req = nfs_list_entry(data->pages.next);
data->inode = req->wb_inode; data->inode = inode = req->wb_inode;
data->cred = req->wb_cred; data->cred = req->wb_cred;
data->u.v3.args.fh = NFS_FH(req->wb_inode);
data->u.v3.args.offset = req_offset(req) + req->wb_offset;
data->u.v3.args.pgbase = req->wb_offset;
data->u.v3.args.count = count;
data->u.v3.res.fattr = &data->fattr;
data->u.v3.res.count = count;
data->u.v3.res.verf = &data->verf;
}
NFS_PROTO(inode)->write_setup(data, count, how);
dprintk("NFS: %4d initiated write call (req %s/%Ld, %u bytes @ offset %Lu)\n",
task->tk_pid,
inode->i_sb->s_id,
(long long)NFS_FILEID(inode),
count,
(unsigned long long)req_offset(req) + req->wb_offset);
}
/* /*
* Create an RPC task for the given write request and kick it. * Create an RPC task for the given write request and kick it.
...@@ -909,64 +878,20 @@ nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data) ...@@ -909,64 +878,20 @@ nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data)
static int static int
nfs_flush_one(struct list_head *head, struct inode *inode, int how) nfs_flush_one(struct list_head *head, struct inode *inode, int how)
{ {
struct nfs_inode *nfsi = NFS_I(inode);
struct rpc_clnt *clnt = NFS_CLIENT(inode); struct rpc_clnt *clnt = NFS_CLIENT(inode);
struct nfs_write_data *data; struct nfs_write_data *data;
struct rpc_task *task;
struct rpc_message msg;
int flags,
nfsvers = NFS_PROTO(inode)->version,
async = !(how & FLUSH_SYNC),
stable = (how & FLUSH_STABLE);
sigset_t oldset; sigset_t oldset;
data = nfs_writedata_alloc(); data = nfs_writedata_alloc();
if (!data) if (!data)
goto out_bad; goto out_bad;
task = &data->task;
/* Set the initial flags for the task. */
flags = (async) ? RPC_TASK_ASYNC : 0;
/* Set up the argument struct */ /* Set up the argument struct */
nfs_write_rpcsetup(head, data); nfs_write_rpcsetup(head, data, how);
if (nfsvers < 3)
data->u.v3.args.stable = NFS_FILE_SYNC;
else if (stable) {
if (!nfsi->ncommit)
data->u.v3.args.stable = NFS_FILE_SYNC;
else
data->u.v3.args.stable = NFS_DATA_SYNC;
} else
data->u.v3.args.stable = NFS_UNSTABLE;
/* Finalize the task. */
rpc_init_task(task, clnt, nfs_writeback_done, flags);
task->tk_calldata = data;
/* Release requests */
task->tk_release = nfs_writedata_release;
#ifdef CONFIG_NFS_V3
msg.rpc_proc = (nfsvers == 3) ? NFS3PROC_WRITE : NFSPROC_WRITE;
#else
msg.rpc_proc = NFSPROC_WRITE;
#endif
msg.rpc_argp = &data->u.v3.args;
msg.rpc_resp = &data->u.v3.res;
msg.rpc_cred = data->cred;
dprintk("NFS: %4d initiated write call (req %s/%Ld, %u bytes @ offset %Lu)\n",
task->tk_pid,
inode->i_sb->s_id,
(long long)NFS_FILEID(inode),
(unsigned int)data->u.v3.args.count,
(unsigned long long)data->u.v3.args.offset);
rpc_clnt_sigmask(clnt, &oldset); rpc_clnt_sigmask(clnt, &oldset);
rpc_call_setup(task, &msg, 0);
lock_kernel(); lock_kernel();
rpc_execute(task); rpc_execute(&data->task);
unlock_kernel(); unlock_kernel();
rpc_clnt_sigunmask(clnt, &oldset); rpc_clnt_sigunmask(clnt, &oldset);
return 0; return 0;
...@@ -1011,12 +936,11 @@ nfs_flush_list(struct list_head *head, int wpages, int how) ...@@ -1011,12 +936,11 @@ nfs_flush_list(struct list_head *head, int wpages, int how)
/* /*
* This function is called when the WRITE call is complete. * This function is called when the WRITE call is complete.
*/ */
static void void
nfs_writeback_done(struct rpc_task *task) nfs_writeback_done(struct rpc_task *task, int stable,
unsigned int arg_count, unsigned int res_count)
{ {
struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata; struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
struct nfs_writeargs *argp = &data->u.v3.args;
struct nfs_writeres *resp = &data->u.v3.res;
struct inode *inode = data->inode; struct inode *inode = data->inode;
struct nfs_page *req; struct nfs_page *req;
struct page *page; struct page *page;
...@@ -1024,11 +948,8 @@ nfs_writeback_done(struct rpc_task *task) ...@@ -1024,11 +948,8 @@ nfs_writeback_done(struct rpc_task *task)
dprintk("NFS: %4d nfs_writeback_done (status %d)\n", dprintk("NFS: %4d nfs_writeback_done (status %d)\n",
task->tk_pid, task->tk_status); task->tk_pid, task->tk_status);
if (nfs_async_handle_jukebox(task))
return;
/* We can't handle that yet but we check for it nevertheless */ /* We can't handle that yet but we check for it nevertheless */
if (resp->count < argp->count && task->tk_status >= 0) { if (res_count < arg_count && task->tk_status >= 0) {
static unsigned long complain; static unsigned long complain;
if (time_before(complain, jiffies)) { if (time_before(complain, jiffies)) {
printk(KERN_WARNING printk(KERN_WARNING
...@@ -1040,7 +961,7 @@ nfs_writeback_done(struct rpc_task *task) ...@@ -1040,7 +961,7 @@ nfs_writeback_done(struct rpc_task *task)
task->tk_status = -EIO; task->tk_status = -EIO;
} }
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
if (resp->verf->committed < argp->stable && task->tk_status >= 0) { if (data->verf.committed < stable && task->tk_status >= 0) {
/* We tried a write call, but the server did not /* We tried a write call, but the server did not
* commit data to stable storage even though we * commit data to stable storage even though we
* requested it. * requested it.
...@@ -1052,10 +973,10 @@ nfs_writeback_done(struct rpc_task *task) ...@@ -1052,10 +973,10 @@ nfs_writeback_done(struct rpc_task *task)
static unsigned long complain; static unsigned long complain;
if (time_before(complain, jiffies)) { if (time_before(complain, jiffies)) {
dprintk("NFS: faulty NFSv3 server %s:" dprintk("NFS: faulty NFS server %s:"
" (committed = %d) != (stable = %d)\n", " (committed = %d) != (stable = %d)\n",
NFS_SERVER(inode)->hostname, NFS_SERVER(inode)->hostname,
resp->verf->committed, argp->stable); data->verf.committed, stable);
complain = jiffies + 300 * HZ; complain = jiffies + 300 * HZ;
} }
} }
...@@ -1067,7 +988,7 @@ nfs_writeback_done(struct rpc_task *task) ...@@ -1067,7 +988,7 @@ nfs_writeback_done(struct rpc_task *task)
* writebacks since the page->count is kept > 1 for as long * writebacks since the page->count is kept > 1 for as long
* as the page has a write request pending. * as the page has a write request pending.
*/ */
nfs_write_attributes(inode, resp->fattr); nfs_write_attributes(inode, &data->fattr);
while (!list_empty(&data->pages)) { while (!list_empty(&data->pages)) {
req = nfs_list_entry(data->pages.next); req = nfs_list_entry(data->pages.next);
nfs_list_remove_request(req); nfs_list_remove_request(req);
...@@ -1090,12 +1011,12 @@ nfs_writeback_done(struct rpc_task *task) ...@@ -1090,12 +1011,12 @@ nfs_writeback_done(struct rpc_task *task)
} }
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
if (argp->stable != NFS_UNSTABLE || resp->verf->committed == NFS_FILE_SYNC) { if (stable != NFS_UNSTABLE || data->verf.committed == NFS_FILE_SYNC) {
nfs_inode_remove_request(req); nfs_inode_remove_request(req);
dprintk(" OK\n"); dprintk(" OK\n");
goto next; goto next;
} }
memcpy(&req->wb_verf, resp->verf, sizeof(req->wb_verf)); memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf));
req->wb_timeout = jiffies + NFS_COMMIT_DELAY; req->wb_timeout = jiffies + NFS_COMMIT_DELAY;
nfs_mark_request_commit(req); nfs_mark_request_commit(req);
dprintk(" marked for commit\n"); dprintk(" marked for commit\n");
...@@ -1113,8 +1034,9 @@ nfs_writeback_done(struct rpc_task *task) ...@@ -1113,8 +1034,9 @@ nfs_writeback_done(struct rpc_task *task)
* Set up the argument/result storage required for the RPC call. * Set up the argument/result storage required for the RPC call.
*/ */
static void static void
nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data) nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data, int how)
{ {
struct rpc_task *task = &data->task;
struct nfs_page *first, *last; struct nfs_page *first, *last;
struct inode *inode; struct inode *inode;
loff_t start, end, len; loff_t start, end, len;
...@@ -1140,11 +1062,10 @@ nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data) ...@@ -1140,11 +1062,10 @@ nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data)
data->inode = inode; data->inode = inode;
data->cred = first->wb_cred; data->cred = first->wb_cred;
data->u.v3.args.fh = NFS_FH(inode);
data->u.v3.args.offset = start; NFS_PROTO(inode)->commit_setup(data, start, len, how);
data->u.v3.res.count = data->u.v3.args.count = (u32)len;
data->u.v3.res.fattr = &data->fattr; dprintk("NFS: %4d initiated commit call\n", task->tk_pid);
data->u.v3.res.verf = &data->verf;
} }
/* /*
...@@ -1153,43 +1074,23 @@ nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data) ...@@ -1153,43 +1074,23 @@ nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data)
int int
nfs_commit_list(struct list_head *head, int how) nfs_commit_list(struct list_head *head, int how)
{ {
struct rpc_message msg;
struct rpc_clnt *clnt; struct rpc_clnt *clnt;
struct nfs_write_data *data; struct nfs_write_data *data;
struct rpc_task *task;
struct nfs_page *req; struct nfs_page *req;
int flags,
async = !(how & FLUSH_SYNC);
sigset_t oldset; sigset_t oldset;
data = nfs_writedata_alloc(); data = nfs_writedata_alloc();
if (!data) if (!data)
goto out_bad; goto out_bad;
task = &data->task;
flags = (async) ? RPC_TASK_ASYNC : 0;
/* Set up the argument struct */ /* Set up the argument struct */
nfs_commit_rpcsetup(head, data); nfs_commit_rpcsetup(head, data, how);
req = nfs_list_entry(data->pages.next); clnt = NFS_CLIENT(data->inode);
clnt = NFS_CLIENT(req->wb_inode);
rpc_init_task(task, clnt, nfs_commit_done, flags);
task->tk_calldata = data;
/* Release requests */
task->tk_release = nfs_writedata_release;
msg.rpc_proc = NFS3PROC_COMMIT;
msg.rpc_argp = &data->u.v3.args;
msg.rpc_resp = &data->u.v3.res;
msg.rpc_cred = data->cred;
dprintk("NFS: %4d initiated commit call\n", task->tk_pid);
rpc_clnt_sigmask(clnt, &oldset); rpc_clnt_sigmask(clnt, &oldset);
rpc_call_setup(task, &msg, 0);
lock_kernel(); lock_kernel();
rpc_execute(task); rpc_execute(&data->task);
unlock_kernel(); unlock_kernel();
rpc_clnt_sigunmask(clnt, &oldset); rpc_clnt_sigunmask(clnt, &oldset);
return 0; return 0;
...@@ -1206,21 +1107,17 @@ nfs_commit_list(struct list_head *head, int how) ...@@ -1206,21 +1107,17 @@ nfs_commit_list(struct list_head *head, int how)
/* /*
* COMMIT call returned * COMMIT call returned
*/ */
static void void
nfs_commit_done(struct rpc_task *task) nfs_commit_done(struct rpc_task *task)
{ {
struct nfs_write_data *data = (struct nfs_write_data *)task->tk_calldata; struct nfs_write_data *data = (struct nfs_write_data *)task->tk_calldata;
struct nfs_writeres *resp = &data->u.v3.res;
struct nfs_page *req; struct nfs_page *req;
struct inode *inode = data->inode; struct inode *inode = data->inode;
dprintk("NFS: %4d nfs_commit_done (status %d)\n", dprintk("NFS: %4d nfs_commit_done (status %d)\n",
task->tk_pid, task->tk_status); task->tk_pid, task->tk_status);
if (nfs_async_handle_jukebox(task)) nfs_write_attributes(inode, &data->fattr);
return;
nfs_write_attributes(inode, resp->fattr);
while (!list_empty(&data->pages)) { while (!list_empty(&data->pages)) {
req = nfs_list_entry(data->pages.next); req = nfs_list_entry(data->pages.next);
nfs_list_remove_request(req); nfs_list_remove_request(req);
......
...@@ -323,6 +323,14 @@ extern void nfs_complete_unlink(struct dentry *); ...@@ -323,6 +323,14 @@ extern void nfs_complete_unlink(struct dentry *);
extern int nfs_writepage(struct page *); extern int nfs_writepage(struct page *);
extern int nfs_flush_incompatible(struct file *file, struct page *page); extern int nfs_flush_incompatible(struct file *file, struct page *page);
extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int); extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int);
extern void nfs_writeback_done(struct rpc_task *task, int stable,
unsigned int arg_count, unsigned int res_count);
extern void nfs_writedata_release(struct rpc_task *task);
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
extern void nfs_commit_done(struct rpc_task *);
#endif
/* /*
* Try to write back everything synchronously (but check the * Try to write back everything synchronously (but check the
* return value!) * return value!)
......
...@@ -326,6 +326,25 @@ struct nfs_read_data { ...@@ -326,6 +326,25 @@ struct nfs_read_data {
} u; } u;
}; };
struct nfs_write_data {
struct rpc_task task;
struct inode *inode;
struct rpc_cred *cred;
struct nfs_fattr fattr;
struct nfs_writeverf verf;
struct list_head pages; /* Coalesced requests we wish to flush */
struct page *pagevec[NFS_WRITE_MAXIOV];
union {
struct {
struct nfs_writeargs args;
struct nfs_writeres res;
} v3;
#ifdef CONFIG_NFS_V4
/* NFSv4 data to come here... */
#endif
} u;
};
/* /*
* RPC procedure vector for NFSv2/NFSv3 demuxing * RPC procedure vector for NFSv2/NFSv3 demuxing
*/ */
...@@ -374,6 +393,8 @@ struct nfs_rpc_ops { ...@@ -374,6 +393,8 @@ struct nfs_rpc_ops {
struct nfs_fsinfo *); struct nfs_fsinfo *);
u32 * (*decode_dirent)(u32 *, struct nfs_entry *, int plus); u32 * (*decode_dirent)(u32 *, struct nfs_entry *, int plus);
void (*read_setup) (struct nfs_read_data *, unsigned int count); void (*read_setup) (struct nfs_read_data *, unsigned int count);
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);
}; };
/* /*
......
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