summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2004-04-12 02:31:17 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-04-12 02:31:17 -0700
commit193ce3bea659ee78cff8288b5e9ec9186fcb1b30 (patch)
tree692380518671e92adc505c7072aaee0225af3d82
parentf2d816ef30bba85a850166fa3a6404a544f8849f (diff)
parent78a21ca05cd8217251d1bcb96b72f9dca11a4eaf (diff)
Merge NFS conflicts
-rw-r--r--fs/lockd/clntlock.c1
-rw-r--r--fs/lockd/clntproc.c46
-rw-r--r--fs/nfs/direct.c9
-rw-r--r--fs/nfs/inode.c23
-rw-r--r--fs/nfs/nfs2xdr.c6
-rw-r--r--fs/nfs/nfs3proc.c55
-rw-r--r--fs/nfs/nfs3xdr.c6
-rw-r--r--fs/nfs/nfs4proc.c1121
-rw-r--r--fs/nfs/nfs4state.c2
-rw-r--r--fs/nfs/nfs4xdr.c2575
-rw-r--r--fs/nfs/nfsroot.c218
-rw-r--r--fs/nfs/pagelist.c3
-rw-r--r--fs/nfs/proc.c42
-rw-r--r--fs/nfs/read.c341
-rw-r--r--fs/nfs/write.c535
-rw-r--r--include/linux/nfs4.h131
-rw-r--r--include/linux/nfs_fs.h16
-rw-r--r--include/linux/nfs_fs_sb.h11
-rw-r--r--include/linux/nfs_page.h42
-rw-r--r--include/linux/nfs_xdr.h276
-rw-r--r--include/linux/sunrpc/sched.h66
-rw-r--r--include/linux/sunrpc/xdr.h91
-rw-r--r--include/linux/sunrpc/xprt.h9
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c9
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_crypto.c35
-rw-r--r--net/sunrpc/clnt.c12
-rw-r--r--net/sunrpc/sched.c244
-rw-r--r--net/sunrpc/sunrpc_syms.c3
-rw-r--r--net/sunrpc/xdr.c202
-rw-r--r--net/sunrpc/xprt.c89
30 files changed, 3651 insertions, 2568 deletions
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c
index 6c95574b2cfc..59c6c49fe196 100644
--- a/fs/lockd/clntlock.c
+++ b/fs/lockd/clntlock.c
@@ -228,7 +228,6 @@ restart:
}
host->h_reclaiming = 0;
- wake_up(&host->h_gracewait);
/* Now, wake up all processes that sleep on a blocked lock */
for (block = nlm_blocked; block; block = block->b_next) {
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 8a3e7d694992..319e28fde008 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -217,6 +217,21 @@ nlmclnt_alloc_call(void)
return NULL;
}
+static int nlm_wait_on_grace(wait_queue_head_t *queue)
+{
+ DEFINE_WAIT(wait);
+ int status = -EINTR;
+
+ prepare_to_wait(queue, &wait, TASK_INTERRUPTIBLE);
+ if (!signalled ()) {
+ schedule_timeout(NLMCLNT_GRACE_WAIT);
+ if (!signalled ())
+ status = 0;
+ }
+ finish_wait(queue, &wait);
+ return status;
+}
+
/*
* Generic NLM call
*/
@@ -241,10 +256,8 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc)
msg.rpc_cred = nfs_file_cred(filp);
do {
- if (host->h_reclaiming && !argp->reclaim) {
- interruptible_sleep_on(&host->h_gracewait);
- continue;
- }
+ if (host->h_reclaiming && !argp->reclaim)
+ goto in_grace_period;
/* If we have no RPC client yet, create one. */
if ((clnt = nlm_bind_host(host)) == NULL)
@@ -279,22 +292,23 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc)
return -ENOLCK;
}
} else {
+ if (!argp->reclaim) {
+ /* We appear to be out of the grace period */
+ wake_up_all(&host->h_gracewait);
+ }
dprintk("lockd: server returns status %d\n", resp->status);
return 0; /* Okay, call complete */
}
- /* Back off a little and try again */
- interruptible_sleep_on_timeout(&host->h_gracewait, 15*HZ);
-
- /* When the lock requested by F_SETLKW isn't available,
- we will wait until the request can be satisfied. If
- a signal is received during wait, we should return
- -EINTR. */
- if (signalled ()) {
- status = -EINTR;
- break;
- }
- } while (1);
+in_grace_period:
+ /*
+ * The server has rebooted and appears to be in the grace
+ * period during which locks are only allowed to be
+ * reclaimed.
+ * We can only back off and try again later.
+ */
+ status = nlm_wait_on_grace(&host->h_gracewait);
+ } while (status == 0);
return status;
}
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 87d17b6e429b..70c8fd128376 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -128,6 +128,7 @@ nfs_direct_read_seg(struct inode *inode, struct file *file,
.inode = inode,
.args = {
.fh = NFS_FH(inode),
+ .lockowner = current->files,
},
.res = {
.fattr = &rdata.fattr,
@@ -258,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,
@@ -335,8 +337,7 @@ retry:
VERF_SIZE) != 0)
goto sync_retry;
}
- nfs_end_data_update(inode);
- NFS_FLAGS(inode) |= NFS_INO_INVALID_DATA;
+ nfs_end_data_update_defer(inode);
return tot_bytes;
@@ -395,10 +396,6 @@ nfs_direct_write(struct inode *inode, struct file *file,
if (result < size)
break;
}
- /* Zap the page cache if we managed to write */
- if (tot_bytes > 0)
- invalidate_remote_inode(inode);
-
return tot_bytes;
}
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 2a3cc1f63c0f..54fa2c0799ca 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -1012,6 +1012,8 @@ void nfs_begin_data_update(struct inode *inode)
* nfs_end_data_update
* @inode - pointer to inode
* Declare end of the operations that will update file data
+ * This will mark the inode as immediately needing revalidation
+ * of its attribute cache.
*/
void nfs_end_data_update(struct inode *inode)
{
@@ -1027,6 +1029,27 @@ void nfs_end_data_update(struct inode *inode)
}
/**
+ * nfs_end_data_update_defer
+ * @inode - pointer to inode
+ * Declare end of the operations that will update file data
+ * This will defer marking the inode as needing revalidation
+ * unless there are no other pending updates.
+ */
+void nfs_end_data_update_defer(struct inode *inode)
+{
+ struct nfs_inode *nfsi = NFS_I(inode);
+
+ if (atomic_dec_and_test(&nfsi->data_updates)) {
+ /* Mark the attribute cache for revalidation */
+ nfsi->flags |= NFS_INO_INVALID_ATTR;
+ /* Directories and symlinks: invalidate page cache too */
+ if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
+ nfsi->flags |= NFS_INO_INVALID_DATA;
+ nfsi->cache_change_attribute ++;
+ }
+}
+
+/**
* nfs_refresh_inode - verify consistency of the inode attribute cache
* @inode - pointer to inode
* @fattr - updated attributes
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index 138afa28c742..61f5e8105392 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -231,7 +231,7 @@ nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
static int
nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
{
- struct iovec *iov = req->rq_rvec;
+ struct iovec *iov = req->rq_rcv_buf.head;
int status, count, recvd, hdrlen;
if ((status = ntohl(*p++)))
@@ -250,7 +250,7 @@ nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
}
- recvd = req->rq_received - hdrlen;
+ recvd = req->rq_rcv_buf.len - hdrlen;
if (count > recvd) {
printk(KERN_WARNING "NFS: server cheating in read reply: "
"count %d > recvd %d\n", count, recvd);
@@ -396,7 +396,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy)
}
pglen = rcvbuf->page_len;
- recvd = req->rq_received - hdrlen;
+ recvd = rcvbuf->len - hdrlen;
if (pglen > recvd)
pglen = recvd;
page = rcvbuf->pages;
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 5f3443baee69..c79c0a9abf20 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -729,11 +729,10 @@ nfs3_read_done(struct rpc_task *task)
}
static void
-nfs3_proc_read_setup(struct nfs_read_data *data, unsigned int count)
+nfs3_proc_read_setup(struct nfs_read_data *data)
{
struct rpc_task *task = &data->task;
struct inode *inode = data->inode;
- struct nfs_page *req;
int flags;
struct rpc_message msg = {
.rpc_proc = &nfs3_procedures[NFS3PROC_READ],
@@ -741,27 +740,13 @@ nfs3_proc_read_setup(struct nfs_read_data *data, unsigned int count)
.rpc_resp = &data->res,
.rpc_cred = data->cred,
};
-
- 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.pages = data->pagevec;
- data->args.count = count;
- data->res.fattr = &data->fattr;
- data->res.count = count;
- data->res.eof = 0;
-
+
/* N.B. Do we need to test? Never called for swapfile inode */
flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0);
/* Finalize the task. */
rpc_init_task(task, NFS_CLIENT(inode), nfs3_read_done, flags);
- task->tk_calldata = data;
- /* Release requests */
- task->tk_release = nfs_readdata_release;
-
- rpc_call_setup(&data->task, &msg, 0);
+ rpc_call_setup(task, &msg, 0);
}
static void
@@ -778,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 = {
@@ -799,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
@@ -837,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;
@@ -849,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);
}
/*
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index fdc4bcafd007..98de0230ced2 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -515,7 +515,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
}
pglen = rcvbuf->page_len;
- recvd = req->rq_received - hdrlen;
+ recvd = rcvbuf->len - hdrlen;
if (pglen > recvd)
pglen = recvd;
page = rcvbuf->pages;
@@ -758,7 +758,7 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
static int
nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
{
- struct iovec *iov = req->rq_rvec;
+ struct iovec *iov = req->rq_rcv_buf.head;
int status, count, ocount, recvd, hdrlen;
status = ntohl(*p++);
@@ -789,7 +789,7 @@ nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
}
- recvd = req->rq_received - hdrlen;
+ recvd = req->rq_rcv_buf.len - hdrlen;
if (count > recvd) {
printk(KERN_WARNING "NFS: server cheating in read reply: "
"count %d > recvd %d\n", count, recvd);
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 9efe346181bc..6060f32d751d 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -51,10 +51,7 @@
#define NFS4_POLL_RETRY_TIME (15*HZ)
-#define GET_OP(cp,name) &cp->ops[cp->req_nops].u.name
-#define OPNUM(cp) cp->ops[cp->req_nops].opnum
-
-static int nfs4_proc_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
+static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
static int nfs4_async_handle_error(struct rpc_task *, struct nfs_server *);
extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);
extern struct rpc_procinfo nfs4_procedures[];
@@ -72,102 +69,10 @@ static inline int nfs4_map_errors(int err)
return err;
}
-static void
-nfs4_setup_compound(struct nfs4_compound *cp, struct nfs4_op *ops,
- struct nfs_server *server, char *tag)
-{
- memset(cp, 0, sizeof(*cp));
- cp->ops = ops;
- cp->server = server;
-}
-
-static void
-nfs4_setup_access(struct nfs4_compound *cp, u32 req_access, u32 *resp_supported, u32 *resp_access)
-{
- struct nfs4_access *access = GET_OP(cp, access);
-
- access->ac_req_access = req_access;
- access->ac_resp_supported = resp_supported;
- access->ac_resp_access = resp_access;
-
- OPNUM(cp) = OP_ACCESS;
- cp->req_nops++;
-}
-
-static void
-nfs4_setup_create_dir(struct nfs4_compound *cp, struct qstr *name,
- struct iattr *sattr, struct nfs4_change_info *info)
-{
- struct nfs4_create *create = GET_OP(cp, create);
-
- create->cr_ftype = NF4DIR;
- create->cr_namelen = name->len;
- create->cr_name = name->name;
- create->cr_attrs = sattr;
- create->cr_cinfo = info;
-
- OPNUM(cp) = OP_CREATE;
- cp->req_nops++;
-}
-
-static void
-nfs4_setup_create_symlink(struct nfs4_compound *cp, struct qstr *name,
- struct qstr *linktext, struct iattr *sattr,
- struct nfs4_change_info *info)
-{
- struct nfs4_create *create = GET_OP(cp, create);
-
- create->cr_ftype = NF4LNK;
- create->cr_textlen = linktext->len;
- create->cr_text = linktext->name;
- create->cr_namelen = name->len;
- create->cr_name = name->name;
- create->cr_attrs = sattr;
- create->cr_cinfo = info;
-
- OPNUM(cp) = OP_CREATE;
- cp->req_nops++;
-}
-
-static void
-nfs4_setup_create_special(struct nfs4_compound *cp, struct qstr *name,
- dev_t dev, struct iattr *sattr,
- struct nfs4_change_info *info)
-{
- int mode = sattr->ia_mode;
- struct nfs4_create *create = GET_OP(cp, create);
-
- BUG_ON(!(sattr->ia_valid & ATTR_MODE));
- BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode));
-
- if (S_ISFIFO(mode))
- create->cr_ftype = NF4FIFO;
- else if (S_ISBLK(mode)) {
- create->cr_ftype = NF4BLK;
- create->cr_specdata1 = MAJOR(dev);
- create->cr_specdata2 = MINOR(dev);
- }
- else if (S_ISCHR(mode)) {
- create->cr_ftype = NF4CHR;
- create->cr_specdata1 = MAJOR(dev);
- create->cr_specdata2 = MINOR(dev);
- }
- else
- create->cr_ftype = NF4SOCK;
-
- create->cr_namelen = name->len;
- create->cr_name = name->name;
- create->cr_attrs = sattr;
- create->cr_cinfo = info;
-
- OPNUM(cp) = OP_CREATE;
- cp->req_nops++;
-}
-
/*
* This is our standard bitmap for GETATTR requests.
*/
-u32 nfs4_fattr_bitmap[2] = {
+const u32 nfs4_fattr_bitmap[2] = {
FATTR4_WORD0_TYPE
| FATTR4_WORD0_CHANGE
| FATTR4_WORD0_SIZE
@@ -184,7 +89,7 @@ u32 nfs4_fattr_bitmap[2] = {
| FATTR4_WORD1_TIME_MODIFY
};
-u32 nfs4_statfs_bitmap[2] = {
+const u32 nfs4_statfs_bitmap[2] = {
FATTR4_WORD0_FILES_AVAIL
| FATTR4_WORD0_FILES_FREE
| FATTR4_WORD0_FILES_TOTAL,
@@ -199,121 +104,28 @@ u32 nfs4_pathconf_bitmap[2] = {
0
};
-static inline void
-__nfs4_setup_getattr(struct nfs4_compound *cp, u32 *bitmap,
- struct nfs_fattr *fattr,
- struct nfs_fsstat *fsstat,
- struct nfs_pathconf *pathconf)
-{
- struct nfs4_getattr *getattr = GET_OP(cp, getattr);
-
- getattr->gt_bmval = bitmap;
- getattr->gt_attrs = fattr;
- getattr->gt_fsstat = fsstat;
- getattr->gt_pathconf = pathconf;
-
- OPNUM(cp) = OP_GETATTR;
- cp->req_nops++;
-}
-
-static void
-nfs4_setup_getattr(struct nfs4_compound *cp,
- struct nfs_fattr *fattr)
-{
- __nfs4_setup_getattr(cp, nfs4_fattr_bitmap, fattr,
- NULL, NULL);
-}
-
-static void
-nfs4_setup_statfs(struct nfs4_compound *cp,
- struct nfs_fsstat *fsstat)
-{
- __nfs4_setup_getattr(cp, nfs4_statfs_bitmap,
- NULL, fsstat, NULL);
-}
-
-static void
-nfs4_setup_pathconf(struct nfs4_compound *cp,
- struct nfs_pathconf *pathconf)
-{
- __nfs4_setup_getattr(cp, nfs4_pathconf_bitmap,
- NULL, NULL, pathconf);
-}
-
-static void
-nfs4_setup_getfh(struct nfs4_compound *cp, struct nfs_fh *fhandle)
-{
- struct nfs4_getfh *getfh = GET_OP(cp, getfh);
-
- getfh->gf_fhandle = fhandle;
-
- OPNUM(cp) = OP_GETFH;
- cp->req_nops++;
-}
-
-static void
-nfs4_setup_link(struct nfs4_compound *cp, struct qstr *name,
- struct nfs4_change_info *info)
-{
- struct nfs4_link *link = GET_OP(cp, link);
-
- link->ln_namelen = name->len;
- link->ln_name = name->name;
- link->ln_cinfo = info;
-
- OPNUM(cp) = OP_LINK;
- cp->req_nops++;
-}
-
-static void
-nfs4_setup_lookup(struct nfs4_compound *cp, struct qstr *q)
-{
- struct nfs4_lookup *lookup = GET_OP(cp, lookup);
-
- lookup->lo_name = q;
-
- OPNUM(cp) = OP_LOOKUP;
- cp->req_nops++;
-}
-
-static void
-nfs4_setup_putfh(struct nfs4_compound *cp, struct nfs_fh *fhandle)
-{
- struct nfs4_putfh *putfh = GET_OP(cp, putfh);
-
- putfh->pf_fhandle = fhandle;
-
- OPNUM(cp) = OP_PUTFH;
- cp->req_nops++;
-}
-
-static void
-nfs4_setup_putrootfh(struct nfs4_compound *cp)
-{
- OPNUM(cp) = OP_PUTROOTFH;
- cp->req_nops++;
-}
+const u32 nfs4_fsinfo_bitmap[2] = { FATTR4_WORD0_MAXFILESIZE
+ | FATTR4_WORD0_MAXREAD
+ | FATTR4_WORD0_MAXWRITE
+ | FATTR4_WORD0_LEASE_TIME,
+ 0
+};
-static void
-nfs4_setup_readdir(struct nfs4_compound *cp, u64 cookie, u32 *verifier,
- struct page **pages, unsigned int bufsize, struct dentry *dentry)
+static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry,
+ struct nfs4_readdir_arg *readdir)
{
u32 *start, *p;
- struct nfs4_readdir *readdir = GET_OP(cp, readdir);
-
- BUG_ON(bufsize < 80);
- readdir->rd_cookie = (cookie > 2) ? cookie : 0;
- memcpy(&readdir->rd_req_verifier, verifier, sizeof(readdir->rd_req_verifier));
- readdir->rd_count = bufsize;
- readdir->rd_bmval[0] = FATTR4_WORD0_FILEID;
- readdir->rd_bmval[1] = 0;
- readdir->rd_pages = pages;
- readdir->rd_pgbase = 0;
-
- OPNUM(cp) = OP_READDIR;
- cp->req_nops++;
- if (cookie >= 2)
+ BUG_ON(readdir->count < 80);
+ if (cookie > 2) {
+ readdir->cookie = (cookie > 2) ? cookie : 0;
+ memcpy(&readdir->verifier, verifier, sizeof(readdir->verifier));
+ return;
+ }
+
+ readdir->cookie = 0;
+ memset(&readdir->verifier, 0, sizeof(readdir->verifier));
+ if (cookie == 2)
return;
/*
@@ -323,7 +135,7 @@ nfs4_setup_readdir(struct nfs4_compound *cp, u64 cookie, u32 *verifier,
* when talking to the server, we always send cookie 0
* instead of 1 or 2.
*/
- start = p = (u32 *)kmap_atomic(*pages, KM_USER0);
+ start = p = (u32 *)kmap_atomic(*readdir->pages, KM_USER0);
if (cookie == 0) {
*p++ = xdr_one; /* next */
@@ -335,7 +147,7 @@ nfs4_setup_readdir(struct nfs4_compound *cp, u64 cookie, u32 *verifier,
*p++ = xdr_one; /* bitmap length */
*p++ = htonl(FATTR4_WORD0_FILEID); /* bitmap */
*p++ = htonl(8); /* attribute buffer length */
- p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_inode));
+ p = xdr_encode_hyper(p, dentry->d_inode->i_ino);
}
*p++ = xdr_one; /* next */
@@ -347,70 +159,14 @@ nfs4_setup_readdir(struct nfs4_compound *cp, u64 cookie, u32 *verifier,
*p++ = xdr_one; /* bitmap length */
*p++ = htonl(FATTR4_WORD0_FILEID); /* bitmap */
*p++ = htonl(8); /* attribute buffer length */
- p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_parent->d_inode));
+ p = xdr_encode_hyper(p, dentry->d_parent->d_inode->i_ino);
- readdir->rd_pgbase = (char *)p - (char *)start;
- readdir->rd_count -= readdir->rd_pgbase;
+ readdir->pgbase = (char *)p - (char *)start;
+ readdir->count -= readdir->pgbase;
kunmap_atomic(start, KM_USER0);
}
static void
-nfs4_setup_readlink(struct nfs4_compound *cp, int count, struct page **pages)
-{
- struct nfs4_readlink *readlink = GET_OP(cp, readlink);
-
- readlink->rl_count = count;
- readlink->rl_pages = pages;
-
- OPNUM(cp) = OP_READLINK;
- cp->req_nops++;
-}
-
-static void
-nfs4_setup_remove(struct nfs4_compound *cp, struct qstr *name, struct nfs4_change_info *cinfo)
-{
- struct nfs4_remove *remove = GET_OP(cp, remove);
-
- remove->rm_namelen = name->len;
- remove->rm_name = name->name;
- remove->rm_cinfo = cinfo;
-
- OPNUM(cp) = OP_REMOVE;
- cp->req_nops++;
-}
-
-static void
-nfs4_setup_rename(struct nfs4_compound *cp, struct qstr *old, struct qstr *new,
- struct nfs4_change_info *old_cinfo, struct nfs4_change_info *new_cinfo)
-{
- struct nfs4_rename *rename = GET_OP(cp, rename);
-
- rename->rn_oldnamelen = old->len;
- rename->rn_oldname = old->name;
- rename->rn_newnamelen = new->len;
- rename->rn_newname = new->name;
- rename->rn_src_cinfo = old_cinfo;
- rename->rn_dst_cinfo = new_cinfo;
-
- OPNUM(cp) = OP_RENAME;
- cp->req_nops++;
-}
-
-static void
-nfs4_setup_restorefh(struct nfs4_compound *cp)
-{
- OPNUM(cp) = OP_RESTOREFH;
- cp->req_nops++;
-}
-
-static void
-nfs4_setup_savefh(struct nfs4_compound *cp)
-{
- OPNUM(cp) = OP_SAVEFH;
- cp->req_nops++;
-}
-
-static void
renew_lease(struct nfs_server *server, unsigned long timestamp)
{
struct nfs4_client *clp = server->nfs4_state;
@@ -420,58 +176,12 @@ renew_lease(struct nfs_server *server, unsigned long timestamp)
spin_unlock(&clp->cl_lock);
}
-static inline void
-process_lease(struct nfs4_compound *cp)
+static void update_changeattr(struct inode *inode, struct nfs4_change_info *cinfo)
{
- /*
- * Generic lease processing: If this operation contains a
- * lease-renewing operation, and it succeeded, update the RENEW time
- * in the superblock. Instead of the current time, we use the time
- * when the request was sent out. (All we know is that the lease was
- * renewed sometime between then and now, and we have to assume the
- * worst case.)
- *
- * Notes:
- * (1) renewd doesn't acquire the spinlock when messing with
- * server->last_renewal; this is OK since rpciod always runs
- * under the BKL.
- * (2) cp->timestamp was set at the end of XDR encode.
- */
- if (!cp->renew_index)
- return;
- if (!cp->toplevel_status || cp->resp_nops > cp->renew_index)
- renew_lease(cp->server, cp->timestamp);
-}
-
-static int
-nfs4_call_compound(struct nfs4_compound *cp, struct rpc_cred *cred, int flags)
-{
- int status;
- struct rpc_message msg = {
- .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMPOUND],
- .rpc_argp = cp,
- .rpc_resp = cp,
- .rpc_cred = cred,
- };
-
- status = rpc_call_sync(cp->server->client, &msg, flags);
- if (!status)
- process_lease(cp);
-
- return status;
-}
+ struct nfs_inode *nfsi = NFS_I(inode);
-static inline void
-process_cinfo(struct nfs4_change_info *info, struct nfs_fattr *fattr)
-{
- BUG_ON((fattr->valid & NFS_ATTR_FATTR) == 0);
- BUG_ON((fattr->valid & NFS_ATTR_FATTR_V4) == 0);
-
- if (fattr->change_attr == info->after) {
- fattr->pre_change_attr = info->before;
- fattr->valid |= NFS_ATTR_PRE_CHANGE;
- fattr->timestamp = jiffies;
- }
+ if (cinfo->before == nfsi->change_attr && cinfo->atomic)
+ nfsi->change_attr = cinfo->after;
}
/*
@@ -487,12 +197,6 @@ nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state)
struct nfs_fattr fattr = {
.valid = 0,
};
- struct nfs4_change_info d_cinfo;
- struct nfs4_getattr f_getattr = {
- .gt_bmval = nfs4_fattr_bitmap,
- .gt_attrs = &fattr,
- };
-
struct nfs_open_reclaimargs o_arg = {
.fh = NFS_FH(inode),
.seqid = sp->so_seqid,
@@ -500,11 +204,10 @@ nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state)
.share_access = state->state,
.clientid = server->nfs4_state->cl_clientid,
.claim = NFS4_OPEN_CLAIM_PREVIOUS,
- .f_getattr = &f_getattr,
+ .bitmask = server->attr_bitmask,
};
struct nfs_openres o_res = {
- .cinfo = &d_cinfo,
- .f_getattr = &f_getattr,
+ .f_attr = &fattr,
.server = server, /* Grrr */
};
struct rpc_message msg = {
@@ -534,36 +237,21 @@ nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *satt
struct nfs4_state *state = NULL;
struct nfs_server *server = NFS_SERVER(dir);
struct inode *inode = NULL;
- struct nfs4_change_info d_cinfo;
int status;
- struct nfs_fattr d_attr = {
- .valid = 0,
- };
struct nfs_fattr f_attr = {
.valid = 0,
};
- struct nfs4_getattr f_getattr = {
- .gt_bmval = nfs4_fattr_bitmap,
- .gt_attrs = &f_attr,
- };
- struct nfs4_getattr d_getattr = {
- .gt_bmval = nfs4_fattr_bitmap,
- .gt_attrs = &d_attr,
- };
struct nfs_openargs o_arg = {
.fh = NFS_FH(dir),
.share_access = flags & (FMODE_READ|FMODE_WRITE),
.opentype = (flags & O_CREAT) ? NFS4_OPEN_CREATE : NFS4_OPEN_NOCREATE,
.createmode = (flags & O_EXCL) ? NFS4_CREATE_EXCLUSIVE : NFS4_CREATE_UNCHECKED,
.name = name,
- .f_getattr = &f_getattr,
- .d_getattr = &d_getattr,
.server = server,
+ .bitmask = server->attr_bitmask,
};
struct nfs_openres o_res = {
- .cinfo = &d_cinfo,
- .f_getattr = &f_getattr,
- .d_getattr = &d_getattr,
+ .f_attr = &f_attr,
.server = server,
};
struct rpc_message msg = {
@@ -596,8 +284,7 @@ retry:
nfs4_increment_seqid(status, sp);
if (status)
goto out_up;
- process_cinfo(&d_cinfo, &d_attr);
- nfs_refresh_inode(dir, &d_attr);
+ update_changeattr(dir, &o_res.cinfo);
status = -ENOMEM;
inode = nfs_fhget(dir->i_sb, &o_res.fh, &f_attr);
@@ -679,18 +366,14 @@ nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr,
struct nfs_fh *fhandle, struct iattr *sattr,
struct nfs4_state *state)
{
- struct nfs4_getattr getattr = {
- .gt_bmval = nfs4_fattr_bitmap,
- .gt_attrs = fattr,
- };
struct nfs_setattrargs arg = {
.fh = fhandle,
.iap = sattr,
- .attr = &getattr,
.server = server,
+ .bitmask = server->attr_bitmask,
};
struct nfs_setattrres res = {
- .attr = &getattr,
+ .fattr = fattr,
.server = server,
};
struct rpc_message msg = {
@@ -834,30 +517,85 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags)
return 0;
}
-static int
-nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
- struct nfs_fsinfo *info)
+
+static int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
+{
+ struct nfs4_server_caps_res res = {};
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SERVER_CAPS],
+ .rpc_argp = fhandle,
+ .rpc_resp = &res,
+ };
+ int status;
+
+ status = rpc_call_sync(server->client, &msg, 0);
+ if (status == 0) {
+ memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask));
+ if (res.attr_bitmask[0] & FATTR4_WORD0_ACL)
+ server->caps |= NFS_CAP_ACLS;
+ if (res.has_links != 0)
+ server->caps |= NFS_CAP_HARDLINKS;
+ if (res.has_symlinks != 0)
+ server->caps |= NFS_CAP_SYMLINKS;
+ server->acl_bitmask = res.acl_bitmask;
+ }
+ return status;
+}
+
+static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_fsinfo *info)
+{
+ struct nfs_fattr * fattr = info->fattr;
+ struct nfs4_lookup_root_arg args = {
+ .bitmask = nfs4_fattr_bitmap,
+ };
+ struct nfs4_lookup_res res = {
+ .server = server,
+ .fattr = fattr,
+ .fh = fhandle,
+ };
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP_ROOT],
+ .rpc_argp = &args,
+ .rpc_resp = &res,
+ };
+ fattr->valid = 0;
+ return rpc_call_sync(server->client, &msg, 0);
+}
+
+static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_fsinfo *info)
{
- struct nfs4_compound compound;
- struct nfs4_op ops[4];
struct nfs_fattr * fattr = info->fattr;
unsigned char * p;
struct qstr q;
- int status;
+ struct nfs4_lookup_arg args = {
+ .dir_fh = fhandle,
+ .name = &q,
+ .bitmask = nfs4_fattr_bitmap,
+ };
+ struct nfs4_lookup_res res = {
+ .server = server,
+ .fattr = fattr,
+ .fh = fhandle,
+ };
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP],
+ .rpc_argp = &args,
+ .rpc_resp = &res,
+ };
+ int status;
/*
* Now we do a separate LOOKUP for each component of the mount path.
* The LOOKUPs are done separately so that we can conveniently
* catch an ERR_WRONGSEC if it occurs along the way...
*/
- p = server->mnt_path;
- fattr->valid = 0;
- nfs4_setup_compound(&compound, ops, server, "getrootfh");
- nfs4_setup_putrootfh(&compound);
- nfs4_setup_getattr(&compound, fattr);
- nfs4_setup_getfh(&compound, fhandle);
- if ((status = nfs4_call_compound(&compound, NULL, 0)))
+ status = nfs4_lookup_root(server, fhandle, info);
+ if (status)
goto out;
+
+ p = server->mnt_path;
for (;;) {
while (*p == '/')
p++;
@@ -869,12 +607,7 @@ nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
q.len = p - q.name;
fattr->valid = 0;
- nfs4_setup_compound(&compound, ops, server, "mount");
- nfs4_setup_putfh(&compound, fhandle);
- nfs4_setup_lookup(&compound, &q);
- nfs4_setup_getattr(&compound, fattr);
- nfs4_setup_getfh(&compound, fhandle);
- status = nfs4_call_compound(&compound, NULL, 0);
+ status = rpc_call_sync(server->client, &msg, 0);
if (!status)
continue;
if (status == -ENOENT) {
@@ -883,24 +616,34 @@ nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
}
break;
}
+ if (status == 0)
+ status = nfs4_server_capabilities(server, fhandle);
+ if (status == 0)
+ status = nfs4_do_fsinfo(server, fhandle, info);
out:
- if (status)
- return nfs4_map_errors(status);
- return nfs4_proc_fsinfo(server, fhandle, info);
+ return nfs4_map_errors(status);
}
-static int
-nfs4_proc_getattr(struct inode *inode, struct nfs_fattr *fattr)
+static int nfs4_proc_getattr(struct inode *inode, struct nfs_fattr *fattr)
{
- struct nfs4_compound compound;
- struct nfs4_op ops[2];
-
+ struct nfs_server *server = NFS_SERVER(inode);
+ struct nfs4_getattr_arg args = {
+ .fh = NFS_FH(inode),
+ .bitmask = server->attr_bitmask,
+ };
+ struct nfs4_getattr_res res = {
+ .fattr = fattr,
+ .server = server,
+ };
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETATTR],
+ .rpc_argp = &args,
+ .rpc_resp = &res,
+ };
+
fattr->valid = 0;
- nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "getattr");
- nfs4_setup_putfh(&compound, NFS_FH(inode));
- nfs4_setup_getattr(&compound, fattr);
- return nfs4_map_errors(nfs4_call_compound(&compound, NULL, 0));
+ return nfs4_map_errors(rpc_call_sync(NFS_CLIENT(inode), &msg, 0));
}
/*
@@ -962,75 +705,72 @@ out:
return status;
}
-static int
-nfs4_proc_lookup(struct inode *dir, struct qstr *name,
- struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+static int nfs4_proc_lookup(struct inode *dir, struct qstr *name,
+ struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
- struct nfs4_compound compound;
- struct nfs4_op ops[5];
- struct nfs_fattr dir_attr;
- int status;
-
- dir_attr.valid = 0;
+ int status;
+ struct nfs_server *server = NFS_SERVER(dir);
+ struct nfs4_lookup_arg args = {
+ .bitmask = server->attr_bitmask,
+ .dir_fh = NFS_FH(dir),
+ .name = name,
+ };
+ struct nfs4_lookup_res res = {
+ .server = server,
+ .fattr = fattr,
+ .fh = fhandle,
+ };
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP],
+ .rpc_argp = &args,
+ .rpc_resp = &res,
+ };
+
fattr->valid = 0;
dprintk("NFS call lookup %s\n", name->name);
- nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "lookup");
- nfs4_setup_putfh(&compound, NFS_FH(dir));
- nfs4_setup_getattr(&compound, &dir_attr);
- nfs4_setup_lookup(&compound, name);
- nfs4_setup_getattr(&compound, fattr);
- nfs4_setup_getfh(&compound, fhandle);
- status = nfs4_call_compound(&compound, NULL, 0);
+ status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
dprintk("NFS reply lookup: %d\n", status);
-
- if (status >= 0)
- status = nfs_refresh_inode(dir, &dir_attr);
return nfs4_map_errors(status);
}
-static int
-nfs4_proc_access(struct inode *inode, struct rpc_cred *cred, int mode)
+static int nfs4_proc_access(struct inode *inode, struct rpc_cred *cred, int mode)
{
- struct nfs4_compound compound;
- struct nfs4_op ops[3];
- struct nfs_fattr fattr;
- u32 req_access = 0, resp_supported, resp_access;
int status;
-
- fattr.valid = 0;
+ struct nfs4_accessargs args = {
+ .fh = NFS_FH(inode),
+ };
+ struct nfs4_accessres res = { 0 };
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS],
+ .rpc_argp = &args,
+ .rpc_resp = &res,
+ .rpc_cred = cred,
+ };
/*
* Determine which access bits we want to ask for...
*/
if (mode & MAY_READ)
- req_access |= NFS4_ACCESS_READ;
+ args.access |= NFS4_ACCESS_READ;
if (S_ISDIR(inode->i_mode)) {
if (mode & MAY_WRITE)
- req_access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE;
+ args.access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE;
if (mode & MAY_EXEC)
- req_access |= NFS4_ACCESS_LOOKUP;
+ args.access |= NFS4_ACCESS_LOOKUP;
}
else {
if (mode & MAY_WRITE)
- req_access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND;
+ args.access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND;
if (mode & MAY_EXEC)
- req_access |= NFS4_ACCESS_EXECUTE;
+ args.access |= NFS4_ACCESS_EXECUTE;
}
-
- nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "access");
- nfs4_setup_putfh(&compound, NFS_FH(inode));
- nfs4_setup_getattr(&compound, &fattr);
- nfs4_setup_access(&compound, req_access, &resp_supported, &resp_access);
- status = nfs4_call_compound(&compound, cred, 0);
- nfs_refresh_inode(inode, &fattr);
-
+ status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
if (!status) {
- if (req_access != resp_supported) {
+ if (args.access != res.supported) {
printk(KERN_NOTICE "NFS: server didn't support all access bits!\n");
status = -ENOTSUPP;
- }
- else if (req_access != resp_access)
+ } else if ((args.access & res.access) != args.access)
status = -EACCES;
}
return nfs4_map_errors(status);
@@ -1060,16 +800,20 @@ nfs4_proc_access(struct inode *inode, struct rpc_cred *cred, int mode)
* Both of these changes to the XDR layer would in fact be quite
* minor, but I decided to leave them for a subsequent patch.
*/
-static int
-nfs4_proc_readlink(struct inode *inode, struct page *page)
+static int nfs4_proc_readlink(struct inode *inode, struct page *page)
{
- struct nfs4_compound compound;
- struct nfs4_op ops[2];
+ struct nfs4_readlink args = {
+ .fh = NFS_FH(inode),
+ .count = PAGE_CACHE_SIZE,
+ .pages = &page,
+ };
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READLINK],
+ .rpc_argp = &args,
+ .rpc_resp = NULL,
+ };
- nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "readlink");
- nfs4_setup_putfh(&compound, NFS_FH(inode));
- nfs4_setup_readlink(&compound, PAGE_CACHE_SIZE, &page);
- return nfs4_map_errors(nfs4_call_compound(&compound, NULL, 0));
+ return nfs4_map_errors(rpc_call_sync(NFS_CLIENT(inode), &msg, 0));
}
static int
@@ -1096,10 +840,10 @@ nfs4_proc_read(struct nfs_read_data *rdata, struct file *filp)
if (filp) {
struct nfs4_state *state;
state = (struct nfs4_state *)filp->private_data;
- nfs4_copy_stateid(&rdata->args.stateid, state, rdata->lockowner);
+ rdata->args.state = state;
msg.rpc_cred = state->owner->so_cred;
} else {
- memcpy(&rdata->args.stateid, &zero_stateid, sizeof(rdata->args.stateid));
+ rdata->args.state = NULL;
msg.rpc_cred = NFS_I(inode)->mm_cred;
}
@@ -1134,10 +878,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 +910,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);
@@ -1226,301 +965,318 @@ nfs4_proc_create(struct inode *dir, struct qstr *name, struct iattr *sattr,
return inode;
}
-static int
-nfs4_proc_remove(struct inode *dir, struct qstr *name)
+static int nfs4_proc_remove(struct inode *dir, struct qstr *name)
{
- struct nfs4_compound compound;
- struct nfs4_op ops[3];
- struct nfs4_change_info dir_cinfo;
- struct nfs_fattr dir_attr;
+ struct nfs4_remove_arg args = {
+ .fh = NFS_FH(dir),
+ .name = name,
+ };
+ struct nfs4_change_info res;
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE],
+ .rpc_argp = &args,
+ .rpc_resp = &res,
+ };
int status;
- dir_attr.valid = 0;
- nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "remove");
- nfs4_setup_putfh(&compound, NFS_FH(dir));
- nfs4_setup_remove(&compound, name, &dir_cinfo);
- nfs4_setup_getattr(&compound, &dir_attr);
- status = nfs4_call_compound(&compound, NULL, 0);
-
- if (!status) {
- process_cinfo(&dir_cinfo, &dir_attr);
- nfs_refresh_inode(dir, &dir_attr);
- }
+ status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+ if (status == 0)
+ update_changeattr(dir, &res);
return nfs4_map_errors(status);
}
struct unlink_desc {
- struct nfs4_compound compound;
- struct nfs4_op ops[3];
- struct nfs4_change_info cinfo;
- struct nfs_fattr attrs;
+ struct nfs4_remove_arg args;
+ struct nfs4_change_info res;
};
-static int
-nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name)
+static int nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir,
+ struct qstr *name)
{
- struct unlink_desc * up;
- struct nfs4_compound * cp;
+ struct unlink_desc *up;
up = (struct unlink_desc *) kmalloc(sizeof(*up), GFP_KERNEL);
if (!up)
return -ENOMEM;
- cp = &up->compound;
- nfs4_setup_compound(cp, up->ops, NFS_SERVER(dir->d_inode), "unlink_setup");
- nfs4_setup_putfh(cp, NFS_FH(dir->d_inode));
- nfs4_setup_remove(cp, name, &up->cinfo);
- nfs4_setup_getattr(cp, &up->attrs);
+ up->args.fh = NFS_FH(dir->d_inode);
+ up->args.name = name;
- msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMPOUND];
- msg->rpc_argp = cp;
- msg->rpc_resp = cp;
+ msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
+ msg->rpc_argp = &up->args;
+ msg->rpc_resp = &up->res;
return 0;
}
-static int
-nfs4_proc_unlink_done(struct dentry *dir, struct rpc_task *task)
+static int nfs4_proc_unlink_done(struct dentry *dir, struct rpc_task *task)
{
struct rpc_message *msg = &task->tk_msg;
struct unlink_desc *up;
- if (msg->rpc_argp) {
- up = (struct unlink_desc *) msg->rpc_argp;
- process_lease(&up->compound);
- process_cinfo(&up->cinfo, &up->attrs);
- nfs_refresh_inode(dir->d_inode, &up->attrs);
+ if (msg->rpc_resp != NULL) {
+ up = container_of(msg->rpc_resp, struct unlink_desc, res);
+ update_changeattr(dir->d_inode, &up->res);
kfree(up);
+ msg->rpc_resp = NULL;
msg->rpc_argp = NULL;
}
return 0;
}
-static int
-nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
- struct inode *new_dir, struct qstr *new_name)
+static int nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
+ struct inode *new_dir, struct qstr *new_name)
{
- struct nfs4_compound compound;
- struct nfs4_op ops[7];
- struct nfs4_change_info old_cinfo, new_cinfo;
- struct nfs_fattr old_dir_attr, new_dir_attr;
+ struct nfs4_rename_arg arg = {
+ .old_dir = NFS_FH(old_dir),
+ .new_dir = NFS_FH(new_dir),
+ .old_name = old_name,
+ .new_name = new_name,
+ };
+ struct nfs4_rename_res res = { };
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME],
+ .rpc_argp = &arg,
+ .rpc_resp = &res,
+ };
int status;
-
- old_dir_attr.valid = 0;
- new_dir_attr.valid = 0;
- nfs4_setup_compound(&compound, ops, NFS_SERVER(old_dir), "rename");
- nfs4_setup_putfh(&compound, NFS_FH(old_dir));
- nfs4_setup_savefh(&compound);
- nfs4_setup_putfh(&compound, NFS_FH(new_dir));
- nfs4_setup_rename(&compound, old_name, new_name, &old_cinfo, &new_cinfo);
- nfs4_setup_getattr(&compound, &new_dir_attr);
- nfs4_setup_restorefh(&compound);
- nfs4_setup_getattr(&compound, &old_dir_attr);
- status = nfs4_call_compound(&compound, NULL, 0);
+ status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0);
if (!status) {
- process_cinfo(&old_cinfo, &old_dir_attr);
- process_cinfo(&new_cinfo, &new_dir_attr);
- nfs_refresh_inode(old_dir, &old_dir_attr);
- nfs_refresh_inode(new_dir, &new_dir_attr);
+ update_changeattr(old_dir, &res.old_cinfo);
+ update_changeattr(new_dir, &res.new_cinfo);
}
return nfs4_map_errors(status);
}
-static int
-nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
+static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
{
- struct nfs4_compound compound;
- struct nfs4_op ops[7];
- struct nfs4_change_info dir_cinfo;
- struct nfs_fattr dir_attr, fattr;
+ struct nfs4_link_arg arg = {
+ .fh = NFS_FH(inode),
+ .dir_fh = NFS_FH(dir),
+ .name = name,
+ };
+ struct nfs4_change_info cinfo = { };
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK],
+ .rpc_argp = &arg,
+ .rpc_resp = &cinfo,
+ };
int status;
-
- dir_attr.valid = 0;
- fattr.valid = 0;
-
- nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "link");
- nfs4_setup_putfh(&compound, NFS_FH(inode));
- nfs4_setup_savefh(&compound);
- nfs4_setup_putfh(&compound, NFS_FH(dir));
- nfs4_setup_link(&compound, name, &dir_cinfo);
- nfs4_setup_getattr(&compound, &dir_attr);
- nfs4_setup_restorefh(&compound);
- nfs4_setup_getattr(&compound, &fattr);
- status = nfs4_call_compound(&compound, NULL, 0);
- if (!status) {
- process_cinfo(&dir_cinfo, &dir_attr);
- nfs_refresh_inode(dir, &dir_attr);
- nfs_refresh_inode(inode, &fattr);
- }
+ status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
+ if (!status)
+ update_changeattr(dir, &cinfo);
+
return nfs4_map_errors(status);
}
-static int
-nfs4_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path,
- struct iattr *sattr, struct nfs_fh *fhandle,
- struct nfs_fattr *fattr)
+static int nfs4_proc_symlink(struct inode *dir, struct qstr *name,
+ struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle,
+ struct nfs_fattr *fattr)
{
- struct nfs4_compound compound;
- struct nfs4_op ops[7];
- struct nfs_fattr dir_attr;
- struct nfs4_change_info dir_cinfo;
+ struct nfs_server *server = NFS_SERVER(dir);
+ struct nfs4_create_arg arg = {
+ .dir_fh = NFS_FH(dir),
+ .server = server,
+ .name = name,
+ .attrs = sattr,
+ .ftype = NF4LNK,
+ .bitmask = server->attr_bitmask,
+ };
+ struct nfs4_create_res res = {
+ .server = server,
+ .fh = fhandle,
+ .fattr = fattr,
+ };
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE],
+ .rpc_argp = &arg,
+ .rpc_resp = &res,
+ };
int status;
- dir_attr.valid = 0;
+ arg.u.symlink = path;
fattr->valid = 0;
- nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "symlink");
- nfs4_setup_putfh(&compound, NFS_FH(dir));
- nfs4_setup_savefh(&compound);
- nfs4_setup_create_symlink(&compound, name, path, sattr, &dir_cinfo);
- nfs4_setup_getattr(&compound, fattr);
- nfs4_setup_getfh(&compound, fhandle);
- nfs4_setup_restorefh(&compound);
- nfs4_setup_getattr(&compound, &dir_attr);
- status = nfs4_call_compound(&compound, NULL, 0);
-
- if (!status) {
- process_cinfo(&dir_cinfo, &dir_attr);
- nfs_refresh_inode(dir, &dir_attr);
- }
+ status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+ if (!status)
+ update_changeattr(dir, &res.dir_cinfo);
return nfs4_map_errors(status);
}
-static int
-nfs4_proc_mkdir(struct inode *dir, struct qstr *name, struct iattr *sattr,
- struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+static int nfs4_proc_mkdir(struct inode *dir, struct qstr *name,
+ struct iattr *sattr, struct nfs_fh *fhandle,
+ struct nfs_fattr *fattr)
{
- struct nfs4_compound compound;
- struct nfs4_op ops[7];
- struct nfs_fattr dir_attr;
- struct nfs4_change_info dir_cinfo;
+ struct nfs_server *server = NFS_SERVER(dir);
+ struct nfs4_create_arg arg = {
+ .dir_fh = NFS_FH(dir),
+ .server = server,
+ .name = name,
+ .attrs = sattr,
+ .ftype = NF4DIR,
+ .bitmask = server->attr_bitmask,
+ };
+ struct nfs4_create_res res = {
+ .server = server,
+ .fh = fhandle,
+ .fattr = fattr,
+ };
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE],
+ .rpc_argp = &arg,
+ .rpc_resp = &res,
+ };
int status;
- dir_attr.valid = 0;
fattr->valid = 0;
- nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "mkdir");
- nfs4_setup_putfh(&compound, NFS_FH(dir));
- nfs4_setup_savefh(&compound);
- nfs4_setup_create_dir(&compound, name, sattr, &dir_cinfo);
- nfs4_setup_getattr(&compound, fattr);
- nfs4_setup_getfh(&compound, fhandle);
- nfs4_setup_restorefh(&compound);
- nfs4_setup_getattr(&compound, &dir_attr);
- status = nfs4_call_compound(&compound, NULL, 0);
-
- if (!status) {
- process_cinfo(&dir_cinfo, &dir_attr);
- nfs_refresh_inode(dir, &dir_attr);
- }
+ status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+ if (!status)
+ update_changeattr(dir, &res.dir_cinfo);
return nfs4_map_errors(status);
}
-static int
-nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
+static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
u64 cookie, struct page *page, unsigned int count, int plus)
{
struct inode *dir = dentry->d_inode;
- struct nfs4_compound compound;
- struct nfs4_op ops[2];
+ struct nfs4_readdir_arg args = {
+ .fh = NFS_FH(dir),
+ .pages = &page,
+ .pgbase = 0,
+ .count = count,
+ };
+ struct nfs4_readdir_res res;
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READDIR],
+ .rpc_argp = &args,
+ .rpc_resp = &res,
+ .rpc_cred = cred,
+ };
int status;
lock_kernel();
-
- nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "readdir");
- nfs4_setup_putfh(&compound, NFS_FH(dir));
- nfs4_setup_readdir(&compound, cookie, NFS_COOKIEVERF(dir), &page, count, dentry);
- status = nfs4_call_compound(&compound, cred, 0);
+ nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args);
+ res.pgbase = args.pgbase;
+ status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
if (status == 0)
- memcpy(NFS_COOKIEVERF(dir), ops[1].u.readdir.rd_resp_verifier.data, NFS4_VERIFIER_SIZE);
-
+ memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE);
unlock_kernel();
return nfs4_map_errors(status);
}
-static int
-nfs4_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr,
- dev_t rdev, struct nfs_fh *fh, struct nfs_fattr *fattr)
+static int nfs4_proc_mknod(struct inode *dir, struct qstr *name,
+ struct iattr *sattr, dev_t rdev, struct nfs_fh *fh,
+ struct nfs_fattr *fattr)
{
- struct nfs4_compound compound;
- struct nfs4_op ops[7];
- struct nfs_fattr dir_attr;
- struct nfs4_change_info dir_cinfo;
+ struct nfs_server *server = NFS_SERVER(dir);
+ struct nfs4_create_arg arg = {
+ .dir_fh = NFS_FH(dir),
+ .server = server,
+ .name = name,
+ .attrs = sattr,
+ .bitmask = server->attr_bitmask,
+ };
+ struct nfs4_create_res res = {
+ .server = server,
+ .fh = fh,
+ .fattr = fattr,
+ };
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE],
+ .rpc_argp = &arg,
+ .rpc_resp = &res,
+ };
int status;
+ int mode = sattr->ia_mode;
- dir_attr.valid = 0;
fattr->valid = 0;
-
- nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "mknod");
- nfs4_setup_putfh(&compound, NFS_FH(dir));
- nfs4_setup_savefh(&compound);
- nfs4_setup_create_special(&compound, name, rdev,sattr, &dir_cinfo);
- nfs4_setup_getattr(&compound, fattr);
- nfs4_setup_getfh(&compound, fh);
- nfs4_setup_restorefh(&compound);
- nfs4_setup_getattr(&compound, &dir_attr);
- status = nfs4_call_compound(&compound, NULL, 0);
- if (!status) {
- process_cinfo(&dir_cinfo, &dir_attr);
- nfs_refresh_inode(dir, &dir_attr);
+ BUG_ON(!(sattr->ia_valid & ATTR_MODE));
+ BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode));
+ if (S_ISFIFO(mode))
+ arg.ftype = NF4FIFO;
+ else if (S_ISBLK(mode)) {
+ arg.ftype = NF4BLK;
+ arg.u.device.specdata1 = MAJOR(rdev);
+ arg.u.device.specdata2 = MINOR(rdev);
+ }
+ else if (S_ISCHR(mode)) {
+ arg.ftype = NF4CHR;
+ arg.u.device.specdata1 = MAJOR(rdev);
+ arg.u.device.specdata2 = MINOR(rdev);
}
+ else
+ arg.ftype = NF4SOCK;
+
+ status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+ if (!status)
+ update_changeattr(dir, &res.dir_cinfo);
return nfs4_map_errors(status);
}
-static int
-nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
+static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fsstat *fsstat)
{
- struct nfs4_compound compound;
- struct nfs4_op ops[2];
+ struct nfs4_statfs_arg args = {
+ .fh = fhandle,
+ .bitmask = server->attr_bitmask,
+ };
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_STATFS],
+ .rpc_argp = &args,
+ .rpc_resp = fsstat,
+ };
- nfs4_setup_compound(&compound, ops, server, "statfs");
- nfs4_setup_putfh(&compound, fhandle);
- nfs4_setup_statfs(&compound, fsstat);
- return nfs4_map_errors(nfs4_call_compound(&compound, NULL, 0));
+ fsstat->fattr->valid = 0;
+ return nfs4_map_errors(rpc_call_sync(server->client, &msg, 0));
}
-static int
-nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
- struct nfs_fsinfo *fsinfo)
+static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_fsinfo *fsinfo)
{
+ struct nfs4_fsinfo_arg args = {
+ .fh = fhandle,
+ .bitmask = server->attr_bitmask,
+ };
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSINFO],
- .rpc_argp = fhandle,
+ .rpc_argp = &args,
.rpc_resp = fsinfo,
};
return nfs4_map_errors(rpc_call_sync(server->client, &msg, 0));
}
-static int
-nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
- struct nfs_pathconf *pathconf)
+static int nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
{
- struct nfs4_compound compound;
- struct nfs4_op ops[2];
-
- nfs4_setup_compound(&compound, ops, server, "statfs");
- nfs4_setup_putfh(&compound, fhandle);
- nfs4_setup_pathconf(&compound, pathconf);
- return nfs4_map_errors(nfs4_call_compound(&compound, NULL, 0));
+ fsinfo->fattr->valid = 0;
+ return nfs4_map_errors(nfs4_do_fsinfo(server, fhandle, fsinfo));
}
-static void
-nfs4_restart_read(struct rpc_task *task)
+static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_pathconf *pathconf)
{
- struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata;
- struct nfs_page *req;
+ struct nfs4_pathconf_arg args = {
+ .fh = fhandle,
+ .bitmask = server->attr_bitmask,
+ };
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_PATHCONF],
+ .rpc_argp = &args,
+ .rpc_resp = pathconf,
+ };
- 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));
+ /* None of the pathconf attributes are mandatory to implement */
+ if ((args.bitmask[0] & nfs4_pathconf_bitmap[0]) == 0) {
+ memset(pathconf, 0, sizeof(*pathconf));
+ return 0;
+ }
+
+ pathconf->fattr->valid = 0;
+ return nfs4_map_errors(rpc_call_sync(server->client, &msg, 0));
}
static void
@@ -1530,7 +1286,7 @@ nfs4_read_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_read;
+ rpc_restart_call(task);
return;
}
if (task->tk_status > 0)
@@ -1540,7 +1296,7 @@ nfs4_read_done(struct rpc_task *task)
}
static void
-nfs4_proc_read_setup(struct nfs_read_data *data, unsigned int count)
+nfs4_proc_read_setup(struct nfs_read_data *data)
{
struct rpc_task *task = &data->task;
struct rpc_message msg = {
@@ -1550,59 +1306,26 @@ nfs4_proc_read_setup(struct nfs_read_data *data, unsigned int count)
.rpc_cred = data->cred,
};
struct inode *inode = data->inode;
- struct nfs_page *req = nfs_list_entry(data->pages.next);
int flags;
- data->args.fh = NFS_FH(inode);
- data->args.offset = req_offset(req);
- data->args.pgbase = req->wb_pgbase;
- data->args.pages = data->pagevec;
- data->args.count = count;
- data->res.fattr = &data->fattr;
- data->res.count = count;
- data->res.eof = 0;
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));
-
/* N.B. Do we need to test? Never called for swapfile inode */
flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0);
/* Finalize the task. */
rpc_init_task(task, NFS_CLIENT(inode), nfs4_read_done, flags);
- task->tk_calldata = data;
- /* Release requests */
- task->tk_release = nfs_readdata_release;
-
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)
{
struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
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)
@@ -1612,7 +1335,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 = {
@@ -1622,7 +1345,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;
@@ -1633,33 +1355,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);
}
@@ -1670,7 +1374,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 */
@@ -1678,7 +1382,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 = {
@@ -1690,22 +1394,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);
}
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 7d19679f6952..9c3405af1f37 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -105,7 +105,7 @@ nfs4_alloc_client(struct in_addr *addr)
INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp);
INIT_LIST_HEAD(&clp->cl_superblocks);
init_waitqueue_head(&clp->cl_waitq);
- INIT_RPC_WAITQ(&clp->cl_rpcwaitq, "NFS4 client");
+ rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client");
clp->cl_state = 1 << NFS4CLNT_NEW;
}
return clp;
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 3cf1a83df495..0e12e772d255 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -81,21 +81,14 @@ static int nfs_stat_to_errno(int);
#define decode_putrootfh_maxsz (op_decode_hdr_maxsz)
#define encode_getfh_maxsz (op_encode_hdr_maxsz)
#define decode_getfh_maxsz (op_decode_hdr_maxsz + 1 + \
- (NFS4_FHSIZE >> 2))
+ ((3+NFS4_FHSIZE) >> 2))
#define encode_getattr_maxsz (op_encode_hdr_maxsz + 3)
-#define nfs4_fattr_bitmap_maxsz (26 + 2 * ((NFS4_MAXNAMLEN +1) >> 2))
+#define nfs4_name_maxsz (1 + ((3 + NFS4_MAXNAMLEN) >> 2))
+#define nfs4_fattr_bitmap_maxsz (36 + 2 * nfs4_name_maxsz)
#define decode_getattr_maxsz (op_decode_hdr_maxsz + 3 + \
nfs4_fattr_bitmap_maxsz)
#define encode_savefh_maxsz (op_encode_hdr_maxsz)
#define decode_savefh_maxsz (op_decode_hdr_maxsz)
-#define encode_restorefh_maxsz (op_encode_hdr_maxsz)
-#define decode_restorefh_maxsz (op_decode_hdr_maxsz)
-#define encode_read_getattr_maxsz (op_encode_hdr_maxsz + 2)
-#define decode_read_getattr_maxsz (op_decode_hdr_maxsz + 8)
-#define encode_pre_write_getattr_maxsz (op_encode_hdr_maxsz + 2)
-#define decode_pre_write_getattr_maxsz (op_decode_hdr_maxsz + 5)
-#define encode_post_write_getattr_maxsz (op_encode_hdr_maxsz + 2)
-#define decode_post_write_getattr_maxsz (op_decode_hdr_maxsz + 13)
#define encode_fsinfo_maxsz (op_encode_hdr_maxsz + 2)
#define decode_fsinfo_maxsz (op_decode_hdr_maxsz + 11)
#define encode_renew_maxsz (op_encode_hdr_maxsz + 3)
@@ -115,54 +108,63 @@ static int nfs_stat_to_errno(int);
3 + (NFS4_VERIFIER_SIZE >> 2))
#define decode_setclientid_confirm_maxsz \
(op_decode_hdr_maxsz)
-
+#define encode_lookup_maxsz (op_encode_hdr_maxsz + \
+ 1 + ((3 + NFS4_FHSIZE) >> 2))
+#define encode_remove_maxsz (op_encode_hdr_maxsz + \
+ nfs4_name_maxsz)
+#define encode_rename_maxsz (op_encode_hdr_maxsz + \
+ 2 * nfs4_name_maxsz)
+#define decode_rename_maxsz (op_decode_hdr_maxsz + 5 + 5)
+#define encode_link_maxsz (op_encode_hdr_maxsz + \
+ nfs4_name_maxsz)
+#define decode_link_maxsz (op_decode_hdr_maxsz + 5)
+#define encode_create_maxsz (op_encode_hdr_maxsz + \
+ 2 + 2 * nfs4_name_maxsz + \
+ nfs4_fattr_bitmap_maxsz)
+#define decode_create_maxsz (op_decode_hdr_maxsz + 8)
#define NFS4_enc_compound_sz (1024) /* XXX: large enough? */
#define NFS4_dec_compound_sz (1024) /* XXX: large enough? */
#define NFS4_enc_read_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
- encode_read_getattr_maxsz + \
op_encode_hdr_maxsz + 7)
#define NFS4_dec_read_sz (compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
- decode_read_getattr_maxsz + \
+ op_decode_hdr_maxsz + 2)
+#define NFS4_enc_readlink_sz (compound_encode_hdr_maxsz + \
+ encode_putfh_maxsz + \
+ op_encode_hdr_maxsz)
+#define NFS4_dec_readlink_sz (compound_decode_hdr_maxsz + \
+ decode_putfh_maxsz + \
+ op_decode_hdr_maxsz)
+#define NFS4_enc_readdir_sz (compound_encode_hdr_maxsz + \
+ encode_putfh_maxsz + \
+ op_encode_hdr_maxsz + 9)
+#define NFS4_dec_readdir_sz (compound_decode_hdr_maxsz + \
+ decode_putfh_maxsz + \
op_decode_hdr_maxsz + 2)
#define NFS4_enc_write_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
- encode_pre_write_getattr_maxsz + \
- op_encode_hdr_maxsz + 8 + \
- encode_post_write_getattr_maxsz)
+ op_encode_hdr_maxsz + 8)
#define NFS4_dec_write_sz (compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
- decode_pre_write_getattr_maxsz + \
- op_decode_hdr_maxsz + 4 + \
- decode_post_write_getattr_maxsz)
+ op_decode_hdr_maxsz + 4)
#define NFS4_enc_commit_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
- encode_pre_write_getattr_maxsz + \
- op_encode_hdr_maxsz + 3 + \
- encode_post_write_getattr_maxsz)
+ op_encode_hdr_maxsz + 3)
#define NFS4_dec_commit_sz (compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
- decode_pre_write_getattr_maxsz + \
- op_decode_hdr_maxsz + 2 + \
- decode_post_write_getattr_maxsz)
+ op_decode_hdr_maxsz + 2)
#define NFS4_enc_open_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
- encode_savefh_maxsz + \
op_encode_hdr_maxsz + \
13 + 3 + 2 + 64 + \
encode_getattr_maxsz + \
- encode_getfh_maxsz + \
- encode_restorefh_maxsz + \
- encode_getattr_maxsz)
+ encode_getfh_maxsz)
#define NFS4_dec_open_sz (compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
- decode_savefh_maxsz + \
op_decode_hdr_maxsz + 4 + 5 + 2 + 3 + \
decode_getattr_maxsz + \
- decode_getfh_maxsz + \
- decode_restorefh_maxsz + \
- decode_getattr_maxsz)
+ decode_getfh_maxsz)
#define NFS4_enc_open_confirm_sz \
(compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
@@ -255,8 +257,88 @@ static int nfs_stat_to_errno(int);
decode_putfh_maxsz + \
decode_getattr_maxsz + \
op_decode_hdr_maxsz + 4)
-
-
+#define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \
+ encode_putfh_maxsz + \
+ op_encode_hdr_maxsz + 1)
+#define NFS4_dec_access_sz (compound_decode_hdr_maxsz + \
+ decode_putfh_maxsz + \
+ op_decode_hdr_maxsz + 2)
+#define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \
+ encode_putfh_maxsz + \
+ encode_getattr_maxsz)
+#define NFS4_dec_getattr_sz (compound_decode_hdr_maxsz + \
+ decode_putfh_maxsz + \
+ decode_getattr_maxsz)
+#define NFS4_enc_lookup_sz (compound_encode_hdr_maxsz + \
+ encode_putfh_maxsz + \
+ encode_lookup_maxsz + \
+ encode_getattr_maxsz + \
+ encode_getfh_maxsz)
+#define NFS4_dec_lookup_sz (compound_decode_hdr_maxsz + \
+ decode_putfh_maxsz + \
+ op_decode_hdr_maxsz + \
+ decode_getattr_maxsz + \
+ decode_getfh_maxsz)
+#define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \
+ encode_putrootfh_maxsz + \
+ encode_getattr_maxsz + \
+ encode_getfh_maxsz)
+#define NFS4_dec_lookup_root_sz (compound_decode_hdr_maxsz + \
+ decode_putrootfh_maxsz + \
+ decode_getattr_maxsz + \
+ decode_getfh_maxsz)
+#define NFS4_enc_remove_sz (compound_encode_hdr_maxsz + \
+ encode_putfh_maxsz + \
+ encode_remove_maxsz)
+#define NFS4_dec_remove_sz (compound_decode_hdr_maxsz + \
+ decode_putfh_maxsz + \
+ op_decode_hdr_maxsz + 5)
+#define NFS4_enc_rename_sz (compound_encode_hdr_maxsz + \
+ encode_putfh_maxsz + \
+ encode_savefh_maxsz + \
+ encode_putfh_maxsz + \
+ encode_rename_maxsz)
+#define NFS4_dec_rename_sz (compound_decode_hdr_maxsz + \
+ decode_putfh_maxsz + \
+ decode_savefh_maxsz + \
+ decode_putfh_maxsz + \
+ decode_rename_maxsz)
+#define NFS4_enc_link_sz (compound_encode_hdr_maxsz + \
+ encode_putfh_maxsz + \
+ encode_savefh_maxsz + \
+ encode_putfh_maxsz + \
+ encode_link_maxsz)
+#define NFS4_dec_link_sz (compound_decode_hdr_maxsz + \
+ decode_putfh_maxsz + \
+ decode_savefh_maxsz + \
+ decode_putfh_maxsz + \
+ decode_link_maxsz)
+#define NFS4_enc_create_sz (compound_encode_hdr_maxsz + \
+ encode_putfh_maxsz + \
+ encode_create_maxsz + \
+ encode_getattr_maxsz + \
+ encode_getfh_maxsz)
+#define NFS4_dec_create_sz (compound_decode_hdr_maxsz + \
+ decode_putfh_maxsz + \
+ decode_create_maxsz + \
+ decode_getattr_maxsz + \
+ decode_getfh_maxsz)
+#define NFS4_enc_pathconf_sz (compound_encode_hdr_maxsz + \
+ encode_putfh_maxsz + \
+ encode_getattr_maxsz)
+#define NFS4_dec_pathconf_sz (compound_decode_hdr_maxsz + \
+ decode_putfh_maxsz + \
+ decode_getattr_maxsz)
+#define NFS4_enc_statfs_sz (compound_encode_hdr_maxsz + \
+ encode_putfh_maxsz + \
+ encode_getattr_maxsz)
+#define NFS4_dec_statfs_sz (compound_decode_hdr_maxsz + \
+ decode_putfh_maxsz + \
+ op_decode_hdr_maxsz + 12)
+#define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \
+ encode_getattr_maxsz)
+#define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \
+ decode_getattr_maxsz)
static struct {
unsigned int mode;
@@ -297,7 +379,7 @@ struct compound_hdr {
*p++ = htonl((uint32_t)(n)); \
} while (0)
#define WRITEMEM(ptr,nbytes) do { \
- p = xdr_writemem(p, ptr, nbytes); \
+ p = xdr_encode_opaque_fixed(p, ptr, nbytes); \
} while (0)
#define RESERVE_SPACE(nbytes) do { \
@@ -306,19 +388,7 @@ struct compound_hdr {
BUG_ON(!p); \
} while (0)
-static inline
-uint32_t *xdr_writemem(uint32_t *p, const void *ptr, int nbytes)
-{
- int tmp = XDR_QUADLEN(nbytes);
- if (!tmp)
- return p;
- p[tmp-1] = 0;
- memcpy(p, ptr, nbytes);
- return p + tmp;
-}
-
-static int
-encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
+static int encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
{
uint32_t *p;
@@ -332,9 +402,7 @@ encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
return 0;
}
-static int
-encode_attrs(struct xdr_stream *xdr, struct iattr *iap,
- struct nfs_server *server)
+static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server)
{
char owner_name[IDMAP_NAMESZ];
char owner_group[IDMAP_NAMESZ];
@@ -461,20 +529,18 @@ encode_attrs(struct xdr_stream *xdr, struct iattr *iap,
return status;
}
-static int
-encode_access(struct xdr_stream *xdr, struct nfs4_access *access)
+static int encode_access(struct xdr_stream *xdr, u32 access)
{
uint32_t *p;
RESERVE_SPACE(8);
WRITE32(OP_ACCESS);
- WRITE32(access->ac_req_access);
+ WRITE32(access);
return 0;
}
-static int
-encode_close(struct xdr_stream *xdr, struct nfs_closeargs *arg)
+static int encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg)
{
uint32_t *p;
@@ -486,8 +552,7 @@ encode_close(struct xdr_stream *xdr, struct nfs_closeargs *arg)
return 0;
}
-static int
-encode_commit(struct xdr_stream *xdr, struct nfs_writeargs *args)
+static int encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args)
{
uint32_t *p;
@@ -499,42 +564,39 @@ encode_commit(struct xdr_stream *xdr, struct nfs_writeargs *args)
return 0;
}
-static int
-encode_create(struct xdr_stream *xdr, struct nfs4_create *create,
- struct nfs_server *server)
+static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create)
{
uint32_t *p;
RESERVE_SPACE(8);
WRITE32(OP_CREATE);
- WRITE32(create->cr_ftype);
+ WRITE32(create->ftype);
- switch (create->cr_ftype) {
+ switch (create->ftype) {
case NF4LNK:
- RESERVE_SPACE(4 + create->cr_textlen);
- WRITE32(create->cr_textlen);
- WRITEMEM(create->cr_text, create->cr_textlen);
+ RESERVE_SPACE(4 + create->u.symlink->len);
+ WRITE32(create->u.symlink->len);
+ WRITEMEM(create->u.symlink->name, create->u.symlink->len);
break;
case NF4BLK: case NF4CHR:
RESERVE_SPACE(8);
- WRITE32(create->cr_specdata1);
- WRITE32(create->cr_specdata2);
+ WRITE32(create->u.device.specdata1);
+ WRITE32(create->u.device.specdata2);
break;
default:
break;
}
- RESERVE_SPACE(4 + create->cr_namelen);
- WRITE32(create->cr_namelen);
- WRITEMEM(create->cr_name, create->cr_namelen);
+ RESERVE_SPACE(4 + create->name->len);
+ WRITE32(create->name->len);
+ WRITEMEM(create->name->name, create->name->len);
- return encode_attrs(xdr, create->cr_attrs, server);
+ return encode_attrs(xdr, create->attrs, create->server);
}
-static int
-encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap)
+static int encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap)
{
uint32_t *p;
@@ -545,8 +607,7 @@ encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap)
return 0;
}
-static int
-encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1)
+static int encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1)
{
uint32_t *p;
@@ -558,56 +619,24 @@ encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1)
return 0;
}
-static inline int
-encode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr)
+static int encode_getfattr(struct xdr_stream *xdr, const u32* bitmask)
{
- return encode_getattr_two(xdr, getattr->gt_bmval[0],
- getattr->gt_bmval[1]);
-}
+ extern u32 nfs4_fattr_bitmap[];
-/*
- * Request the change attribute in order to check attribute+cache consistency
- */
-static inline int
-encode_read_getattr(struct xdr_stream *xdr)
-{
- return encode_getattr_two(xdr, FATTR4_WORD0_CHANGE,
- FATTR4_WORD1_TIME_ACCESS);
+ return encode_getattr_two(xdr,
+ bitmask[0] & nfs4_fattr_bitmap[0],
+ bitmask[1] & nfs4_fattr_bitmap[1]);
}
-/*
- * Request the change attribute prior to doing a write operation
- */
-static inline int
-encode_pre_write_getattr(struct xdr_stream *xdr)
+static int encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask)
{
- /* Request the change attribute */
- return encode_getattr_one(xdr, FATTR4_WORD0_CHANGE);
-}
+ extern u32 nfs4_fsinfo_bitmap[];
-/*
- * Request the change attribute, size, and [cm]time after a write operation
- */
-static inline int
-encode_post_write_getattr(struct xdr_stream *xdr)
-{
- return encode_getattr_two(xdr, FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE,
- FATTR4_WORD1_SPACE_USED |
- FATTR4_WORD1_TIME_METADATA |
- FATTR4_WORD1_TIME_MODIFY);
-}
-
-static int
-encode_fsinfo(struct xdr_stream *xdr)
-{
- return encode_getattr_one(xdr, FATTR4_WORD0_MAXFILESIZE
- | FATTR4_WORD0_MAXREAD
- | FATTR4_WORD0_MAXWRITE
- | FATTR4_WORD0_LEASE_TIME);
+ return encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0],
+ bitmask[1] & nfs4_fsinfo_bitmap[1]);
}
-static int
-encode_getfh(struct xdr_stream *xdr)
+static int encode_getfh(struct xdr_stream *xdr)
{
uint32_t *p;
@@ -617,15 +646,14 @@ encode_getfh(struct xdr_stream *xdr)
return 0;
}
-static int
-encode_link(struct xdr_stream *xdr, struct nfs4_link *link)
+static int encode_link(struct xdr_stream *xdr, const struct qstr *name)
{
uint32_t *p;
- RESERVE_SPACE(8 + link->ln_namelen);
+ RESERVE_SPACE(8 + name->len);
WRITE32(OP_LINK);
- WRITE32(link->ln_namelen);
- WRITEMEM(link->ln_name, link->ln_namelen);
+ WRITE32(name->len);
+ WRITEMEM(name->name, name->len);
return 0;
}
@@ -634,8 +662,7 @@ encode_link(struct xdr_stream *xdr, struct nfs4_link *link)
* opcode,type,reclaim,offset,length,new_lock_owner = 32
* open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40
*/
-static int
-encode_lock(struct xdr_stream *xdr, struct nfs_lockargs *arg)
+static int encode_lock(struct xdr_stream *xdr, const struct nfs_lockargs *arg)
{
uint32_t *p;
struct nfs_lock_opargs *opargs = arg->u.lock;
@@ -669,8 +696,7 @@ encode_lock(struct xdr_stream *xdr, struct nfs_lockargs *arg)
return 0;
}
-static int
-encode_lockt(struct xdr_stream *xdr, struct nfs_lockargs *arg)
+static int encode_lockt(struct xdr_stream *xdr, const struct nfs_lockargs *arg)
{
uint32_t *p;
struct nfs_lowner *opargs = arg->u.lockt;
@@ -687,8 +713,7 @@ encode_lockt(struct xdr_stream *xdr, struct nfs_lockargs *arg)
return 0;
}
-static int
-encode_locku(struct xdr_stream *xdr, struct nfs_lockargs *arg)
+static int encode_locku(struct xdr_stream *xdr, const struct nfs_lockargs *arg)
{
uint32_t *p;
struct nfs_locku_opargs *opargs = arg->u.locku;
@@ -704,22 +729,20 @@ encode_locku(struct xdr_stream *xdr, struct nfs_lockargs *arg)
return 0;
}
-static int
-encode_lookup(struct xdr_stream *xdr, struct nfs4_lookup *lookup)
+static int encode_lookup(struct xdr_stream *xdr, const struct qstr *name)
{
- int len = lookup->lo_name->len;
+ int len = name->len;
uint32_t *p;
RESERVE_SPACE(8 + len);
WRITE32(OP_LOOKUP);
WRITE32(len);
- WRITEMEM(lookup->lo_name->name, len);
+ WRITEMEM(name->name, len);
return 0;
}
-static int
-encode_open(struct xdr_stream *xdr, struct nfs_openargs *arg)
+static int encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg)
{
int status;
uint32_t *p;
@@ -778,8 +801,7 @@ encode_open(struct xdr_stream *xdr, struct nfs_openargs *arg)
return 0;
}
-static int
-encode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmargs *arg)
+static int encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg)
{
uint32_t *p;
@@ -792,8 +814,7 @@ encode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmargs *arg)
}
-static int
-encode_open_reclaim(struct xdr_stream *xdr, struct nfs_open_reclaimargs *arg)
+static int encode_open_reclaim(struct xdr_stream *xdr, const struct nfs_open_reclaimargs *arg)
{
uint32_t *p;
@@ -827,8 +848,7 @@ encode_open_reclaim(struct xdr_stream *xdr, struct nfs_open_reclaimargs *arg)
return 0;
}
-static int
-encode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeargs *arg)
+static int encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg)
{
uint32_t *p;
@@ -844,7 +864,7 @@ encode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeargs *arg)
}
static int
-encode_putfh(struct xdr_stream *xdr, struct nfs_fh *fh)
+encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh)
{
int len = fh->size;
uint32_t *p;
@@ -857,8 +877,7 @@ encode_putfh(struct xdr_stream *xdr, struct nfs_fh *fh)
return 0;
}
-static int
-encode_putrootfh(struct xdr_stream *xdr)
+static int encode_putrootfh(struct xdr_stream *xdr)
{
uint32_t *p;
@@ -868,22 +887,37 @@ encode_putrootfh(struct xdr_stream *xdr)
return 0;
}
-static int
-encode_read(struct xdr_stream *xdr, struct nfs_readargs *args)
+static void encode_stateid(struct xdr_stream *xdr, struct nfs4_state *state, fl_owner_t lockowner)
{
+ extern nfs4_stateid zero_stateid;
+ nfs4_stateid stateid;
uint32_t *p;
- RESERVE_SPACE(32);
+ RESERVE_SPACE(16);
+ if (state != NULL) {
+ nfs4_copy_stateid(&stateid, state, lockowner);
+ WRITEMEM(stateid.data, sizeof(stateid.data));
+ } else
+ WRITEMEM(zero_stateid.data, sizeof(zero_stateid.data));
+}
+
+static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args)
+{
+ uint32_t *p;
+
+ RESERVE_SPACE(4);
WRITE32(OP_READ);
- WRITEMEM(args->stateid.data, sizeof(args->stateid.data));
+
+ encode_stateid(xdr, args->state, args->lockowner);
+
+ RESERVE_SPACE(12);
WRITE64(args->offset);
WRITE32(args->count);
return 0;
}
-static int
-encode_readdir(struct xdr_stream *xdr, struct nfs4_readdir *readdir, struct rpc_rqst *req)
+static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req)
{
struct rpc_auth *auth = req->rq_task->tk_auth;
int replen;
@@ -891,27 +925,26 @@ encode_readdir(struct xdr_stream *xdr, struct nfs4_readdir *readdir, struct rpc_
RESERVE_SPACE(32+sizeof(nfs4_verifier));
WRITE32(OP_READDIR);
- WRITE64(readdir->rd_cookie);
- WRITEMEM(readdir->rd_req_verifier.data, sizeof(readdir->rd_req_verifier.data));
- WRITE32(readdir->rd_count >> 5); /* meaningless "dircount" field */
- WRITE32(readdir->rd_count);
+ WRITE64(readdir->cookie);
+ WRITEMEM(readdir->verifier.data, sizeof(readdir->verifier.data));
+ WRITE32(readdir->count >> 5); /* meaningless "dircount" field */
+ WRITE32(readdir->count);
WRITE32(2);
- WRITE32(readdir->rd_bmval[0]);
- WRITE32(readdir->rd_bmval[1]);
+ WRITE32(FATTR4_WORD0_FILEID);
+ WRITE32(0);
/* set up reply iovec
* toplevel_status + taglen + rescount + OP_PUTFH + status
* + OP_READDIR + status + verifer(2) = 9
*/
replen = (RPC_REPHDRSIZE + auth->au_rslack + 9) << 2;
- xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->rd_pages,
- readdir->rd_pgbase, readdir->rd_count);
+ xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->pages,
+ readdir->pgbase, readdir->count);
return 0;
}
-static int
-encode_readlink(struct xdr_stream *xdr, struct nfs4_readlink *readlink, struct rpc_rqst *req)
+static int encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req)
{
struct rpc_auth *auth = req->rq_task->tk_auth;
int replen;
@@ -925,43 +958,40 @@ encode_readlink(struct xdr_stream *xdr, struct nfs4_readlink *readlink, struct r
* + OP_READLINK + status = 7
*/
replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2;
- xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->rl_pages, 0, readlink->rl_count);
+ xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->pages, 0, readlink->count);
return 0;
}
-static int
-encode_remove(struct xdr_stream *xdr, struct nfs4_remove *remove)
+static int encode_remove(struct xdr_stream *xdr, const struct qstr *name)
{
uint32_t *p;
- RESERVE_SPACE(8 + remove->rm_namelen);
+ RESERVE_SPACE(8 + name->len);
WRITE32(OP_REMOVE);
- WRITE32(remove->rm_namelen);
- WRITEMEM(remove->rm_name, remove->rm_namelen);
+ WRITE32(name->len);
+ WRITEMEM(name->name, name->len);
return 0;
}
-static int
-encode_rename(struct xdr_stream *xdr, struct nfs4_rename *rename)
+static int encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname)
{
uint32_t *p;
- RESERVE_SPACE(8 + rename->rn_oldnamelen);
+ RESERVE_SPACE(8 + oldname->len);
WRITE32(OP_RENAME);
- WRITE32(rename->rn_oldnamelen);
- WRITEMEM(rename->rn_oldname, rename->rn_oldnamelen);
+ WRITE32(oldname->len);
+ WRITEMEM(oldname->name, oldname->len);
- RESERVE_SPACE(4 + rename->rn_newnamelen);
- WRITE32(rename->rn_newnamelen);
- WRITEMEM(rename->rn_newname, rename->rn_newnamelen);
+ RESERVE_SPACE(4 + newname->len);
+ WRITE32(newname->len);
+ WRITEMEM(newname->name, newname->len);
return 0;
}
-static int
-encode_renew(struct xdr_stream *xdr, struct nfs4_client *client_stateid)
+static int encode_renew(struct xdr_stream *xdr, const struct nfs4_client *client_stateid)
{
uint32_t *p;
@@ -973,17 +1003,6 @@ encode_renew(struct xdr_stream *xdr, struct nfs4_client *client_stateid)
}
static int
-encode_restorefh(struct xdr_stream *xdr)
-{
- uint32_t *p;
-
- RESERVE_SPACE(4);
- WRITE32(OP_RESTOREFH);
-
- return 0;
-}
-
-static int
encode_savefh(struct xdr_stream *xdr)
{
uint32_t *p;
@@ -994,9 +1013,7 @@ encode_savefh(struct xdr_stream *xdr)
return 0;
}
-static int
-encode_setattr(struct xdr_stream *xdr, struct nfs_setattrargs *arg,
- struct nfs_server *server)
+static int encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server)
{
int status;
uint32_t *p;
@@ -1011,8 +1028,7 @@ encode_setattr(struct xdr_stream *xdr, struct nfs_setattrargs *arg,
return 0;
}
-static int
-encode_setclientid(struct xdr_stream *xdr, struct nfs4_setclientid *setclientid)
+static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid)
{
uint32_t total_len;
uint32_t len1, len2, len3;
@@ -1039,8 +1055,7 @@ encode_setclientid(struct xdr_stream *xdr, struct nfs4_setclientid *setclientid)
return 0;
}
-static int
-encode_setclientid_confirm(struct xdr_stream *xdr, struct nfs4_client *client_state)
+static int encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4_client *client_state)
{
uint32_t *p;
@@ -1052,14 +1067,16 @@ encode_setclientid_confirm(struct xdr_stream *xdr, struct nfs4_client *client_st
return 0;
}
-static int
-encode_write(struct xdr_stream *xdr, struct nfs_writeargs *args)
+static int encode_write(struct xdr_stream *xdr, const 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);
@@ -1068,97 +1085,185 @@ encode_write(struct xdr_stream *xdr, struct nfs_writeargs *args)
return 0;
}
+/*
+ * END OF "GENERIC" ENCODE ROUTINES.
+ */
-/* FIXME: this sucks */
-static int
-encode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqst *req)
+/*
+ * Encode an ACCESS request
+ */
+static int nfs4_xdr_enc_access(struct rpc_rqst *req, uint32_t *p, const struct nfs4_accessargs *args)
{
+ struct xdr_stream xdr;
struct compound_hdr hdr = {
- .taglen = cp->taglen,
- .tag = cp->tag,
- .nops = cp->req_nops,
+ .nops = 2,
};
- int i, status = 0;
+ int status;
- encode_compound_hdr(xdr, &hdr);
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+ encode_compound_hdr(&xdr, &hdr);
+ if ((status = encode_putfh(&xdr, args->fh)) == 0)
+ status = encode_access(&xdr, args->access);
+ return status;
+}
- for (i = 0; i < cp->req_nops; i++) {
- switch (cp->ops[i].opnum) {
- case OP_ACCESS:
- status = encode_access(xdr, &cp->ops[i].u.access);
- break;
- case OP_CREATE:
- status = encode_create(xdr, &cp->ops[i].u.create, cp->server);
- break;
- case OP_GETATTR:
- status = encode_getattr(xdr, &cp->ops[i].u.getattr);
- break;
- case OP_GETFH:
- status = encode_getfh(xdr);
- break;
- case OP_LINK:
- status = encode_link(xdr, &cp->ops[i].u.link);
- break;
- case OP_LOOKUP:
- status = encode_lookup(xdr, &cp->ops[i].u.lookup);
- break;
- case OP_PUTFH:
- status = encode_putfh(xdr, cp->ops[i].u.putfh.pf_fhandle);
- break;
- case OP_PUTROOTFH:
- status = encode_putrootfh(xdr);
- break;
- case OP_READDIR:
- status = encode_readdir(xdr, &cp->ops[i].u.readdir, req);
- break;
- case OP_READLINK:
- status = encode_readlink(xdr, &cp->ops[i].u.readlink, req);
- break;
- case OP_REMOVE:
- status = encode_remove(xdr, &cp->ops[i].u.remove);
- break;
- case OP_RENAME:
- status = encode_rename(xdr, &cp->ops[i].u.rename);
- break;
- case OP_RESTOREFH:
- status = encode_restorefh(xdr);
- break;
- case OP_SAVEFH:
- status = encode_savefh(xdr);
- break;
- default:
- BUG();
- }
- if (status)
- return status;
- }
-
- return 0;
+/*
+ * Encode LOOKUP request
+ */
+static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, uint32_t *p, const struct nfs4_lookup_arg *args)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+ .nops = 4,
+ };
+ int status;
+
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+ encode_compound_hdr(&xdr, &hdr);
+ if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
+ goto out;
+ if ((status = encode_lookup(&xdr, args->name)) != 0)
+ goto out;
+ if ((status = encode_getfh(&xdr)) != 0)
+ goto out;
+ status = encode_getfattr(&xdr, args->bitmask);
+out:
+ return status;
}
+
/*
- * END OF "GENERIC" ENCODE ROUTINES.
+ * Encode LOOKUP_ROOT request
+ */
+static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, uint32_t *p, const struct nfs4_lookup_root_arg *args)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+ .nops = 3,
+ };
+ int status;
+
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+ encode_compound_hdr(&xdr, &hdr);
+ if ((status = encode_putrootfh(&xdr)) != 0)
+ goto out;
+ if ((status = encode_getfh(&xdr)) == 0)
+ status = encode_getfattr(&xdr, args->bitmask);
+out:
+ return status;
+}
+
+/*
+ * Encode REMOVE request
*/
+static int nfs4_xdr_enc_remove(struct rpc_rqst *req, uint32_t *p, const struct nfs4_remove_arg *args)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+ .nops = 2,
+ };
+ int status;
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+ encode_compound_hdr(&xdr, &hdr);
+ if ((status = encode_putfh(&xdr, args->fh)) == 0)
+ status = encode_remove(&xdr, args->name);
+ return status;
+}
/*
- * Encode COMPOUND argument
+ * Encode RENAME request
*/
-static int
-nfs4_xdr_enc_compound(struct rpc_rqst *req, uint32_t *p, struct nfs4_compound *cp)
+static int nfs4_xdr_enc_rename(struct rpc_rqst *req, uint32_t *p, const struct nfs4_rename_arg *args)
{
struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+ .nops = 4,
+ };
int status;
-
+
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
- status = encode_compound(&xdr, cp, req);
- cp->timestamp = jiffies;
+ encode_compound_hdr(&xdr, &hdr);
+ if ((status = encode_putfh(&xdr, args->old_dir)) != 0)
+ goto out;
+ if ((status = encode_savefh(&xdr)) != 0)
+ goto out;
+ if ((status = encode_putfh(&xdr, args->new_dir)) != 0)
+ goto out;
+ status = encode_rename(&xdr, args->old_name, args->new_name);
+out:
return status;
}
+
+/*
+ * Encode LINK request
+ */
+static int nfs4_xdr_enc_link(struct rpc_rqst *req, uint32_t *p, const struct nfs4_link_arg *args)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+ .nops = 4,
+ };
+ int status;
+
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+ encode_compound_hdr(&xdr, &hdr);
+ if ((status = encode_putfh(&xdr, args->fh)) != 0)
+ goto out;
+ if ((status = encode_savefh(&xdr)) != 0)
+ goto out;
+ if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
+ goto out;
+ status = encode_link(&xdr, args->name);
+out:
+ return status;
+}
+
+/*
+ * Encode CREATE request
+ */
+static int nfs4_xdr_enc_create(struct rpc_rqst *req, uint32_t *p, const struct nfs4_create_arg *args)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+ .nops = 4,
+ };
+ int status;
+
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+ encode_compound_hdr(&xdr, &hdr);
+ if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
+ goto out;
+ if ((status = encode_create(&xdr, args)) != 0)
+ goto out;
+ if ((status = encode_getfattr(&xdr, args->bitmask)) != 0)
+ goto out;
+ status = encode_getfh(&xdr);
+out:
+ return status;
+}
+
+/*
+ * Encode GETATTR request
+ */
+static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, uint32_t *p, const struct nfs4_getattr_arg *args)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+ .nops = 2,
+ };
+ int status;
+
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+ encode_compound_hdr(&xdr, &hdr);
+ if ((status = encode_putfh(&xdr, args->fh)) == 0)
+ status = encode_getfattr(&xdr, args->bitmask);
+ return status;
+}
+
/*
* Encode a CLOSE request
*/
-static int
-nfs4_xdr_enc_close(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args)
+static int nfs4_xdr_enc_close(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1179,12 +1284,11 @@ out:
/*
* Encode an OPEN request
*/
-static int
-nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_openargs *args)
+static int nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_openargs *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 7,
+ .nops = 4,
};
int status;
@@ -1193,22 +1297,13 @@ nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_openargs *args)
status = encode_putfh(&xdr, args->fh);
if (status)
goto out;
- status = encode_savefh(&xdr);
- if (status)
- goto out;
status = encode_open(&xdr, args);
if (status)
goto out;
- status = encode_getattr(&xdr, args->f_getattr);
+ status = encode_getfattr(&xdr, args->bitmask);
if (status)
goto out;
status = encode_getfh(&xdr);
- if (status)
- goto out;
- status = encode_restorefh(&xdr);
- if (status)
- goto out;
- status = encode_getattr(&xdr, args->d_getattr);
out:
return status;
}
@@ -1216,8 +1311,7 @@ out:
/*
* Encode an OPEN_CONFIRM request
*/
-static int
-nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_open_confirmargs *args)
+static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_open_confirmargs *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1238,9 +1332,7 @@ out:
/*
* Encode an OPEN request
*/
-static int
-nfs4_xdr_enc_open_reclaim(struct rpc_rqst *req, uint32_t *p,
- struct nfs_open_reclaimargs *args)
+static int nfs4_xdr_enc_open_reclaim(struct rpc_rqst *req, uint32_t *p, struct nfs_open_reclaimargs *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1256,7 +1348,7 @@ nfs4_xdr_enc_open_reclaim(struct rpc_rqst *req, uint32_t *p,
status = encode_open_reclaim(&xdr, args);
if (status)
goto out;
- status = encode_getattr(&xdr, args->f_getattr);
+ status = encode_getfattr(&xdr, args->bitmask);
out:
return status;
}
@@ -1264,8 +1356,7 @@ out:
/*
* Encode an OPEN_DOWNGRADE request
*/
-static int
-nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args)
+static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1286,8 +1377,7 @@ out:
/*
* Encode a LOCK request
*/
-static int
-nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
+static int nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1308,8 +1398,7 @@ out:
/*
* Encode a LOCKT request
*/
-static int
-nfs4_xdr_enc_lockt(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
+static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1330,8 +1419,7 @@ out:
/*
* Encode a LOCKU request
*/
-static int
-nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
+static int nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1350,15 +1438,56 @@ out:
}
/*
+ * Encode a READLINK request
+ */
+static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, uint32_t *p, const struct nfs4_readlink *args)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+ .nops = 2,
+ };
+ int status;
+
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+ encode_compound_hdr(&xdr, &hdr);
+ status = encode_putfh(&xdr, args->fh);
+ if(status)
+ goto out;
+ status = encode_readlink(&xdr, args, req);
+out:
+ return status;
+}
+
+/*
+ * Encode a READDIR request
+ */
+static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, uint32_t *p, const struct nfs4_readdir_arg *args)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+ .nops = 2,
+ };
+ int status;
+
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+ encode_compound_hdr(&xdr, &hdr);
+ status = encode_putfh(&xdr, args->fh);
+ if(status)
+ goto out;
+ status = encode_readdir(&xdr, args, req);
+out:
+ return status;
+}
+
+/*
* Encode a READ request
*/
-static int
-nfs4_xdr_enc_read(struct rpc_rqst *req, uint32_t *p, struct nfs_readargs *args)
+static int nfs4_xdr_enc_read(struct rpc_rqst *req, uint32_t *p, struct nfs_readargs *args)
{
struct rpc_auth *auth = req->rq_task->tk_auth;
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 3,
+ .nops = 2,
};
int replen, status;
@@ -1370,14 +1499,12 @@ nfs4_xdr_enc_read(struct rpc_rqst *req, uint32_t *p, struct nfs_readargs *args)
status = encode_read(&xdr, args);
if (status)
goto out;
- status = encode_read_getattr(&xdr);
/* set up reply iovec
* toplevel status + taglen=0 + rescount + OP_PUTFH + status
* + OP_READ + status + eof + datalen = 9
*/
- replen = (RPC_REPHDRSIZE + auth->au_rslack +
- NFS4_dec_read_sz - decode_read_getattr_maxsz) << 2;
+ replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_read_sz) << 2;
xdr_inline_pages(&req->rq_rcv_buf, replen,
args->pages, args->pgbase, args->count);
out:
@@ -1387,8 +1514,7 @@ out:
/*
* Encode an SETATTR request
*/
-static int
-nfs4_xdr_enc_setattr(struct rpc_rqst *req, uint32_t *p, struct nfs_setattrargs *args)
+static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, uint32_t *p, struct nfs_setattrargs *args)
{
struct xdr_stream xdr;
@@ -1405,7 +1531,7 @@ nfs4_xdr_enc_setattr(struct rpc_rqst *req, uint32_t *p, struct nfs_setattrargs *
status = encode_setattr(&xdr, args, args->server);
if(status)
goto out;
- status = encode_getattr(&xdr, args->attr);
+ status = encode_getfattr(&xdr, args->bitmask);
out:
return status;
}
@@ -1413,12 +1539,11 @@ out:
/*
* Encode a WRITE request
*/
-static int
-nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args)
+static int nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 4,
+ .nops = 2,
};
int status;
@@ -1427,13 +1552,7 @@ nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args
status = encode_putfh(&xdr, args->fh);
if (status)
goto out;
- status = encode_pre_write_getattr(&xdr);
- if (status)
- goto out;
status = encode_write(&xdr, args);
- if (status)
- goto out;
- status = encode_post_write_getattr(&xdr);
out:
return status;
}
@@ -1441,12 +1560,11 @@ out:
/*
* a COMMIT request
*/
-static int
-nfs4_xdr_enc_commit(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args)
+static int nfs4_xdr_enc_commit(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 4,
+ .nops = 2,
};
int status;
@@ -1455,13 +1573,7 @@ nfs4_xdr_enc_commit(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *arg
status = encode_putfh(&xdr, args->fh);
if (status)
goto out;
- status = encode_pre_write_getattr(&xdr);
- if (status)
- goto out;
status = encode_commit(&xdr, args);
- if (status)
- goto out;
- status = encode_post_write_getattr(&xdr);
out:
return status;
}
@@ -1469,8 +1581,7 @@ out:
/*
* FSINFO request
*/
-static int
-nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, uint32_t *p, void *fhandle)
+static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs4_fsinfo_arg *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1480,17 +1591,81 @@ nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, uint32_t *p, void *fhandle)
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- status = encode_putfh(&xdr, fhandle);
+ status = encode_putfh(&xdr, args->fh);
+ if (!status)
+ status = encode_fsinfo(&xdr, args->bitmask);
+ return status;
+}
+
+/*
+ * a PATHCONF request
+ */
+static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, uint32_t *p, const struct nfs4_pathconf_arg *args)
+{
+ extern u32 nfs4_pathconf_bitmap[2];
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+ .nops = 2,
+ };
+ int status;
+
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+ encode_compound_hdr(&xdr, &hdr);
+ status = encode_putfh(&xdr, args->fh);
if (!status)
- status = encode_fsinfo(&xdr);
+ status = encode_getattr_one(&xdr,
+ args->bitmask[0] & nfs4_pathconf_bitmap[0]);
+ return status;
+}
+
+/*
+ * a STATFS request
+ */
+static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, uint32_t *p, const struct nfs4_statfs_arg *args)
+{
+ extern u32 nfs4_statfs_bitmap[];
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+ .nops = 2,
+ };
+ int status;
+
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+ encode_compound_hdr(&xdr, &hdr);
+ status = encode_putfh(&xdr, args->fh);
+ if (status == 0)
+ status = encode_getattr_two(&xdr,
+ args->bitmask[0] & nfs4_statfs_bitmap[0],
+ args->bitmask[1] & nfs4_statfs_bitmap[1]);
+ return status;
+}
+
+/*
+ * GETATTR_BITMAP request
+ */
+static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, uint32_t *p, const struct nfs_fh *fhandle)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+ .nops = 2,
+ };
+ int status;
+
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+ encode_compound_hdr(&xdr, &hdr);
+ status = encode_putfh(&xdr, fhandle);
+ if (status == 0)
+ status = encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS|
+ FATTR4_WORD0_LINK_SUPPORT|
+ FATTR4_WORD0_SYMLINK_SUPPORT|
+ FATTR4_WORD0_ACLSUPPORT);
return status;
}
/*
* a RENEW request
*/
-static int
-nfs4_xdr_enc_renew(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp)
+static int nfs4_xdr_enc_renew(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1505,9 +1680,7 @@ nfs4_xdr_enc_renew(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp)
/*
* a SETCLIENTID request
*/
-static int
-nfs4_xdr_enc_setclientid(struct rpc_rqst *req, uint32_t *p,
- struct nfs4_setclientid *sc)
+static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, uint32_t *p, struct nfs4_setclientid *sc)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1522,14 +1695,13 @@ nfs4_xdr_enc_setclientid(struct rpc_rqst *req, uint32_t *p,
/*
* a SETCLIENTID_CONFIRM request
*/
-static int
-nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p,
- struct nfs4_client *clp)
+static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
.nops = 3,
};
+ const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 };
int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
@@ -1538,7 +1710,7 @@ nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p,
if (!status)
status = encode_putrootfh(&xdr);
if (!status)
- status = encode_fsinfo(&xdr);
+ status = encode_fsinfo(&xdr, lease_bitmap);
return status;
}
@@ -1552,15 +1724,6 @@ nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p,
* task to translate them into Linux-specific versions which are more
* consistent with the style used in NFSv2/v3...
*/
-#define DECODE_TAIL \
- status = 0; \
-out: \
- return status; \
-xdr_error: \
- printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); \
- status = -EIO; \
- goto out
-
#define READ32(x) (x) = ntohl(*p++)
#define READ64(x) do { \
(x) = (u64)ntohl(*p++) << 32; \
@@ -1585,8 +1748,7 @@ xdr_error: \
} \
} while (0)
-static int
-decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
+static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
{
uint32_t *p;
@@ -1601,8 +1763,7 @@ decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
return 0;
}
-static int
-decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
+static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
{
uint32_t *p;
uint32_t opnum;
@@ -1623,523 +1784,847 @@ decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
return 0;
}
-static int
-decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
+static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
+{
+ uint32_t bmlen, *p;
+
+ READ_BUF(4);
+ READ32(bmlen);
+
+ bitmap[0] = bitmap[1] = 0;
+ READ_BUF((bmlen << 2));
+ if (bmlen > 0) {
+ READ32(bitmap[0]);
+ if (bmlen > 1)
+ READ32(bitmap[1]);
+ }
+ return 0;
+}
+
+static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, uint32_t **savep)
{
uint32_t *p;
- READ_BUF(20);
- READ32(cinfo->atomic);
- READ64(cinfo->before);
- READ64(cinfo->after);
+ READ_BUF(4);
+ READ32(*attrlen);
+ *savep = xdr->p;
return 0;
}
-static int
-decode_access(struct xdr_stream *xdr, struct nfs4_access *access)
+static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *bitmask)
+{
+ if (likely(bitmap[0] & FATTR4_WORD0_SUPPORTED_ATTRS)) {
+ decode_attr_bitmap(xdr, bitmask);
+ bitmap[0] &= ~FATTR4_WORD0_SUPPORTED_ATTRS;
+ } else
+ bitmask[0] = bitmask[1] = 0;
+ dprintk("%s: bitmask=0x%x%x\n", __FUNCTION__, bitmask[0], bitmask[1]);
+ return 0;
+}
+
+static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *type)
{
uint32_t *p;
- uint32_t supp, acc;
- int status;
- status = decode_op_hdr(xdr, OP_ACCESS);
- if (status)
- return status;
- READ_BUF(8);
- READ32(supp);
- READ32(acc);
- if ((supp & ~access->ac_req_access) || (acc & ~supp)) {
- printk(KERN_NOTICE "NFS: server returned bad bits in access call!\n");
+ *type = 0;
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_TYPE - 1U)))
return -EIO;
+ if (likely(bitmap[0] & FATTR4_WORD0_TYPE)) {
+ READ_BUF(4);
+ READ32(*type);
+ if (*type < NF4REG || *type > NF4NAMEDATTR) {
+ dprintk("%s: bad type %d\n", __FUNCTION__, *type);
+ return -EIO;
+ }
+ bitmap[0] &= ~FATTR4_WORD0_TYPE;
}
- *access->ac_resp_supported = supp;
- *access->ac_resp_access = acc;
+ dprintk("%s: type=0%o\n", __FUNCTION__, nfs_type2fmt[*type].nfs2type);
return 0;
}
-static int
-decode_close(struct xdr_stream *xdr, struct nfs_closeres *res)
+static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change)
{
uint32_t *p;
- int status;
- status = decode_op_hdr(xdr, OP_CLOSE);
- if (status)
- return status;
- READ_BUF(sizeof(res->stateid.data));
- COPYMEM(res->stateid.data, sizeof(res->stateid.data));
+ *change = 0;
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_CHANGE - 1U)))
+ return -EIO;
+ if (likely(bitmap[0] & FATTR4_WORD0_CHANGE)) {
+ READ_BUF(8);
+ READ64(*change);
+ bitmap[0] &= ~FATTR4_WORD0_CHANGE;
+ }
+ dprintk("%s: change attribute=%Lu\n", __FUNCTION__,
+ (unsigned long long)*change);
return 0;
}
-static int
-decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res)
+static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *size)
{
uint32_t *p;
- int status;
- status = decode_op_hdr(xdr, OP_COMMIT);
- if (status)
- return status;
- READ_BUF(8);
- COPYMEM(res->verf->verifier, 8);
+ *size = 0;
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_SIZE - 1U)))
+ return -EIO;
+ if (likely(bitmap[0] & FATTR4_WORD0_SIZE)) {
+ READ_BUF(8);
+ READ64(*size);
+ bitmap[0] &= ~FATTR4_WORD0_SIZE;
+ }
+ dprintk("%s: file size=%Lu\n", __FUNCTION__, (unsigned long long)*size);
return 0;
}
-static int
-decode_create(struct xdr_stream *xdr, struct nfs4_create *create)
+static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
uint32_t *p;
- uint32_t bmlen;
- int status;
- status = decode_op_hdr(xdr, OP_CREATE);
- if (status)
- return status;
- if ((status = decode_change_info(xdr, create->cr_cinfo)))
- return status;
- READ_BUF(4);
- READ32(bmlen);
- READ_BUF(bmlen << 2);
+ *res = 0;
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_LINK_SUPPORT - 1U)))
+ return -EIO;
+ if (likely(bitmap[0] & FATTR4_WORD0_LINK_SUPPORT)) {
+ READ_BUF(4);
+ READ32(*res);
+ bitmap[0] &= ~FATTR4_WORD0_LINK_SUPPORT;
+ }
+ dprintk("%s: link support=%s\n", __FUNCTION__, *res == 0 ? "false" : "true");
return 0;
}
-extern uint32_t nfs4_fattr_bitmap[2];
-extern uint32_t nfs4_fsstat_bitmap[2];
-extern uint32_t nfs4_pathconf_bitmap[2];
+static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
+{
+ uint32_t *p;
+
+ *res = 0;
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_SYMLINK_SUPPORT - 1U)))
+ return -EIO;
+ if (likely(bitmap[0] & FATTR4_WORD0_SYMLINK_SUPPORT)) {
+ READ_BUF(4);
+ READ32(*res);
+ bitmap[0] &= ~FATTR4_WORD0_SYMLINK_SUPPORT;
+ }
+ dprintk("%s: symlink support=%s\n", __FUNCTION__, *res == 0 ? "false" : "true");
+ return 0;
+}
-static int
-decode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr,
- struct nfs_server *server)
+static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fsid *fsid)
{
- struct nfs_fattr *nfp = getattr->gt_attrs;
- struct nfs_fsstat *fsstat = getattr->gt_fsstat;
- struct nfs_pathconf *pathconf = getattr->gt_pathconf;
- uint32_t attrlen, dummy32, bmlen,
- bmval0 = 0,
- bmval1 = 0,
- len = 0;
uint32_t *p;
- unsigned int type;
- int fmode = 0;
- int status;
-
- status = decode_op_hdr(xdr, OP_GETATTR);
- if (status)
- return status;
-
- READ_BUF(4);
- READ32(bmlen);
- if (bmlen > 2)
- goto xdr_error;
-
- READ_BUF((bmlen << 2) + 4);
- if (bmlen > 0)
- READ32(bmval0);
- if (bmlen > 1)
- READ32(bmval1);
- READ32(attrlen);
-
- if ((bmval0 & ~getattr->gt_bmval[0]) ||
- (bmval1 & ~getattr->gt_bmval[1])) {
- dprintk("read_attrs: server returned bad attributes!\n");
- goto xdr_error;
+
+ fsid->major = 0;
+ fsid->minor = 0;
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_FSID - 1U)))
+ return -EIO;
+ if (likely(bitmap[0] & FATTR4_WORD0_FSID)) {
+ READ_BUF(16);
+ READ64(fsid->major);
+ READ64(fsid->minor);
+ bitmap[0] &= ~FATTR4_WORD0_FSID;
}
- if (nfp) {
- nfp->bitmap[0] = bmval0;
- nfp->bitmap[1] = bmval1;
+ dprintk("%s: fsid=(0x%Lx/0x%Lx)\n", __FUNCTION__,
+ (unsigned long long)fsid->major,
+ (unsigned long long)fsid->minor);
+ return 0;
+}
+
+static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
+{
+ uint32_t *p;
+
+ *res = 60;
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_LEASE_TIME - 1U)))
+ return -EIO;
+ if (likely(bitmap[0] & FATTR4_WORD0_LEASE_TIME)) {
+ READ_BUF(4);
+ READ32(*res);
+ bitmap[0] &= ~FATTR4_WORD0_LEASE_TIME;
}
+ dprintk("%s: file size=%u\n", __FUNCTION__, (unsigned int)*res);
+ return 0;
+}
- /*
- * In case the server doesn't return some attributes,
- * we initialize them here to some nominal values..
- */
- if (nfp) {
- nfp->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4;
- nfp->nlink = 1;
- nfp->timestamp = jiffies;
+static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
+{
+ uint32_t *p;
+
+ *res = ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL;
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_ACLSUPPORT - 1U)))
+ return -EIO;
+ if (likely(bitmap[0] & FATTR4_WORD0_ACLSUPPORT)) {
+ READ_BUF(4);
+ READ32(*res);
+ bitmap[0] &= ~FATTR4_WORD0_ACLSUPPORT;
+ }
+ dprintk("%s: ACLs supported=%u\n", __FUNCTION__, (unsigned int)*res);
+ return 0;
+}
+
+static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
+{
+ uint32_t *p;
+
+ *fileid = 0;
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEID - 1U)))
+ return -EIO;
+ if (likely(bitmap[0] & FATTR4_WORD0_FILEID)) {
+ READ_BUF(8);
+ READ64(*fileid);
+ bitmap[0] &= ~FATTR4_WORD0_FILEID;
}
- if (bmval0 & FATTR4_WORD0_TYPE) {
- READ_BUF(4);
- len += 4;
- READ32(type);
- if (type < NF4REG || type > NF4NAMEDATTR) {
- dprintk("read_attrs: bad type %d\n", type);
- goto xdr_error;
- }
- nfp->type = nfs_type2fmt[type].nfs2type;
- fmode = nfs_type2fmt[type].mode;
- dprintk("read_attrs: type=%d\n", (uint32_t)nfp->type);
- }
- if (bmval0 & FATTR4_WORD0_CHANGE) {
- READ_BUF(8);
- len += 8;
- READ64(nfp->change_attr);
- dprintk("read_attrs: changeid=%Ld\n", (long long)nfp->change_attr);
- }
- if (bmval0 & FATTR4_WORD0_SIZE) {
- READ_BUF(8);
- len += 8;
- READ64(nfp->size);
- dprintk("read_attrs: size=%Ld\n", (long long)nfp->size);
- }
- if (bmval0 & FATTR4_WORD0_FSID) {
- READ_BUF(16);
- len += 16;
- READ64(nfp->fsid_u.nfs4.major);
- READ64(nfp->fsid_u.nfs4.minor);
- dprintk("read_attrs: fsid=0x%Lx/0x%Lx\n",
- (long long)nfp->fsid_u.nfs4.major,
- (long long)nfp->fsid_u.nfs4.minor);
- }
- if (bmval0 & FATTR4_WORD0_FILEID) {
- READ_BUF(8);
- len += 8;
- READ64(nfp->fileid);
- dprintk("read_attrs: fileid=%Ld\n", (long long) nfp->fileid);
- }
- if (bmval0 & FATTR4_WORD0_FILES_AVAIL) {
+ dprintk("%s: fileid=%Lu\n", __FUNCTION__, (unsigned long long)*fileid);
+ return 0;
+}
+
+static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
+{
+ uint32_t *p;
+ int status = 0;
+
+ *res = 0;
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_AVAIL - 1U)))
+ return -EIO;
+ if (likely(bitmap[0] & FATTR4_WORD0_FILES_AVAIL)) {
READ_BUF(8);
- len += 8;
- READ64(fsstat->afiles);
- dprintk("read_attrs: files_avail=0x%Lx\n", (long long) fsstat->afiles);
+ READ64(*res);
+ bitmap[0] &= ~FATTR4_WORD0_FILES_AVAIL;
+ }
+ dprintk("%s: files avail=%Lu\n", __FUNCTION__, (unsigned long long)*res);
+ return status;
+}
+
+static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
+{
+ uint32_t *p;
+ int status = 0;
+
+ *res = 0;
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_FREE - 1U)))
+ return -EIO;
+ if (likely(bitmap[0] & FATTR4_WORD0_FILES_FREE)) {
+ READ_BUF(8);
+ READ64(*res);
+ bitmap[0] &= ~FATTR4_WORD0_FILES_FREE;
+ }
+ dprintk("%s: files free=%Lu\n", __FUNCTION__, (unsigned long long)*res);
+ return status;
+}
+
+static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
+{
+ uint32_t *p;
+ int status = 0;
+
+ *res = 0;
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_TOTAL - 1U)))
+ return -EIO;
+ if (likely(bitmap[0] & FATTR4_WORD0_FILES_TOTAL)) {
+ READ_BUF(8);
+ READ64(*res);
+ bitmap[0] &= ~FATTR4_WORD0_FILES_TOTAL;
}
- if (bmval0 & FATTR4_WORD0_FILES_FREE) {
- READ_BUF(8);
- len += 8;
- READ64(fsstat->ffiles);
- dprintk("read_attrs: files_free=0x%Lx\n", (long long) fsstat->ffiles);
- }
- if (bmval0 & FATTR4_WORD0_FILES_TOTAL) {
- READ_BUF(8);
- len += 8;
- READ64(fsstat->tfiles);
- dprintk("read_attrs: files_tot=0x%Lx\n", (long long) fsstat->tfiles);
- }
- if (bmval0 & FATTR4_WORD0_MAXLINK) {
+ dprintk("%s: files total=%Lu\n", __FUNCTION__, (unsigned long long)*res);
+ return status;
+}
+
+static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
+{
+ uint32_t *p;
+ int status = 0;
+
+ *res = 0;
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXFILESIZE - 1U)))
+ return -EIO;
+ if (likely(bitmap[0] & FATTR4_WORD0_MAXFILESIZE)) {
+ READ_BUF(8);
+ READ64(*res);
+ bitmap[0] &= ~FATTR4_WORD0_MAXFILESIZE;
+ }
+ dprintk("%s: maxfilesize=%Lu\n", __FUNCTION__, (unsigned long long)*res);
+ return status;
+}
+
+static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxlink)
+{
+ uint32_t *p;
+ int status = 0;
+
+ *maxlink = 1;
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXLINK - 1U)))
+ return -EIO;
+ if (likely(bitmap[0] & FATTR4_WORD0_MAXLINK)) {
READ_BUF(4);
- len += 4;
- READ32(pathconf->max_link);
- dprintk("read_attrs: maxlink=%d\n", pathconf->max_link);
+ READ32(*maxlink);
+ bitmap[0] &= ~FATTR4_WORD0_MAXLINK;
}
- if (bmval0 & FATTR4_WORD0_MAXNAME) {
- READ_BUF(4);
- len += 4;
- READ32(pathconf->max_namelen);
- dprintk("read_attrs: maxname=%d\n", pathconf->max_namelen);
- }
-
- if (bmval1 & FATTR4_WORD1_MODE) {
- READ_BUF(4);
- len += 4;
- READ32(dummy32);
- nfp->mode = (dummy32 & ~S_IFMT) | fmode;
- dprintk("read_attrs: mode=0%o\n", nfp->mode);
- }
- if (bmval1 & FATTR4_WORD1_NUMLINKS) {
- READ_BUF(4);
- len += 4;
- READ32(nfp->nlink);
- dprintk("read_attrs: nlinks=0%o\n", nfp->nlink);
- }
- if (bmval1 & FATTR4_WORD1_OWNER) {
- READ_BUF(4);
- len += 4;
- READ32(dummy32); /* name length */
- if (dummy32 > XDR_MAX_NETOBJ) {
- dprintk("read_attrs: name too long!\n");
- goto xdr_error;
- }
- READ_BUF(dummy32);
- len += (XDR_QUADLEN(dummy32) << 2);
- if ((status = nfs_map_name_to_uid(server->nfs4_state, (char *)p, dummy32,
- &nfp->uid)) < 0) {
- dprintk("read_attrs: name-to-uid mapping failed!\n");
- nfp->uid = -2;
- }
- dprintk("read_attrs: uid=%d\n", (int)nfp->uid);
- }
- if (bmval1 & FATTR4_WORD1_OWNER_GROUP) {
- READ_BUF(4);
- len += 4;
- READ32(dummy32);
- if (dummy32 > XDR_MAX_NETOBJ) {
- dprintk("read_attrs: name too long!\n");
- goto xdr_error;
- }
- READ_BUF(dummy32);
- len += (XDR_QUADLEN(dummy32) << 2);
- if ((status = nfs_map_group_to_gid(server->nfs4_state, (char *)p, dummy32,
- &nfp->gid)) < 0) {
- dprintk("read_attrs: group-to-gid mapping failed!\n");
- nfp->gid = -2;
- }
- dprintk("read_attrs: gid=%d\n", (int)nfp->gid);
- }
- if (bmval1 & FATTR4_WORD1_RAWDEV) {
- uint32_t major, minor;
+ dprintk("%s: maxlink=%u\n", __FUNCTION__, *maxlink);
+ return status;
+}
+
+static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxname)
+{
+ uint32_t *p;
+ int status = 0;
+
+ *maxname = 1024;
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXNAME - 1U)))
+ return -EIO;
+ if (likely(bitmap[0] & FATTR4_WORD0_MAXNAME)) {
+ READ_BUF(4);
+ READ32(*maxname);
+ bitmap[0] &= ~FATTR4_WORD0_MAXNAME;
+ }
+ dprintk("%s: maxname=%u\n", __FUNCTION__, *maxname);
+ return status;
+}
+
+static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
+{
+ uint32_t *p;
+ int status = 0;
+
+ *res = 1024;
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXREAD - 1U)))
+ return -EIO;
+ if (likely(bitmap[0] & FATTR4_WORD0_MAXREAD)) {
+ uint64_t maxread;
+ READ_BUF(8);
+ READ64(maxread);
+ if (maxread > 0x7FFFFFFF)
+ maxread = 0x7FFFFFFF;
+ *res = (uint32_t)maxread;
+ bitmap[0] &= ~FATTR4_WORD0_MAXREAD;
+ }
+ dprintk("%s: maxread=%lu\n", __FUNCTION__, (unsigned long)*res);
+ return status;
+}
+
+static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
+{
+ uint32_t *p;
+ int status = 0;
+
+ *res = 1024;
+ if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXWRITE - 1U)))
+ return -EIO;
+ if (likely(bitmap[0] & FATTR4_WORD0_MAXWRITE)) {
+ uint64_t maxwrite;
+ READ_BUF(8);
+ READ64(maxwrite);
+ if (maxwrite > 0x7FFFFFFF)
+ maxwrite = 0x7FFFFFFF;
+ *res = (uint32_t)maxwrite;
+ bitmap[0] &= ~FATTR4_WORD0_MAXWRITE;
+ }
+ dprintk("%s: maxwrite=%lu\n", __FUNCTION__, (unsigned long)*res);
+ return status;
+}
+
+static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *mode)
+{
+ uint32_t *p;
+
+ *mode = 0;
+ if (unlikely(bitmap[1] & (FATTR4_WORD1_MODE - 1U)))
+ return -EIO;
+ if (likely(bitmap[1] & FATTR4_WORD1_MODE)) {
+ READ_BUF(4);
+ READ32(*mode);
+ *mode &= ~S_IFMT;
+ bitmap[1] &= ~FATTR4_WORD1_MODE;
+ }
+ dprintk("%s: file mode=0%o\n", __FUNCTION__, (unsigned int)*mode);
+ return 0;
+}
+
+static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *nlink)
+{
+ uint32_t *p;
+
+ *nlink = 1;
+ if (unlikely(bitmap[1] & (FATTR4_WORD1_NUMLINKS - 1U)))
+ return -EIO;
+ if (likely(bitmap[1] & FATTR4_WORD1_NUMLINKS)) {
+ READ_BUF(4);
+ READ32(*nlink);
+ bitmap[1] &= ~FATTR4_WORD1_NUMLINKS;
+ }
+ dprintk("%s: nlink=%u\n", __FUNCTION__, (unsigned int)*nlink);
+ return 0;
+}
+
+static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_client *clp, int32_t *uid)
+{
+ uint32_t len, *p;
+
+ *uid = -2;
+ if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER - 1U)))
+ return -EIO;
+ if (likely(bitmap[1] & FATTR4_WORD1_OWNER)) {
+ READ_BUF(4);
+ READ32(len);
+ READ_BUF(len);
+ if (len < XDR_MAX_NETOBJ) {
+ if (nfs_map_name_to_uid(clp, (char *)p, len, uid) != 0)
+ dprintk("%s: nfs_map_name_to_uid failed!\n",
+ __FUNCTION__);
+ } else
+ printk(KERN_WARNING "%s: name too long (%u)!\n",
+ __FUNCTION__, len);
+ bitmap[1] &= ~FATTR4_WORD1_OWNER;
+ }
+ dprintk("%s: uid=%d\n", __FUNCTION__, (int)*uid);
+ return 0;
+}
+
+static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_client *clp, int32_t *gid)
+{
+ uint32_t len, *p;
+
+ *gid = -2;
+ if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER_GROUP - 1U)))
+ return -EIO;
+ if (likely(bitmap[1] & FATTR4_WORD1_OWNER_GROUP)) {
+ READ_BUF(4);
+ READ32(len);
+ READ_BUF(len);
+ if (len < XDR_MAX_NETOBJ) {
+ if (nfs_map_group_to_gid(clp, (char *)p, len, gid) != 0)
+ dprintk("%s: nfs_map_group_to_gid failed!\n",
+ __FUNCTION__);
+ } else
+ printk(KERN_WARNING "%s: name too long (%u)!\n",
+ __FUNCTION__, len);
+ bitmap[1] &= ~FATTR4_WORD1_OWNER_GROUP;
+ }
+ dprintk("%s: gid=%d\n", __FUNCTION__, (int)*gid);
+ return 0;
+}
+
+static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rdev)
+{
+ uint32_t major = 0, minor = 0, *p;
+
+ *rdev = MKDEV(0,0);
+ if (unlikely(bitmap[1] & (FATTR4_WORD1_RAWDEV - 1U)))
+ return -EIO;
+ if (likely(bitmap[1] & FATTR4_WORD1_RAWDEV)) {
+ dev_t tmp;
READ_BUF(8);
- len += 8;
READ32(major);
READ32(minor);
- nfp->rdev = MKDEV(major, minor);
- if (MAJOR(nfp->rdev) != major || MINOR(nfp->rdev) != minor)
- nfp->rdev = 0;
- dprintk("read_attrs: rdev=%u:%u\n", major, minor);
- }
- if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) {
- READ_BUF(8);
- len += 8;
- READ64(fsstat->abytes);
- dprintk("read_attrs: savail=0x%Lx\n", (long long) fsstat->abytes);
- }
- if (bmval1 & FATTR4_WORD1_SPACE_FREE) {
- READ_BUF(8);
- len += 8;
- READ64(fsstat->fbytes);
- dprintk("read_attrs: sfree=0x%Lx\n", (long long) fsstat->fbytes);
- }
- if (bmval1 & FATTR4_WORD1_SPACE_TOTAL) {
- READ_BUF(8);
- len += 8;
- READ64(fsstat->tbytes);
- dprintk("read_attrs: stotal=0x%Lx\n", (long long) fsstat->tbytes);
- }
- if (bmval1 & FATTR4_WORD1_SPACE_USED) {
- READ_BUF(8);
- len += 8;
- READ64(nfp->du.nfs3.used);
- dprintk("read_attrs: sused=0x%Lx\n", (long long) nfp->du.nfs3.used);
- }
- if (bmval1 & FATTR4_WORD1_TIME_ACCESS) {
- READ_BUF(12);
- len += 12;
- READTIME(nfp->atime);
- dprintk("read_attrs: atime=%ld\n", (long)nfp->atime.tv_sec);
- }
- if (bmval1 & FATTR4_WORD1_TIME_METADATA) {
- READ_BUF(12);
- len += 12;
- READTIME(nfp->ctime);
- dprintk("read_attrs: ctime=%ld\n", (long)nfp->ctime.tv_sec);
- }
- if (bmval1 & FATTR4_WORD1_TIME_MODIFY) {
- READ_BUF(12);
- len += 12;
- READTIME(nfp->mtime);
- dprintk("read_attrs: mtime=%ld\n", (long)nfp->mtime.tv_sec);
- }
- if (len != attrlen)
- goto xdr_error;
-
- DECODE_TAIL;
+ tmp = MKDEV(major, minor);
+ if (MAJOR(tmp) == major && MINOR(tmp) == minor)
+ *rdev = tmp;
+ bitmap[1] &= ~ FATTR4_WORD1_RAWDEV;
+ }
+ dprintk("%s: rdev=(0x%x:0x%x)\n", __FUNCTION__, major, minor);
+ return 0;
}
-static int
-decode_change_attr(struct xdr_stream *xdr, uint64_t *change_attr)
+static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
uint32_t *p;
- uint32_t attrlen, bmlen, bmval = 0;
- int status;
+ int status = 0;
- status = decode_op_hdr(xdr, OP_GETATTR);
- if (status)
- return status;
- READ_BUF(4);
- READ32(bmlen);
- if (bmlen < 1)
+ *res = 0;
+ if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_AVAIL - 1U)))
return -EIO;
- READ_BUF(bmlen << 2);
- READ32(bmval);
- if (bmval != FATTR4_WORD0_CHANGE) {
- printk(KERN_NOTICE "decode_change_attr: server returned bad attribute bitmap 0x%x\n",
- (unsigned int)bmval);
+ if (likely(bitmap[1] & FATTR4_WORD1_SPACE_AVAIL)) {
+ READ_BUF(8);
+ READ64(*res);
+ bitmap[1] &= ~FATTR4_WORD1_SPACE_AVAIL;
+ }
+ dprintk("%s: space avail=%Lu\n", __FUNCTION__, (unsigned long long)*res);
+ return status;
+}
+
+static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
+{
+ uint32_t *p;
+ int status = 0;
+
+ *res = 0;
+ if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_FREE - 1U)))
return -EIO;
+ if (likely(bitmap[1] & FATTR4_WORD1_SPACE_FREE)) {
+ READ_BUF(8);
+ READ64(*res);
+ bitmap[1] &= ~FATTR4_WORD1_SPACE_FREE;
}
- READ_BUF(4);
- READ32(attrlen);
- READ_BUF(attrlen);
- if (attrlen < 8) {
- printk(KERN_NOTICE "decode_change_attr: server returned bad attribute length %u\n",
- (unsigned int)attrlen);
+ dprintk("%s: space free=%Lu\n", __FUNCTION__, (unsigned long long)*res);
+ return status;
+}
+
+static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
+{
+ uint32_t *p;
+ int status = 0;
+
+ *res = 0;
+ if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_TOTAL - 1U)))
return -EIO;
+ if (likely(bitmap[1] & FATTR4_WORD1_SPACE_TOTAL)) {
+ READ_BUF(8);
+ READ64(*res);
+ bitmap[1] &= ~FATTR4_WORD1_SPACE_TOTAL;
}
- READ64(*change_attr);
+ dprintk("%s: space total=%Lu\n", __FUNCTION__, (unsigned long long)*res);
+ return status;
+}
+
+static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *used)
+{
+ uint32_t *p;
+
+ *used = 0;
+ if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_USED - 1U)))
+ return -EIO;
+ if (likely(bitmap[1] & FATTR4_WORD1_SPACE_USED)) {
+ READ_BUF(8);
+ READ64(*used);
+ bitmap[1] &= ~FATTR4_WORD1_SPACE_USED;
+ }
+ dprintk("%s: space used=%Lu\n", __FUNCTION__,
+ (unsigned long long)*used);
return 0;
}
-static int
-decode_read_getattr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
+static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time)
{
uint32_t *p;
- uint32_t attrlen, bmlen, bmval0 = 0, bmval1 = 0;
- int status;
+ uint64_t sec;
+ uint32_t nsec;
+
+ READ_BUF(12);
+ READ64(sec);
+ READ32(nsec);
+ time->tv_sec = (time_t)sec;
+ time->tv_nsec = (long)nsec;
+ return 0;
+}
- status = decode_op_hdr(xdr, OP_GETATTR);
- if (status)
- return status;
- READ_BUF(4);
- READ32(bmlen);
- if (bmlen < 1)
+static int decode_attr_time_access(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
+{
+ int status = 0;
+
+ time->tv_sec = 0;
+ time->tv_nsec = 0;
+ if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_ACCESS - 1U)))
return -EIO;
- READ_BUF(bmlen << 2);
- READ32(bmval0);
- if (bmval0 != FATTR4_WORD0_CHANGE)
- goto out_bad_bitmap;
- if (bmlen > 1) {
- READ32(bmval1);
- if (bmval1 & ~(FATTR4_WORD1_TIME_ACCESS))
- goto out_bad_bitmap;
+ if (likely(bitmap[1] & FATTR4_WORD1_TIME_ACCESS)) {
+ status = decode_attr_time(xdr, time);
+ bitmap[1] &= ~FATTR4_WORD1_TIME_ACCESS;
}
- READ_BUF(4);
- READ32(attrlen);
- READ_BUF(attrlen);
- if (attrlen < 16) {
- printk(KERN_NOTICE "decode_post_write_getattr: server returned bad attribute length %u\n",
- (unsigned int)attrlen);
+ dprintk("%s: atime=%ld\n", __FUNCTION__, (long)time->tv_sec);
+ return status;
+}
+
+static int decode_attr_time_metadata(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
+{
+ int status = 0;
+
+ time->tv_sec = 0;
+ time->tv_nsec = 0;
+ if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_METADATA - 1U)))
+ return -EIO;
+ if (likely(bitmap[1] & FATTR4_WORD1_TIME_METADATA)) {
+ status = decode_attr_time(xdr, time);
+ bitmap[1] &= ~FATTR4_WORD1_TIME_METADATA;
+ }
+ dprintk("%s: ctime=%ld\n", __FUNCTION__, (long)time->tv_sec);
+ return status;
+}
+
+static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
+{
+ int status = 0;
+
+ time->tv_sec = 0;
+ time->tv_nsec = 0;
+ if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_MODIFY - 1U)))
+ return -EIO;
+ if (likely(bitmap[1] & FATTR4_WORD1_TIME_MODIFY)) {
+ status = decode_attr_time(xdr, time);
+ bitmap[1] &= ~FATTR4_WORD1_TIME_MODIFY;
+ }
+ dprintk("%s: mtime=%ld\n", __FUNCTION__, (long)time->tv_sec);
+ return status;
+}
+
+static int verify_attr_len(struct xdr_stream *xdr, uint32_t *savep, uint32_t attrlen)
+{
+ unsigned int attrwords = XDR_QUADLEN(attrlen);
+ unsigned int nwords = xdr->p - savep;
+
+ if (unlikely(attrwords != nwords)) {
+ printk(KERN_WARNING "%s: server returned incorrect attribute length: %u %c %u\n",
+ __FUNCTION__,
+ attrwords << 2,
+ (attrwords < nwords) ? '<' : '>',
+ nwords << 2);
return -EIO;
}
- READ64(fattr->change_attr);
- if (bmval1 & FATTR4_WORD1_TIME_ACCESS)
- READTIME(fattr->atime);
- fattr->bitmap[0] = bmval0;
- fattr->bitmap[1] = bmval1;
return 0;
-out_bad_bitmap:
- printk(KERN_NOTICE "decode_read_getattr: server returned bad attribute bitmap 0x%x/0x%x\n",
- (unsigned int)bmval0, (unsigned int)bmval1);
- return -EIO;
}
-static int
-decode_pre_write_getattr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
+static int decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
{
- return decode_change_attr(xdr, &fattr->pre_change_attr);
+ uint32_t *p;
+
+ READ_BUF(20);
+ READ32(cinfo->atomic);
+ READ64(cinfo->before);
+ READ64(cinfo->after);
+ return 0;
}
-static int
-decode_post_write_getattr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
+static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access)
{
uint32_t *p;
- uint32_t attrlen, bmlen, bmval0 = 0, bmval1 = 0;
+ uint32_t supp, acc;
int status;
- status = decode_op_hdr(xdr, OP_GETATTR);
+ status = decode_op_hdr(xdr, OP_ACCESS);
if (status)
return status;
- READ_BUF(4);
- READ32(bmlen);
- if (bmlen < 1)
- return -EIO;
- READ_BUF(bmlen << 2);
- READ32(bmval0);
- if (bmval0 != (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE))
- goto out_bad_bitmap;
- if (bmlen > 1) {
- READ32(bmval1);
- if (bmval1 & ~(FATTR4_WORD1_SPACE_USED |
- FATTR4_WORD1_TIME_METADATA |
- FATTR4_WORD1_TIME_MODIFY))
- goto out_bad_bitmap;
- }
- READ_BUF(4);
- READ32(attrlen);
- READ_BUF(attrlen);
- if (attrlen < 16) {
- printk(KERN_NOTICE "decode_post_write_getattr: server returned bad attribute length %u\n",
- (unsigned int)attrlen);
- return -EIO;
- }
- READ64(fattr->change_attr);
- READ64(fattr->size);
- if (bmval1 & FATTR4_WORD1_SPACE_USED)
- READ64(fattr->du.nfs3.used);
- if (bmval1 & FATTR4_WORD1_TIME_METADATA)
- READTIME(fattr->ctime);
- if (bmval1 & FATTR4_WORD1_TIME_MODIFY)
- READTIME(fattr->mtime);
- fattr->bitmap[0] = bmval0;
- fattr->bitmap[1] = bmval1;
+ READ_BUF(8);
+ READ32(supp);
+ READ32(acc);
+ access->supported = supp;
+ access->access = acc;
return 0;
-out_bad_bitmap:
- printk(KERN_NOTICE "decode_post_write_getattr: server returned bad attribute bitmap 0x%x/0x%x\n",
- (unsigned int)bmval0, (unsigned int)bmval1);
- return -EIO;
}
+static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res)
+{
+ uint32_t *p;
+ int status;
-static int
-decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
+ status = decode_op_hdr(xdr, OP_CLOSE);
+ if (status)
+ return status;
+ READ_BUF(sizeof(res->stateid.data));
+ COPYMEM(res->stateid.data, sizeof(res->stateid.data));
+ return 0;
+}
+
+static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res)
+{
+ uint32_t *p;
+ int status;
+
+ status = decode_op_hdr(xdr, OP_COMMIT);
+ if (status)
+ return status;
+ READ_BUF(8);
+ COPYMEM(res->verf->verifier, 8);
+ return 0;
+}
+
+static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
{
uint32_t *p;
- uint32_t len, attrlen, bmlen, bmval0 = 0, bmval1 = 0;
+ uint32_t bmlen;
int status;
- status = decode_op_hdr(xdr, OP_GETATTR);
+ status = decode_op_hdr(xdr, OP_CREATE);
if (status)
return status;
+ if ((status = decode_change_info(xdr, cinfo)))
+ return status;
READ_BUF(4);
READ32(bmlen);
- if (bmlen < 1)
- return -EIO;
READ_BUF(bmlen << 2);
- READ32(bmval0);
- if (bmval0 & ~(FATTR4_WORD0_MAXFILESIZE|FATTR4_WORD0_MAXREAD|
- FATTR4_WORD0_MAXWRITE|FATTR4_WORD0_LEASE_TIME))
- goto out_bad_bitmap;
- if (bmlen > 1) {
- READ32(bmval1);
- if (bmval1 != 0 || bmlen > 2)
- goto out_bad_bitmap;
+ return 0;
+}
+
+static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res)
+{
+ uint32_t *savep;
+ uint32_t attrlen,
+ bitmap[2] = {0};
+ int status;
+
+ if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_supported(xdr, bitmap, res->attr_bitmask)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_link_support(xdr, bitmap, &res->has_links)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_symlink_support(xdr, bitmap, &res->has_symlinks)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_aclsupport(xdr, bitmap, &res->acl_bitmask)) != 0)
+ goto xdr_error;
+ status = verify_attr_len(xdr, savep, attrlen);
+xdr_error:
+ if (status != 0)
+ printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status);
+ return status;
+}
+
+static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat)
+{
+ uint32_t *savep;
+ uint32_t attrlen,
+ bitmap[2] = {0};
+ int status;
+
+ if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
+ goto xdr_error;
+
+ if ((status = decode_attr_files_avail(xdr, bitmap, &fsstat->afiles)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_files_free(xdr, bitmap, &fsstat->ffiles)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_files_total(xdr, bitmap, &fsstat->tfiles)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_space_avail(xdr, bitmap, &fsstat->abytes)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_space_free(xdr, bitmap, &fsstat->fbytes)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_space_total(xdr, bitmap, &fsstat->tbytes)) != 0)
+ goto xdr_error;
+
+ status = verify_attr_len(xdr, savep, attrlen);
+xdr_error:
+ if (status != 0)
+ printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status);
+ return status;
+}
+
+static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf)
+{
+ uint32_t *savep;
+ uint32_t attrlen,
+ bitmap[2] = {0};
+ int status;
+
+ if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
+ goto xdr_error;
+
+ if ((status = decode_attr_maxlink(xdr, bitmap, &pathconf->max_link)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_maxname(xdr, bitmap, &pathconf->max_namelen)) != 0)
+ goto xdr_error;
+
+ status = verify_attr_len(xdr, savep, attrlen);
+xdr_error:
+ if (status != 0)
+ printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status);
+ return status;
+}
+
+static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, const struct nfs_server *server)
+{
+ uint32_t *savep;
+ uint32_t attrlen,
+ bitmap[2] = {0},
+ type;
+ int status, fmode = 0;
+
+ if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
+ goto xdr_error;
+
+ fattr->bitmap[0] = bitmap[0];
+ fattr->bitmap[1] = bitmap[1];
+
+ if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
+ goto xdr_error;
+
+
+ if ((status = decode_attr_type(xdr, bitmap, &type)) != 0)
+ goto xdr_error;
+ fattr->type = nfs_type2fmt[type].nfs2type;
+ fmode = nfs_type2fmt[type].mode;
+
+ if ((status = decode_attr_change(xdr, bitmap, &fattr->change_attr)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_size(xdr, bitmap, &fattr->size)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_fsid(xdr, bitmap, &fattr->fsid_u.nfs4)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_fileid(xdr, bitmap, &fattr->fileid)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_mode(xdr, bitmap, &fattr->mode)) != 0)
+ goto xdr_error;
+ fattr->mode |= fmode;
+ if ((status = decode_attr_nlink(xdr, bitmap, &fattr->nlink)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_owner(xdr, bitmap, server->nfs4_state, &fattr->uid)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_group(xdr, bitmap, server->nfs4_state, &fattr->gid)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_rdev(xdr, bitmap, &fattr->rdev)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_space_used(xdr, bitmap, &fattr->du.nfs3.used)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_time_access(xdr, bitmap, &fattr->atime)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_time_metadata(xdr, bitmap, &fattr->ctime)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime)) != 0)
+ goto xdr_error;
+ if ((status = verify_attr_len(xdr, savep, attrlen)) == 0) {
+ fattr->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4;
+ fattr->timestamp = jiffies;
}
- READ_BUF(4);
- READ32(attrlen);
- READ_BUF(attrlen);
+xdr_error:
+ if (status != 0)
+ printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status);
+ return status;
+}
+
+
+static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
+{
+ uint32_t *savep;
+ uint32_t attrlen, bitmap[2];
+ int status;
+
+ if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
+ goto xdr_error;
+
fsinfo->rtmult = fsinfo->wtmult = 512; /* ??? */
- fsinfo->lease_time = 60;
- len = attrlen;
- if (bmval0 & FATTR4_WORD0_LEASE_TIME) {
- len -= 4;
- READ32(fsinfo->lease_time);
- dprintk("read_attrs: lease_time=%d\n", fsinfo->lease_time);
- }
- if (bmval0 & FATTR4_WORD0_MAXFILESIZE) {
- len -= 8;
- READ64(fsinfo->maxfilesize);
- dprintk("read_attrs: maxfilesize=0x%Lx\n", (long long) fsinfo->maxfilesize);
- }
- if (bmval0 & FATTR4_WORD0_MAXREAD) {
- len -= 8;
- READ64(fsinfo->rtmax);
- fsinfo->rtpref = fsinfo->dtpref = fsinfo->rtmax;
- dprintk("read_attrs: maxread=%d\n", fsinfo->rtmax);
- }
- if (bmval0 & FATTR4_WORD0_MAXWRITE) {
- len -= 8;
- READ64(fsinfo->wtmax);
- fsinfo->wtpref = fsinfo->wtmax;
- dprintk("read_attrs: maxwrite=%d\n", fsinfo->wtmax);
- }
- if (len != 0)
- goto out_bad_attrlen;
- return 0;
-out_bad_attrlen:
- printk(KERN_NOTICE "%s: server attribute length %u does not match bitmap 0x%x/0x%x\n",
- __FUNCTION__, (unsigned int)attrlen,
- (unsigned int) bmval0, (unsigned int)bmval1);
- return -EIO;
-out_bad_bitmap:
- printk(KERN_NOTICE "%s: server returned bad attribute bitmap 0x%x/0x%x\n",
- __FUNCTION__,
- (unsigned int)bmval0, (unsigned int)bmval1);
- return -EIO;
+ if ((status = decode_attr_lease_time(xdr, bitmap, &fsinfo->lease_time)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_maxfilesize(xdr, bitmap, &fsinfo->maxfilesize)) != 0)
+ goto xdr_error;
+ if ((status = decode_attr_maxread(xdr, bitmap, &fsinfo->rtmax)) != 0)
+ goto xdr_error;
+ fsinfo->rtpref = fsinfo->dtpref = fsinfo->rtmax;
+ if ((status = decode_attr_maxwrite(xdr, bitmap, &fsinfo->wtmax)) != 0)
+ goto xdr_error;
+ fsinfo->wtpref = fsinfo->wtmax;
+
+ status = verify_attr_len(xdr, savep, attrlen);
+xdr_error:
+ if (status != 0)
+ printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status);
+ return status;
}
-static int
-decode_getfh(struct xdr_stream *xdr, struct nfs4_getfh *getfh)
+static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh)
{
- struct nfs_fh *fh = getfh->gf_fhandle;
uint32_t *p;
uint32_t len;
int status;
@@ -2152,7 +2637,7 @@ decode_getfh(struct xdr_stream *xdr, struct nfs4_getfh *getfh)
READ_BUF(4);
READ32(len);
- if (len > NFS_MAXFHSIZE)
+ if (len > NFS4_FHSIZE)
return -EIO;
fh->size = len;
READ_BUF(len);
@@ -2160,22 +2645,20 @@ decode_getfh(struct xdr_stream *xdr, struct nfs4_getfh *getfh)
return 0;
}
-static int
-decode_link(struct xdr_stream *xdr, struct nfs4_link *link)
+static int decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
{
int status;
status = decode_op_hdr(xdr, OP_LINK);
if (status)
return status;
- return decode_change_info(xdr, link->ln_cinfo);
+ return decode_change_info(xdr, cinfo);
}
/*
* We create the owner, so we know a proper owner.id length is 4.
*/
-static int
-decode_lock_denied (struct xdr_stream *xdr, struct nfs_lock_denied *denied)
+static int decode_lock_denied (struct xdr_stream *xdr, struct nfs_lock_denied *denied)
{
uint32_t *p;
uint32_t namelen;
@@ -2192,8 +2675,7 @@ decode_lock_denied (struct xdr_stream *xdr, struct nfs_lock_denied *denied)
return -NFS4ERR_DENIED;
}
-static int
-decode_lock(struct xdr_stream *xdr, struct nfs_lockres *res)
+static int decode_lock(struct xdr_stream *xdr, struct nfs_lockres *res)
{
uint32_t *p;
int status;
@@ -2207,8 +2689,7 @@ decode_lock(struct xdr_stream *xdr, struct nfs_lockres *res)
return status;
}
-static int
-decode_lockt(struct xdr_stream *xdr, struct nfs_lockres *res)
+static int decode_lockt(struct xdr_stream *xdr, struct nfs_lockres *res)
{
int status;
status = decode_op_hdr(xdr, OP_LOCKT);
@@ -2217,8 +2698,7 @@ decode_lockt(struct xdr_stream *xdr, struct nfs_lockres *res)
return status;
}
-static int
-decode_locku(struct xdr_stream *xdr, struct nfs_lockres *res)
+static int decode_locku(struct xdr_stream *xdr, struct nfs_lockres *res)
{
uint32_t *p;
int status;
@@ -2231,14 +2711,12 @@ decode_locku(struct xdr_stream *xdr, struct nfs_lockres *res)
return status;
}
-static int
-decode_lookup(struct xdr_stream *xdr)
+static int decode_lookup(struct xdr_stream *xdr)
{
return decode_op_hdr(xdr, OP_LOOKUP);
}
-static int
-decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
+static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
{
uint32_t *p;
uint32_t bmlen, delegation_type;
@@ -2250,7 +2728,7 @@ decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
READ_BUF(sizeof(res->stateid.data));
COPYMEM(res->stateid.data, sizeof(res->stateid.data));
- decode_change_info(xdr, res->cinfo);
+ decode_change_info(xdr, &res->cinfo);
READ_BUF(8);
READ32(res->rflags);
@@ -2261,14 +2739,14 @@ decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
READ_BUF((bmlen << 2) + 4);
p += bmlen;
READ32(delegation_type);
- if (delegation_type != NFS4_OPEN_DELEGATE_NONE)
- goto xdr_error;
-
- DECODE_TAIL;
+ if (delegation_type == NFS4_OPEN_DELEGATE_NONE)
+ return 0;
+xdr_error:
+ printk(KERN_NOTICE "%s: xdr error!\n", __FUNCTION__);
+ return -EIO;
}
-static int
-decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res)
+static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res)
{
uint32_t *p;
int status;
@@ -2281,8 +2759,7 @@ decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res)
return 0;
}
-static int
-decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *res)
+static int decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *res)
{
uint32_t *p;
int status;
@@ -2295,22 +2772,19 @@ decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *res)
return 0;
}
-static int
-decode_putfh(struct xdr_stream *xdr)
+static int decode_putfh(struct xdr_stream *xdr)
{
return decode_op_hdr(xdr, OP_PUTFH);
}
-static int
-decode_putrootfh(struct xdr_stream *xdr)
+static int decode_putrootfh(struct xdr_stream *xdr)
{
return decode_op_hdr(xdr, OP_PUTROOTFH);
}
-static int
-decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res)
+static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res)
{
- struct iovec *iov = req->rq_rvec;
+ struct iovec *iov = req->rq_rcv_buf.head;
uint32_t *p;
uint32_t count, eof, recvd, hdrlen;
int status;
@@ -2322,7 +2796,7 @@ decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *re
READ32(eof);
READ32(count);
hdrlen = (u8 *) p - (u8 *) iov->iov_base;
- recvd = req->rq_received - hdrlen;
+ recvd = req->rq_rcv_buf.len - hdrlen;
if (count > recvd) {
printk(KERN_WARNING "NFS: server cheating in read reply: "
"count %u > recvd %u\n", count, recvd);
@@ -2335,8 +2809,7 @@ decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *re
return 0;
}
-static int
-decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir *readdir)
+static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir)
{
struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
struct page *page = *rcvbuf->pages;
@@ -2350,17 +2823,17 @@ decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir
if (status)
return status;
READ_BUF(8);
- COPYMEM(readdir->rd_resp_verifier.data, 8);
+ COPYMEM(readdir->verifier.data, 8);
hdrlen = (char *) p - (char *) iov->iov_base;
- recvd = req->rq_received - hdrlen;
+ recvd = rcvbuf->len - hdrlen;
if (pglen > recvd)
pglen = recvd;
xdr_read_pages(xdr, pglen);
- BUG_ON(pglen + readdir->rd_pgbase > PAGE_CACHE_SIZE);
+ BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE);
kaddr = p = (uint32_t *) kmap_atomic(page, KM_USER0);
- end = (uint32_t *) ((char *)p + pglen + readdir->rd_pgbase);
+ end = (uint32_t *) ((char *)p + pglen + readdir->pgbase);
entry = p;
for (nr = 0; *p++; nr++) {
if (p + 3 > end)
@@ -2420,8 +2893,7 @@ err_unmap:
return -errno_NFSERR_IO;
}
-static int
-decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readlink *readlink)
+static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
{
struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
struct iovec *iov = rcvbuf->head;
@@ -2462,43 +2934,34 @@ decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readli
return 0;
}
-static int
-decode_restorefh(struct xdr_stream *xdr)
-{
- return decode_op_hdr(xdr, OP_RESTOREFH);
-}
-
-static int
-decode_remove(struct xdr_stream *xdr, struct nfs4_remove *remove)
+static int decode_remove(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
{
int status;
status = decode_op_hdr(xdr, OP_REMOVE);
if (status)
goto out;
- status = decode_change_info(xdr, remove->rm_cinfo);
+ status = decode_change_info(xdr, cinfo);
out:
return status;
}
-static int
-decode_rename(struct xdr_stream *xdr, struct nfs4_rename *rename)
+static int decode_rename(struct xdr_stream *xdr, struct nfs4_change_info *old_cinfo,
+ struct nfs4_change_info *new_cinfo)
{
int status;
status = decode_op_hdr(xdr, OP_RENAME);
if (status)
goto out;
- if ((status = decode_change_info(xdr, rename->rn_src_cinfo)))
- goto out;
- if ((status = decode_change_info(xdr, rename->rn_dst_cinfo)))
+ if ((status = decode_change_info(xdr, old_cinfo)))
goto out;
+ status = decode_change_info(xdr, new_cinfo);
out:
return status;
}
-static int
-decode_renew(struct xdr_stream *xdr)
+static int decode_renew(struct xdr_stream *xdr)
{
return decode_op_hdr(xdr, OP_RENEW);
}
@@ -2509,8 +2972,7 @@ decode_savefh(struct xdr_stream *xdr)
return decode_op_hdr(xdr, OP_SAVEFH);
}
-static int
-decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res)
+static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res)
{
uint32_t *p;
uint32_t bmlen;
@@ -2526,8 +2988,7 @@ decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res)
return 0;
}
-static int
-decode_setclientid(struct xdr_stream *xdr, struct nfs4_client *clp)
+static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_client *clp)
{
uint32_t *p;
uint32_t opnum;
@@ -2565,14 +3026,12 @@ decode_setclientid(struct xdr_stream *xdr, struct nfs4_client *clp)
return 0;
}
-static int
-decode_setclientid_confirm(struct xdr_stream *xdr)
+static int decode_setclientid_confirm(struct xdr_stream *xdr)
{
return decode_op_hdr(xdr, OP_SETCLIENTID_CONFIRM);
}
-static int
-decode_write(struct xdr_stream *xdr, struct nfs_writeres *res)
+static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res)
{
uint32_t *p;
int status;
@@ -2588,94 +3047,10 @@ decode_write(struct xdr_stream *xdr, struct nfs_writeres *res)
return 0;
}
-/* FIXME: this sucks */
-static int
-decode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqst *req)
-{
- struct compound_hdr hdr;
- struct nfs4_op *op;
- int status;
-
- status = decode_compound_hdr(xdr, &hdr);
- if (status)
- goto out;
-
- cp->toplevel_status = hdr.status;
-
- /*
- * We need this if our zero-copy I/O is going to work. Rumor has
- * it that the spec will soon mandate it...
- */
- if (hdr.taglen != cp->taglen)
- dprintk("nfs4: non-conforming server returns tag length mismatch!\n");
-
- cp->resp_nops = hdr.nops;
- if (hdr.nops > cp->req_nops) {
- dprintk("nfs4: resp_nops > req_nops!\n");
- goto xdr_error;
- }
-
- op = &cp->ops[0];
- for (cp->nops = 0; cp->nops < cp->resp_nops; cp->nops++, op++) {
- switch (op->opnum) {
- case OP_ACCESS:
- status = decode_access(xdr, &op->u.access);
- break;
- case OP_CREATE:
- status = decode_create(xdr, &op->u.create);
- break;
- case OP_GETATTR:
- status = decode_getattr(xdr, &op->u.getattr, cp->server);
- break;
- case OP_GETFH:
- status = decode_getfh(xdr, &op->u.getfh);
- break;
- case OP_LINK:
- status = decode_link(xdr, &op->u.link);
- break;
- case OP_LOOKUP:
- status = decode_lookup(xdr);
- break;
- case OP_PUTFH:
- status = decode_putfh(xdr);
- break;
- case OP_PUTROOTFH:
- status = decode_putrootfh(xdr);
- break;
- case OP_READDIR:
- status = decode_readdir(xdr, req, &op->u.readdir);
- break;
- case OP_READLINK:
- status = decode_readlink(xdr, req, &op->u.readlink);
- break;
- case OP_RESTOREFH:
- status = decode_restorefh(xdr);
- break;
- case OP_REMOVE:
- status = decode_remove(xdr, &op->u.remove);
- break;
- case OP_RENAME:
- status = decode_rename(xdr, &op->u.rename);
- break;
- case OP_SAVEFH:
- status = decode_savefh(xdr);
- break;
- default:
- BUG();
- return -EIO;
- }
- if (status)
- break;
- }
-
- DECODE_TAIL;
-}
-
/*
* Decode OPEN_DOWNGRADE response
*/
-static int
-nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res)
+static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -2698,31 +3073,180 @@ out:
*/
/*
- * Decode COMPOUND response
+ * Decode ACCESS response
*/
-static int
-nfs4_xdr_dec_compound(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_compound *cp)
+static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_accessres *res)
{
struct xdr_stream xdr;
+ struct compound_hdr hdr;
int status;
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
- if ((status = decode_compound(&xdr, cp, rqstp)))
+ if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
goto out;
+ if ((status = decode_putfh(&xdr)) == 0)
+ status = decode_access(&xdr, res);
+out:
+ return status;
+}
+
+/*
+ * Decode LOOKUP response
+ */
+static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_lookup_res *res)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+ int status;
- status = 0;
- if (cp->toplevel_status)
- status = -nfs_stat_to_errno(cp->toplevel_status);
+ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+ if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
+ goto out;
+ if ((status = decode_putfh(&xdr)) != 0)
+ goto out;
+ if ((status = decode_lookup(&xdr)) != 0)
+ goto out;
+ if ((status = decode_getfh(&xdr, res->fh)) != 0)
+ goto out;
+ status = decode_getfattr(&xdr, res->fattr, res->server);
+out:
+ return status;
+}
+/*
+ * Decode LOOKUP_ROOT response
+ */
+static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_lookup_res *res)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+ int status;
+
+ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+ if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
+ goto out;
+ if ((status = decode_putrootfh(&xdr)) != 0)
+ goto out;
+ if ((status = decode_getfh(&xdr, res->fh)) == 0)
+ status = decode_getfattr(&xdr, res->fattr, res->server);
+out:
+ return status;
+}
+
+/*
+ * Decode REMOVE response
+ */
+static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_change_info *cinfo)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+ int status;
+
+ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+ if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
+ goto out;
+ if ((status = decode_putfh(&xdr)) == 0)
+ status = decode_remove(&xdr, cinfo);
+out:
+ return status;
+}
+
+/*
+ * Decode RENAME response
+ */
+static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_rename_res *res)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+ int status;
+
+ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+ if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
+ goto out;
+ if ((status = decode_putfh(&xdr)) != 0)
+ goto out;
+ if ((status = decode_savefh(&xdr)) != 0)
+ goto out;
+ if ((status = decode_putfh(&xdr)) != 0)
+ goto out;
+ status = decode_rename(&xdr, &res->old_cinfo, &res->new_cinfo);
out:
return status;
}
/*
+ * Decode LINK response
+ */
+static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_change_info *cinfo)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+ int status;
+
+ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+ if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
+ goto out;
+ if ((status = decode_putfh(&xdr)) != 0)
+ goto out;
+ if ((status = decode_savefh(&xdr)) != 0)
+ goto out;
+ if ((status = decode_putfh(&xdr)) != 0)
+ goto out;
+ status = decode_link(&xdr, cinfo);
+out:
+ return status;
+}
+
+/*
+ * Decode CREATE response
+ */
+static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_create_res *res)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+ int status;
+
+ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+ if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
+ goto out;
+ if ((status = decode_putfh(&xdr)) != 0)
+ goto out;
+ if ((status = decode_create(&xdr,&res->dir_cinfo)) != 0)
+ goto out;
+ if ((status = decode_getfattr(&xdr, res->fattr, res->server)) != 0)
+ goto out;
+ status = decode_getfh(&xdr, res->fh);
+out:
+ return status;
+}
+
+/*
+ * Decode GETATTR response
+ */
+static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_getattr_res *res)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+ int status;
+
+ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+ status = decode_compound_hdr(&xdr, &hdr);
+ if (status)
+ goto out;
+ status = decode_putfh(&xdr);
+ if (status)
+ goto out;
+ status = decode_getfattr(&xdr, res->fattr, res->server);
+out:
+ return status;
+
+}
+
+
+/*
* Decode CLOSE response
*/
-static int
-nfs4_xdr_dec_close(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res)
+static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -2743,14 +3267,10 @@ out:
/*
* Decode OPEN response
*/
-static int
-nfs4_xdr_dec_open(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res)
+static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
- struct nfs4_getfh gfh = {
- .gf_fhandle = &res->fh,
- };
int status;
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
@@ -2760,24 +3280,13 @@ nfs4_xdr_dec_open(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res)
status = decode_putfh(&xdr);
if (status)
goto out;
- status = decode_savefh(&xdr);
- if (status)
- goto out;
status = decode_open(&xdr, res);
if (status)
goto out;
- status = decode_getattr(&xdr, res->f_getattr, res->server);
- if (status)
- goto out;
- status = decode_getfh(&xdr, &gfh);
- if (status)
- goto out;
- status = decode_restorefh(&xdr);
- if (status)
- goto out;
- status = decode_getattr(&xdr, res->d_getattr, res->server);
+ status = decode_getfattr(&xdr, res->f_attr, res->server);
if (status)
goto out;
+ status = decode_getfh(&xdr, &res->fh);
out:
return status;
}
@@ -2785,8 +3294,7 @@ out:
/*
* Decode OPEN_CONFIRM response
*/
-static int
-nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_open_confirmres *res)
+static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_open_confirmres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -2807,8 +3315,7 @@ out:
/*
* Decode OPEN_RECLAIM response
*/
-static int
-nfs4_xdr_dec_open_reclaim(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res)
+static int nfs4_xdr_dec_open_reclaim(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -2824,7 +3331,7 @@ nfs4_xdr_dec_open_reclaim(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openre
status = decode_open(&xdr, res);
if (status)
goto out;
- status = decode_getattr(&xdr, res->f_getattr, res->server);
+ status = decode_getfattr(&xdr, res->f_attr, res->server);
out:
return status;
}
@@ -2832,8 +3339,7 @@ out:
/*
* Decode SETATTR response
*/
-static int
-nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_setattrres *res)
+static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_setattrres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -2849,7 +3355,7 @@ nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_setattrres
status = decode_setattr(&xdr, res);
if (status)
goto out;
- status = decode_getattr(&xdr, res->attr, res->server);
+ status = decode_getfattr(&xdr, res->fattr, res->server);
out:
return status;
}
@@ -2857,8 +3363,7 @@ out:
/*
* Decode LOCK response
*/
-static int
-nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res)
+static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -2879,8 +3384,7 @@ out:
/*
* Decode LOCKT response
*/
-static int
-nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res)
+static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -2901,8 +3405,7 @@ out:
/*
* Decode LOCKU response
*/
-static int
-nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res)
+static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -2921,10 +3424,9 @@ out:
}
/*
- * Decode Read response
+ * Decode READLINK response
*/
-static int
-nfs4_xdr_dec_read(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_readres *res)
+static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, uint32_t *p, void *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -2937,23 +3439,15 @@ nfs4_xdr_dec_read(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_readres *res)
status = decode_putfh(&xdr);
if (status)
goto out;
- status = decode_read(&xdr, rqstp, res);
- if (status)
- goto out;
- status = decode_read_getattr(&xdr, res->fattr);
- if (!status)
- status = -nfs_stat_to_errno(hdr.status);
- if (!status)
- status = res->count;
+ status = decode_readlink(&xdr, rqstp);
out:
return status;
}
/*
- * Decode WRITE response
+ * Decode READDIR response
*/
-static int
-nfs4_xdr_dec_write(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_writeres *res)
+static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_readdir_res *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -2966,15 +3460,28 @@ nfs4_xdr_dec_write(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_writeres *res
status = decode_putfh(&xdr);
if (status)
goto out;
- status = decode_pre_write_getattr(&xdr, res->fattr);
+ status = decode_readdir(&xdr, rqstp, res);
+out:
+ return status;
+}
+
+/*
+ * Decode Read response
+ */
+static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_readres *res)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+ int status;
+
+ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+ status = decode_compound_hdr(&xdr, &hdr);
if (status)
goto out;
- status = decode_write(&xdr, res);
+ status = decode_putfh(&xdr);
if (status)
goto out;
- status = decode_post_write_getattr(&xdr, res->fattr);
- if (!status)
- status = -nfs_stat_to_errno(hdr.status);
+ status = decode_read(&xdr, rqstp, res);
if (!status)
status = res->count;
out:
@@ -2982,10 +3489,9 @@ out:
}
/*
- * Decode COMMIT response
+ * Decode WRITE response
*/
-static int
-nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_writeres *res)
+static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_writeres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -2998,15 +3504,30 @@ nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_writeres *re
status = decode_putfh(&xdr);
if (status)
goto out;
- status = decode_pre_write_getattr(&xdr, res->fattr);
+ status = decode_write(&xdr, res);
+ if (!status)
+ status = res->count;
+out:
+ return status;
+}
+
+/*
+ * Decode COMMIT response
+ */
+static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_writeres *res)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+ int status;
+
+ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+ status = decode_compound_hdr(&xdr, &hdr);
if (status)
goto out;
- status = decode_commit(&xdr, res);
+ status = decode_putfh(&xdr);
if (status)
goto out;
- status = decode_post_write_getattr(&xdr, res->fattr);
- if (!status)
- status = -nfs_stat_to_errno(hdr.status);
+ status = decode_commit(&xdr, res);
out:
return status;
}
@@ -3014,8 +3535,7 @@ out:
/*
* FSINFO request
*/
-static int
-nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs_fsinfo *fsinfo)
+static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs_fsinfo *fsinfo)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -3033,10 +3553,64 @@ nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs_fsinfo *fsinfo
}
/*
+ * PATHCONF request
+ */
+static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, uint32_t *p, struct nfs_pathconf *pathconf)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+ int status;
+
+ xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
+ status = decode_compound_hdr(&xdr, &hdr);
+ if (!status)
+ status = decode_putfh(&xdr);
+ if (!status)
+ status = decode_pathconf(&xdr, pathconf);
+ return status;
+}
+
+/*
+ * STATFS request
+ */
+static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, uint32_t *p, struct nfs_fsstat *fsstat)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+ int status;
+
+ xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
+ status = decode_compound_hdr(&xdr, &hdr);
+ if (!status)
+ status = decode_putfh(&xdr);
+ if (!status)
+ status = decode_statfs(&xdr, fsstat);
+ return status;
+}
+
+/*
+ * GETATTR_BITMAP request
+ */
+static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, uint32_t *p, struct nfs4_server_caps_res *res)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+ int status;
+
+ xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
+ if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
+ goto out;
+ if ((status = decode_putfh(&xdr)) != 0)
+ goto out;
+ status = decode_server_caps(&xdr, res);
+out:
+ return status;
+}
+
+/*
* Decode RENEW response
*/
-static int
-nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, uint32_t *p, void *dummy)
+static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, uint32_t *p, void *dummy)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -3052,8 +3626,7 @@ nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, uint32_t *p, void *dummy)
/*
* a SETCLIENTID request
*/
-static int
-nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p,
+static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p,
struct nfs4_client *clp)
{
struct xdr_stream xdr;
@@ -3072,8 +3645,7 @@ nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p,
/*
* a SETCLIENTID_CONFIRM request
*/
-static int
-nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_fsinfo *fsinfo)
+static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_fsinfo *fsinfo)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -3092,8 +3664,7 @@ nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_f
return status;
}
-uint32_t *
-nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus)
+uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus)
{
uint32_t len;
@@ -3209,7 +3780,6 @@ nfs_stat_to_errno(int stat)
}
struct rpc_procinfo nfs4_procedures[] = {
- PROC(COMPOUND, enc_compound, dec_compound),
PROC(READ, enc_read, dec_read),
PROC(WRITE, enc_write, dec_write),
PROC(COMMIT, enc_commit, dec_commit),
@@ -3226,6 +3796,19 @@ struct rpc_procinfo nfs4_procedures[] = {
PROC(LOCK, enc_lock, dec_lock),
PROC(LOCKT, enc_lockt, dec_lockt),
PROC(LOCKU, enc_locku, dec_locku),
+ PROC(ACCESS, enc_access, dec_access),
+ PROC(GETATTR, enc_getattr, dec_getattr),
+ PROC(LOOKUP, enc_lookup, dec_lookup),
+ PROC(LOOKUP_ROOT, enc_lookup_root, dec_lookup_root),
+ PROC(REMOVE, enc_remove, dec_remove),
+ PROC(RENAME, enc_rename, dec_rename),
+ PROC(LINK, enc_link, dec_link),
+ PROC(CREATE, enc_create, dec_create),
+ PROC(PATHCONF, enc_pathconf, dec_pathconf),
+ PROC(STATFS, enc_statfs, dec_statfs),
+ PROC(READLINK, enc_readlink, dec_readlink),
+ PROC(READDIR, enc_readdir, dec_readdir),
+ PROC(SERVER_CAPS, enc_server_caps, dec_server_caps),
};
struct rpc_version nfs_version4 = {
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index 0f348c2ab722..305ef463bf82 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -66,7 +66,8 @@
* is NOT for the length of the hostname.
* Hua Qin : Support for mounting root file system via
* NFS over TCP.
- */
+ * Fabian Frederick: Option parser rebuilt (using parser lib)
+*/
#include <linux/config.h>
#include <linux/types.h>
@@ -85,6 +86,7 @@
#include <linux/inet.h>
#include <linux/root_dev.h>
#include <net/ipconfig.h>
+#include <linux/parser.h>
/* Define this to allow debugging output */
#undef NFSROOT_DEBUG
@@ -114,92 +116,158 @@ static int mount_port __initdata = 0; /* Mount daemon port number */
***************************************************************************/
-/*
- * The following integer options are recognized
- */
-static struct nfs_int_opts {
- char *name;
- int *val;
-} root_int_opts[] __initdata = {
- { "port", &nfs_port },
- { "rsize", &nfs_data.rsize },
- { "wsize", &nfs_data.wsize },
- { "timeo", &nfs_data.timeo },
- { "retrans", &nfs_data.retrans },
- { "acregmin", &nfs_data.acregmin },
- { "acregmax", &nfs_data.acregmax },
- { "acdirmin", &nfs_data.acdirmin },
- { "acdirmax", &nfs_data.acdirmax },
- { NULL, NULL }
+enum {
+ Opt_port, Opt_rsize, Opt_wsize, Opt_timeo, Opt_retrans, Opt_acregmin,
+ Opt_acregmax, Opt_acdirmin, Opt_acdirmax, Opt_soft, Opt_hard, Opt_intr,
+ Opt_nointr, Opt_posix, Opt_noposix, Opt_cto, Opt_nocto, Opt_ac,
+ Opt_noac, Opt_lock, Opt_nolock, Opt_v2, Opt_v3, Opt_udp, Opt_tcp,
+ Opt_broken_suid, Opt_err,
};
-
-/*
- * And now the flag options
- */
-static struct nfs_bool_opts {
- char *name;
- int and_mask;
- int or_mask;
-} root_bool_opts[] __initdata = {
- { "soft", ~NFS_MOUNT_SOFT, NFS_MOUNT_SOFT },
- { "hard", ~NFS_MOUNT_SOFT, 0 },
- { "intr", ~NFS_MOUNT_INTR, NFS_MOUNT_INTR },
- { "nointr", ~NFS_MOUNT_INTR, 0 },
- { "posix", ~NFS_MOUNT_POSIX, NFS_MOUNT_POSIX },
- { "noposix", ~NFS_MOUNT_POSIX, 0 },
- { "cto", ~NFS_MOUNT_NOCTO, 0 },
- { "nocto", ~NFS_MOUNT_NOCTO, NFS_MOUNT_NOCTO },
- { "ac", ~NFS_MOUNT_NOAC, 0 },
- { "noac", ~NFS_MOUNT_NOAC, NFS_MOUNT_NOAC },
- { "lock", ~NFS_MOUNT_NONLM, 0 },
- { "nolock", ~NFS_MOUNT_NONLM, NFS_MOUNT_NONLM },
-#ifdef CONFIG_NFS_V3
- { "v2", ~NFS_MOUNT_VER3, 0 },
- { "v3", ~NFS_MOUNT_VER3, NFS_MOUNT_VER3 },
-#endif
- { "udp", ~NFS_MOUNT_TCP, 0 },
- { "tcp", ~NFS_MOUNT_TCP, NFS_MOUNT_TCP },
- { "broken_suid",~NFS_MOUNT_BROKEN_SUID, NFS_MOUNT_BROKEN_SUID },
- { NULL, 0, 0 }
+static match_table_t tokens = {
+ {Opt_port, "port=%u"},
+ {Opt_rsize, "rsize=%u"},
+ {Opt_wsize, "wsize=%u"},
+ {Opt_timeo, "timeo=%u"},
+ {Opt_retrans, "retrans=%u"},
+ {Opt_acregmin, "acregmin=%u"},
+ {Opt_acregmax, "acregmax=%u"},
+ {Opt_acdirmin, "acdirmin=%u"},
+ {Opt_acdirmax, "acdirmax=%u"},
+ {Opt_soft, "soft"},
+ {Opt_hard, "hard"},
+ {Opt_intr, "intr"},
+ {Opt_nointr, "nointr"},
+ {Opt_posix, "posix"},
+ {Opt_noposix, "noposix"},
+ {Opt_cto, "cto"},
+ {Opt_nocto, "nocto"},
+ {Opt_ac, "ac"},
+ {Opt_noac, "noac"},
+ {Opt_lock, "lock"},
+ {Opt_nolock, "nolock"},
+ {Opt_v2, "v2"},
+ {Opt_v3, "v3"},
+ {Opt_udp, "udp"},
+ {Opt_tcp, "tcp"},
+ {Opt_broken_suid, "broken_suid"},
+ {Opt_err, NULL}
+
};
-
/*
* Parse option string.
*/
-static void __init root_nfs_parse(char *name, char *buf)
+
+static int __init root_nfs_parse(char *name, char *buf)
{
- char *options, *val, *cp;
-
- if ((options = strchr(name, ','))) {
- *options++ = 0;
- while ((cp = strsep(&options, ",")) != NULL) {
- if (!*cp)
- continue;
- if ((val = strchr(cp, '='))) {
- struct nfs_int_opts *opts = root_int_opts;
- *val++ = '\0';
- while (opts->name && strcmp(opts->name, cp))
- opts++;
- if (opts->name)
- *(opts->val) = (int) simple_strtoul(val, NULL, 10);
- } else {
- struct nfs_bool_opts *opts = root_bool_opts;
- while (opts->name && strcmp(opts->name, cp))
- opts++;
- if (opts->name) {
- nfs_data.flags &= opts->and_mask;
- nfs_data.flags |= opts->or_mask;
- }
- }
+
+ char *p;
+ substring_t args[MAX_OPT_ARGS];
+ int option;
+
+ if (!name)
+ return 1;
+
+ if (name[0] && strcmp(name, "default")){
+ strlcpy(buf, name, NFS_MAXPATHLEN);
+ return 1;
+ }
+ while ((p = strsep (&name, ",")) != NULL) {
+ int token;
+ if (!*p)
+ continue;
+ token = match_token(p, tokens, args);
+
+ /* %u tokens only */
+ if (match_int(&args[0], &option))
+ return 0;
+ switch (token) {
+ case Opt_port:
+ nfs_port = option;
+ break;
+ case Opt_rsize:
+ nfs_data.rsize = option;
+ break;
+ case Opt_wsize:
+ nfs_data.wsize = option;
+ break;
+ case Opt_timeo:
+ nfs_data.timeo = option;
+ break;
+ case Opt_retrans:
+ nfs_data.retrans = option;
+ break;
+ case Opt_acregmin:
+ nfs_data.acregmin = option;
+ break;
+ case Opt_acregmax:
+ nfs_data.acregmax = option;
+ break;
+ case Opt_acdirmin:
+ nfs_data.acdirmin = option;
+ break;
+ case Opt_acdirmax:
+ nfs_data.acdirmax = option;
+ break;
+ case Opt_soft:
+ nfs_data.flags |= NFS_MOUNT_SOFT;
+ break;
+ case Opt_hard:
+ nfs_data.flags &= ~NFS_MOUNT_SOFT;
+ break;
+ case Opt_intr:
+ nfs_data.flags |= NFS_MOUNT_INTR;
+ break;
+ case Opt_nointr:
+ nfs_data.flags &= ~NFS_MOUNT_INTR;
+ break;
+ case Opt_posix:
+ nfs_data.flags |= NFS_MOUNT_POSIX;
+ break;
+ case Opt_noposix:
+ nfs_data.flags &= ~NFS_MOUNT_POSIX;
+ break;
+ case Opt_cto:
+ nfs_data.flags &= ~NFS_MOUNT_NOCTO;
+ break;
+ case Opt_nocto:
+ nfs_data.flags |= NFS_MOUNT_NOCTO;
+ break;
+ case Opt_ac:
+ nfs_data.flags &= ~NFS_MOUNT_NOAC;
+ break;
+ case Opt_noac:
+ nfs_data.flags |= NFS_MOUNT_NOAC;
+ break;
+ case Opt_lock:
+ nfs_data.flags &= ~NFS_MOUNT_NONLM;
+ break;
+ case Opt_nolock:
+ nfs_data.flags |= NFS_MOUNT_NONLM;
+ break;
+ case Opt_v2:
+ nfs_data.flags &= ~NFS_MOUNT_VER3;
+ break;
+ case Opt_v3:
+ nfs_data.flags |= NFS_MOUNT_VER3;
+ break;
+ case Opt_udp:
+ nfs_data.flags &= ~NFS_MOUNT_TCP;
+ break;
+ case Opt_tcp:
+ nfs_data.flags |= NFS_MOUNT_TCP;
+ break;
+ case Opt_broken_suid:
+ nfs_data.flags |= NFS_MOUNT_BROKEN_SUID;
+ break;
+ default :
+ return 0;
}
}
- if (name[0] && strcmp(name, "default"))
- strlcpy(buf, name, NFS_MAXPATHLEN);
+ return 1;
}
-
/*
* Prepare the NFS data structure and parse all options.
*/
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index 4c025d7357c8..c82fc852840e 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -32,7 +32,7 @@ static inline struct nfs_page *
nfs_page_alloc(void)
{
struct nfs_page *p;
- p = kmem_cache_alloc(nfs_page_cachep, SLAB_NOFS);
+ p = kmem_cache_alloc(nfs_page_cachep, SLAB_KERNEL);
if (p) {
memset(p, 0, sizeof(*p));
INIT_LIST_HEAD(&p->wb_list);
@@ -88,6 +88,7 @@ nfs_create_request(struct file *file, struct inode *inode,
* long write-back delay. This will be adjusted in
* update_nfs_request below if the region is not locked. */
req->wb_page = page;
+ atomic_set(&req->wb_complete, 0);
req->wb_index = page->index;
page_cache_get(page);
req->wb_offset = offset;
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index ca4eccd03adf..8dc6a981c586 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -559,11 +559,10 @@ nfs_read_done(struct rpc_task *task)
}
static void
-nfs_proc_read_setup(struct nfs_read_data *data, unsigned int count)
+nfs_proc_read_setup(struct nfs_read_data *data)
{
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_READ],
@@ -571,27 +570,13 @@ nfs_proc_read_setup(struct nfs_read_data *data, unsigned int count)
.rpc_resp = &data->res,
.rpc_cred = data->cred,
};
-
- 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.pages = data->pagevec;
- data->args.count = count;
- data->res.fattr = &data->fattr;
- data->res.count = count;
- data->res.eof = 0;
-
+
/* N.B. Do we need to test? Never called for swapfile inode */
flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0);
/* Finalize the task. */
rpc_init_task(task, NFS_CLIENT(inode), nfs_read_done, flags);
- task->tk_calldata = data;
- /* Release requests */
- task->tk_release = nfs_readdata_release;
-
- rpc_call_setup(&data->task, &msg, 0);
+ rpc_call_setup(task, &msg, 0);
}
static void
@@ -605,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],
@@ -619,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();
}
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 4b929887c5a4..053d5462fac2 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -35,6 +35,8 @@
#define NFSDBG_FACILITY NFSDBG_PAGECACHE
static int nfs_pagein_one(struct list_head *, struct inode *);
+static void nfs_readpage_result_partial(struct nfs_read_data *, int);
+static void nfs_readpage_result_full(struct nfs_read_data *, int);
static kmem_cache_t *nfs_rdata_cachep;
static mempool_t *nfs_rdata_mempool;
@@ -57,12 +59,37 @@ static __inline__ void nfs_readdata_free(struct nfs_read_data *p)
mempool_free(p, nfs_rdata_mempool);
}
-void nfs_readdata_release(struct rpc_task *task)
+static void nfs_readdata_release(struct rpc_task *task)
{
struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata;
nfs_readdata_free(data);
}
+static
+unsigned int nfs_page_length(struct inode *inode, struct page *page)
+{
+ loff_t i_size = i_size_read(inode);
+ unsigned long idx;
+
+ if (i_size <= 0)
+ return 0;
+ idx = (i_size - 1) >> PAGE_CACHE_SHIFT;
+ if (page->index > idx)
+ return 0;
+ if (page->index != idx)
+ return PAGE_CACHE_SIZE;
+ return 1 + ((i_size - 1) & (PAGE_CACHE_SIZE - 1));
+}
+
+static
+int nfs_return_empty_page(struct page *page)
+{
+ memclear_highpage_flush(page, 0, PAGE_CACHE_SIZE);
+ SetPageUptodate(page);
+ unlock_page(page);
+ return 0;
+}
+
/*
* Read a page synchronously.
*/
@@ -78,6 +105,7 @@ nfs_readpage_sync(struct file *file, struct inode *inode, struct page *page)
.inode = inode,
.args = {
.fh = NFS_FH(inode),
+ .lockowner = current->files,
.pages = &page,
.pgbase = 0UL,
.count = rsize,
@@ -146,89 +174,209 @@ nfs_readpage_async(struct file *file, struct inode *inode, struct page *page)
{
LIST_HEAD(one_request);
struct nfs_page *new;
+ unsigned int len;
- new = nfs_create_request(file, inode, page, 0, PAGE_CACHE_SIZE);
+ len = nfs_page_length(inode, page);
+ if (len == 0)
+ return nfs_return_empty_page(page);
+ new = nfs_create_request(file, inode, page, 0, len);
if (IS_ERR(new)) {
unlock_page(page);
return PTR_ERR(new);
}
+ if (len < PAGE_CACHE_SIZE)
+ memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len);
+
nfs_lock_request(new);
nfs_list_add_request(new, &one_request);
nfs_pagein_one(&one_request, inode);
return 0;
}
+static void nfs_readpage_release(struct nfs_page *req)
+{
+ unlock_page(req->wb_page);
+
+ nfs_clear_request(req);
+ nfs_release_request(req);
+ nfs_unlock_request(req);
+
+ dprintk("NFS: read done (%s/%Ld %d@%Ld)\n",
+ req->wb_inode->i_sb->s_id,
+ (long long)NFS_FILEID(req->wb_inode),
+ req->wb_bytes,
+ (long long)req_offset(req));
+}
+
/*
* Set up the NFS read request struct
*/
-static void
-nfs_read_rpcsetup(struct list_head *head, struct nfs_read_data *data)
+static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
+ unsigned int count, unsigned int offset)
{
struct inode *inode;
- struct nfs_page *req;
- struct page **pages;
- unsigned int count;
- pages = data->pagevec;
- count = 0;
- while (!list_empty(head)) {
- req = nfs_list_entry(head->next);
- nfs_list_remove_request(req);
- nfs_list_add_request(req, &data->pages);
- *pages++ = req->wb_page;
- count += req->wb_bytes;
- }
- req = nfs_list_entry(data->pages.next);
+ data->req = req;
data->inode = inode = req->wb_inode;
data->cred = req->wb_cred;
- NFS_PROTO(inode)->read_setup(data, count);
+ data->args.fh = NFS_FH(inode);
+ data->args.offset = req_offset(req) + offset;
+ data->args.pgbase = req->wb_pgbase + offset;
+ data->args.pages = data->pagevec;
+ data->args.count = count;
+ data->args.lockowner = req->wb_lockowner;
+ data->args.state = req->wb_state;
+
+ data->res.fattr = &data->fattr;
+ data->res.count = count;
+ data->res.eof = 0;
- dprintk("NFS: %4d initiated read call (req %s/%Ld, %u bytes @ offset %Lu.\n",
+ NFS_PROTO(inode)->read_setup(data);
+
+ data->task.tk_cookie = (unsigned long)inode;
+ data->task.tk_calldata = data;
+ /* Release requests */
+ data->task.tk_release = nfs_readdata_release;
+
+ dprintk("NFS: %4d initiated read call (req %s/%Ld, %u bytes @ offset %Lu)\n",
data->task.tk_pid,
inode->i_sb->s_id,
(long long)NFS_FILEID(inode),
count,
- (unsigned long long)req_offset(req));
+ (unsigned long long)data->args.offset);
}
static void
nfs_async_read_error(struct list_head *head)
{
struct nfs_page *req;
- struct page *page;
while (!list_empty(head)) {
req = nfs_list_entry(head->next);
- page = req->wb_page;
nfs_list_remove_request(req);
- SetPageError(page);
- unlock_page(page);
- nfs_clear_request(req);
- nfs_release_request(req);
- nfs_unlock_request(req);
+ SetPageError(req->wb_page);
+ nfs_readpage_release(req);
}
}
-static int
-nfs_pagein_one(struct list_head *head, struct inode *inode)
+/*
+ * Start an async read operation
+ */
+static void nfs_execute_read(struct nfs_read_data *data)
+{
+ struct rpc_clnt *clnt = NFS_CLIENT(data->inode);
+ sigset_t oldset;
+
+ rpc_clnt_sigmask(clnt, &oldset);
+ lock_kernel();
+ rpc_execute(&data->task);
+ unlock_kernel();
+ rpc_clnt_sigunmask(clnt, &oldset);
+}
+
+/*
+ * Generate multiple requests to fill a single page.
+ *
+ * We optimize to reduce the number of read operations on the wire. If we
+ * detect that we're reading a page, or an area of a page, that is past the
+ * end of file, we do not generate NFS read operations but just clear the
+ * parts of the page that would have come back zero from the server anyway.
+ *
+ * We rely on the cached value of i_size to make this determination; another
+ * client can fill pages on the server past our cached end-of-file, but we
+ * won't see the new data until our attribute cache is updated. This is more
+ * or less conventional NFS client behavior.
+ */
+static int nfs_pagein_multi(struct list_head *head, struct inode *inode)
+{
+ struct nfs_page *req = nfs_list_entry(head->next);
+ struct page *page = req->wb_page;
+ struct nfs_read_data *data;
+ unsigned int rsize = NFS_SERVER(inode)->rsize;
+ unsigned int nbytes, offset;
+ int requests = 0;
+ LIST_HEAD(list);
+
+ nfs_list_remove_request(req);
+
+ nbytes = req->wb_bytes;
+ for(;;) {
+ data = nfs_readdata_alloc();
+ if (!data)
+ goto out_bad;
+ list_add(&data->pages, &list);
+ requests++;
+ if (nbytes <= rsize)
+ break;
+ nbytes -= rsize;
+ }
+ atomic_set(&req->wb_complete, requests);
+
+ ClearPageError(page);
+ offset = 0;
+ nbytes = req->wb_bytes;
+ do {
+ data = list_entry(list.next, struct nfs_read_data, pages);
+ list_del_init(&data->pages);
+
+ data->pagevec[0] = page;
+ data->complete = nfs_readpage_result_partial;
+
+ if (nbytes > rsize) {
+ nfs_read_rpcsetup(req, data, rsize, offset);
+ offset += rsize;
+ nbytes -= rsize;
+ } else {
+ nfs_read_rpcsetup(req, data, nbytes, offset);
+ nbytes = 0;
+ }
+ nfs_execute_read(data);
+ } while (nbytes != 0);
+
+ return 0;
+
+out_bad:
+ while (!list_empty(&list)) {
+ data = list_entry(list.next, struct nfs_read_data, pages);
+ list_del(&data->pages);
+ nfs_readdata_free(data);
+ }
+ SetPageError(page);
+ nfs_readpage_release(req);
+ return -ENOMEM;
+}
+
+static int nfs_pagein_one(struct list_head *head, struct inode *inode)
{
- struct rpc_clnt *clnt = NFS_CLIENT(inode);
+ struct nfs_page *req;
+ struct page **pages;
struct nfs_read_data *data;
- sigset_t oldset;
+ unsigned int count;
+
+ if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE)
+ return nfs_pagein_multi(head, inode);
data = nfs_readdata_alloc();
if (!data)
goto out_bad;
- nfs_read_rpcsetup(head, data);
+ pages = data->pagevec;
+ count = 0;
+ while (!list_empty(head)) {
+ req = nfs_list_entry(head->next);
+ nfs_list_remove_request(req);
+ nfs_list_add_request(req, &data->pages);
+ ClearPageError(req->wb_page);
+ *pages++ = req->wb_page;
+ count += req->wb_bytes;
+ }
+ req = nfs_list_entry(data->pages.next);
+
+ data->complete = nfs_readpage_result_full;
+ nfs_read_rpcsetup(req, data, count, 0);
- /* Start the async call */
- rpc_clnt_sigmask(clnt, &oldset);
- lock_kernel();
- rpc_execute(&data->task);
- unlock_kernel();
- rpc_clnt_sigunmask(clnt, &oldset);
+ nfs_execute_read(data);
return 0;
out_bad:
nfs_async_read_error(head);
@@ -258,55 +406,95 @@ nfs_pagein_list(struct list_head *head, int rpages)
}
/*
+ * Handle a read reply that fills part of a page.
+ */
+static void nfs_readpage_result_partial(struct nfs_read_data *data, int status)
+{
+ struct nfs_page *req = data->req;
+ struct page *page = req->wb_page;
+
+ if (status >= 0) {
+ unsigned int request = data->args.count;
+ unsigned int result = data->res.count;
+
+ if (result < request) {
+ memclear_highpage_flush(page,
+ data->args.pgbase + result,
+ request - result);
+ }
+ } else
+ SetPageError(page);
+
+ if (atomic_dec_and_test(&req->wb_complete)) {
+ if (!PageError(page))
+ SetPageUptodate(page);
+ nfs_readpage_release(req);
+ }
+}
+
+/*
* This is the callback from RPC telling us whether a reply was
* received or some error occurred (timeout or socket shutdown).
*/
-void
-nfs_readpage_result(struct rpc_task *task)
+static void nfs_readpage_result_full(struct nfs_read_data *data, int status)
{
- struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata;
unsigned int count = data->res.count;
- dprintk("NFS: %4d nfs_readpage_result, (status %d)\n",
- task->tk_pid, task->tk_status);
-
- NFS_FLAGS(data->inode) |= NFS_INO_INVALID_ATIME;
while (!list_empty(&data->pages)) {
struct nfs_page *req = nfs_list_entry(data->pages.next);
struct page *page = req->wb_page;
nfs_list_remove_request(req);
- if (task->tk_status >= 0) {
+ if (status >= 0) {
if (count < PAGE_CACHE_SIZE) {
- memclear_highpage_flush(page,
+ if (count < req->wb_bytes)
+ memclear_highpage_flush(page,
req->wb_pgbase + count,
req->wb_bytes - count);
-
count = 0;
} else
count -= PAGE_CACHE_SIZE;
SetPageUptodate(page);
} else
SetPageError(page);
- unlock_page(page);
+ nfs_readpage_release(req);
+ }
+}
+
+/*
+ * This is the callback from RPC telling us whether a reply was
+ * received or some error occurred (timeout or socket shutdown).
+ */
+void nfs_readpage_result(struct rpc_task *task)
+{
+ struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata;
+ struct nfs_readargs *argp = &data->args;
+ struct nfs_readres *resp = &data->res;
+ int status = task->tk_status;
- dprintk("NFS: read (%s/%Ld %d@%Ld)\n",
- req->wb_inode->i_sb->s_id,
- (long long)NFS_FILEID(req->wb_inode),
- req->wb_bytes,
- (long long)req_offset(req));
- nfs_clear_request(req);
- nfs_release_request(req);
- nfs_unlock_request(req);
+ dprintk("NFS: %4d nfs_readpage_result, (status %d)\n",
+ task->tk_pid, status);
+
+ /* Is this a short read? */
+ if (task->tk_status >= 0 && resp->count < argp->count && !resp->eof) {
+ /* Has the server at least made some progress? */
+ if (resp->count != 0) {
+ /* Yes, so retry the read at the end of the data */
+ argp->offset += resp->count;
+ argp->pgbase += resp->count;
+ argp->count -= resp->count;
+ rpc_restart_call(task);
+ return;
+ }
+ task->tk_status = -EIO;
}
+ NFS_FLAGS(data->inode) |= NFS_INO_INVALID_ATIME;
+ data->complete(data, status);
}
/*
* Read a page over NFS.
- * We read the page synchronously in the following cases:
- * - The NFS rsize is smaller than PAGE_CACHE_SIZE. We could kludge our way
- * around this by creating several consecutive read requests, but
- * that's hardly worth it.
+ * We read the page synchronously in the following case:
* - The error flag is set for this page. This happens only when a
* previous async read operation failed.
*/
@@ -329,7 +517,7 @@ nfs_readpage(struct file *file, struct page *page)
if (error)
goto out_error;
- if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE) {
+ if (!IS_SYNC(inode)) {
error = nfs_readpage_async(file, inode, page);
goto out;
}
@@ -351,26 +539,25 @@ struct nfs_readdesc {
};
static int
-readpage_sync_filler(void *data, struct page *page)
-{
- struct nfs_readdesc *desc = (struct nfs_readdesc *)data;
- return nfs_readpage_sync(desc->filp, page->mapping->host, page);
-}
-
-static int
readpage_async_filler(void *data, struct page *page)
{
struct nfs_readdesc *desc = (struct nfs_readdesc *)data;
struct inode *inode = page->mapping->host;
struct nfs_page *new;
+ unsigned int len;
nfs_wb_page(inode, page);
- new = nfs_create_request(desc->filp, inode, page, 0, PAGE_CACHE_SIZE);
+ len = nfs_page_length(inode, page);
+ if (len == 0)
+ return nfs_return_empty_page(page);
+ new = nfs_create_request(desc->filp, inode, page, 0, len);
if (IS_ERR(new)) {
SetPageError(page);
unlock_page(page);
return PTR_ERR(new);
}
+ if (len < PAGE_CACHE_SIZE)
+ memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len);
nfs_lock_request(new);
nfs_list_add_request(new, desc->head);
return 0;
@@ -385,14 +572,16 @@ nfs_readpages(struct file *filp, struct address_space *mapping,
.filp = filp,
.head = &head,
};
- struct nfs_server *server = NFS_SERVER(mapping->host);
- int is_sync = server->rsize < PAGE_CACHE_SIZE;
+ struct inode *inode = mapping->host;
+ struct nfs_server *server = NFS_SERVER(inode);
int ret;
- ret = read_cache_pages(mapping, pages,
- is_sync ? readpage_sync_filler :
- readpage_async_filler,
- &desc);
+ dprintk("NFS: nfs_readpages (%s/%Ld %d)\n",
+ inode->i_sb->s_id,
+ (long long)NFS_FILEID(inode),
+ nr_pages);
+
+ ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc);
if (!list_empty(&head)) {
int err = nfs_pagein_list(&head, server->rpages);
if (!ret)
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 53bff1a2a731..6250a5da857f 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -74,11 +74,17 @@
static struct nfs_page * nfs_update_request(struct file*, struct inode *,
struct page *,
unsigned int, unsigned int);
+static void nfs_writeback_done_partial(struct nfs_write_data *, int);
+static void nfs_writeback_done_full(struct nfs_write_data *, int);
+static int nfs_wait_on_write_congestion(struct address_space *, int);
+static int nfs_wait_on_requests(struct inode *, unsigned long, unsigned int);
static kmem_cache_t *nfs_wdata_cachep;
static mempool_t *nfs_wdata_mempool;
static mempool_t *nfs_commit_mempool;
+static DECLARE_WAIT_QUEUE_HEAD(nfs_write_congestion);
+
static __inline__ struct nfs_write_data *nfs_writedata_alloc(void)
{
struct nfs_write_data *p;
@@ -95,7 +101,7 @@ static __inline__ void nfs_writedata_free(struct nfs_write_data *p)
mempool_free(p, nfs_wdata_mempool);
}
-void nfs_writedata_release(struct rpc_task *task)
+static void nfs_writedata_release(struct rpc_task *task)
{
struct nfs_write_data *wdata = (struct nfs_write_data *)task->tk_calldata;
nfs_writedata_free(wdata);
@@ -117,12 +123,6 @@ static __inline__ void nfs_commit_free(struct nfs_write_data *p)
mempool_free(p, nfs_commit_mempool);
}
-void nfs_commit_release(struct rpc_task *task)
-{
- struct nfs_write_data *wdata = (struct nfs_write_data *)task->tk_calldata;
- nfs_commit_free(wdata);
-}
-
/* Adjust the file length if we're writing beyond the end */
static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int count)
{
@@ -173,19 +173,19 @@ static void nfs_mark_uptodate(struct page *page, unsigned int base, unsigned int
* Write a page synchronously.
* Offset is the data offset within the page.
*/
-static int
-nfs_writepage_sync(struct file *file, struct inode *inode, struct page *page,
- unsigned int offset, unsigned int count)
+static int nfs_writepage_sync(struct file *file, struct inode *inode,
+ struct page *page, unsigned int offset, unsigned int count,
+ int how)
{
unsigned int wsize = NFS_SERVER(inode)->wsize;
int result, written = 0;
- int swapfile = IS_SWAPFILE(inode);
struct nfs_write_data wdata = {
- .flags = swapfile ? NFS_RPC_SWAPFLAGS : 0,
+ .flags = how,
.cred = NULL,
.inode = inode,
.args = {
.fh = NFS_FH(inode),
+ .lockowner = current->files,
.pages = &page,
.stable = NFS_FILE_SYNC,
.pgbase = offset,
@@ -204,7 +204,7 @@ nfs_writepage_sync(struct file *file, struct inode *inode, struct page *page,
nfs_begin_data_update(inode);
do {
- if (count < wsize && !swapfile)
+ if (count < wsize)
wdata.args.count = count;
wdata.args.offset = page_offset(page) + wdata.args.pgbase;
@@ -233,7 +233,7 @@ nfs_writepage_sync(struct file *file, struct inode *inode, struct page *page,
ClearPageError(page);
io_error:
- nfs_end_data_update(inode);
+ nfs_end_data_update_defer(inode);
if (wdata.cred)
put_rpccred(wdata.cred);
@@ -259,17 +259,26 @@ static int nfs_writepage_async(struct file *file, struct inode *inode,
return status;
}
+static int wb_priority(struct writeback_control *wbc)
+{
+ if (wbc->for_reclaim)
+ return FLUSH_HIGHPRI;
+ if (wbc->for_kupdate)
+ return FLUSH_LOWPRI;
+ return 0;
+}
+
/*
* Write an mmapped page to the server.
*/
-int
-nfs_writepage(struct page *page, struct writeback_control *wbc)
+int nfs_writepage(struct page *page, struct writeback_control *wbc)
{
struct inode *inode = page->mapping->host;
unsigned long end_index;
unsigned offset = PAGE_CACHE_SIZE;
loff_t i_size = i_size_read(inode);
int inode_referenced = 0;
+ int priority = wb_priority(wbc);
int err;
/*
@@ -285,7 +294,7 @@ nfs_writepage(struct page *page, struct writeback_control *wbc)
end_index = i_size >> PAGE_CACHE_SHIFT;
/* Ensure we've flushed out any previous writes */
- nfs_wb_page(inode,page);
+ nfs_wb_page_priority(inode, page, priority);
/* easy case */
if (page->index < end_index)
@@ -299,44 +308,60 @@ nfs_writepage(struct page *page, struct writeback_control *wbc)
goto out;
do_it:
lock_kernel();
- if (NFS_SERVER(inode)->wsize >= PAGE_CACHE_SIZE && !IS_SYNC(inode) &&
- inode_referenced) {
+ if (!IS_SYNC(inode) && inode_referenced) {
err = nfs_writepage_async(NULL, inode, page, 0, offset);
- if (err >= 0)
+ if (err >= 0) {
err = 0;
+ if (wbc->for_reclaim)
+ err = WRITEPAGE_ACTIVATE;
+ }
} else {
- err = nfs_writepage_sync(NULL, inode, page, 0, offset);
+ err = nfs_writepage_sync(NULL, inode, page, 0, offset, priority);
if (err == offset)
err = 0;
}
unlock_kernel();
out:
- unlock_page(page);
+ if (err != WRITEPAGE_ACTIVATE)
+ unlock_page(page);
if (inode_referenced)
iput(inode);
return err;
}
-int
-nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
+/*
+ * Note: causes nfs_update_request() to block on the assumption
+ * that the writeback is generated due to memory pressure.
+ */
+int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
{
+ struct backing_dev_info *bdi = mapping->backing_dev_info;
struct inode *inode = mapping->host;
- int is_sync = !wbc->nonblocking;
int err;
err = generic_writepages(mapping, wbc);
if (err)
- goto out;
- err = nfs_flush_inode(inode, 0, 0, 0);
+ return err;
+ while (test_and_set_bit(BDI_write_congested, &bdi->state) != 0) {
+ if (wbc->nonblocking)
+ return 0;
+ nfs_wait_on_write_congestion(mapping, 0);
+ }
+ err = nfs_flush_inode(inode, 0, 0, wb_priority(wbc));
if (err < 0)
goto out;
- if (wbc->sync_mode == WB_SYNC_HOLD)
- goto out;
- if (is_sync && wbc->sync_mode == WB_SYNC_ALL) {
- err = nfs_wb_all(inode);
- } else
- nfs_commit_inode(inode, 0, 0, 0);
+ wbc->nr_to_write -= err;
+ if (!wbc->nonblocking && wbc->sync_mode == WB_SYNC_ALL) {
+ err = nfs_wait_on_requests(inode, 0, 0);
+ if (err < 0)
+ goto out;
+ }
+ err = nfs_commit_inode(inode, 0, 0, wb_priority(wbc));
+ if (err > 0)
+ wbc->nr_to_write -= err;
out:
+ clear_bit(BDI_write_congested, &bdi->state);
+ wake_up_all(&nfs_write_congestion);
return err;
}
@@ -365,7 +390,7 @@ nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
/*
* Insert a write request into an inode
*/
-static inline void
+static void
nfs_inode_remove_request(struct nfs_page *req)
{
struct nfs_inode *nfsi;
@@ -379,7 +404,7 @@ nfs_inode_remove_request(struct nfs_page *req)
nfsi->npages--;
if (!nfsi->npages) {
spin_unlock(&nfs_wreq_lock);
- nfs_end_data_update(inode);
+ nfs_end_data_update_defer(inode);
iput(inode);
} else
spin_unlock(&nfs_wreq_lock);
@@ -416,7 +441,7 @@ nfs_find_request(struct inode *inode, unsigned long index)
/*
* Add a request to the inode's dirty list.
*/
-static inline void
+static void
nfs_mark_request_dirty(struct nfs_page *req)
{
struct inode *inode = req->wb_inode;
@@ -444,7 +469,7 @@ nfs_dirty_request(struct nfs_page *req)
/*
* Add a request to the inode's commit list.
*/
-static inline void
+static void
nfs_mark_request_commit(struct nfs_page *req)
{
struct inode *inode = req->wb_inode;
@@ -548,6 +573,38 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_st
}
#endif
+static int nfs_wait_on_write_congestion(struct address_space *mapping, int intr)
+{
+ struct backing_dev_info *bdi = mapping->backing_dev_info;
+ DEFINE_WAIT(wait);
+ int ret = 0;
+
+ might_sleep();
+
+ if (!bdi_write_congested(bdi))
+ return 0;
+ if (intr) {
+ struct rpc_clnt *clnt = NFS_CLIENT(mapping->host);
+ sigset_t oldset;
+
+ rpc_clnt_sigmask(clnt, &oldset);
+ prepare_to_wait(&nfs_write_congestion, &wait, TASK_INTERRUPTIBLE);
+ if (bdi_write_congested(bdi)) {
+ if (signalled())
+ ret = -ERESTARTSYS;
+ else
+ schedule();
+ }
+ rpc_clnt_sigunmask(clnt, &oldset);
+ } else {
+ prepare_to_wait(&nfs_write_congestion, &wait, TASK_UNINTERRUPTIBLE);
+ if (bdi_write_congested(bdi))
+ schedule();
+ }
+ finish_wait(&nfs_write_congestion, &wait);
+ return ret;
+}
+
/*
* Try to update any existing write request, or create one if there is none.
@@ -560,11 +617,14 @@ static struct nfs_page *
nfs_update_request(struct file* file, struct inode *inode, struct page *page,
unsigned int offset, unsigned int bytes)
{
+ struct nfs_server *server = NFS_SERVER(inode);
struct nfs_page *req, *new = NULL;
unsigned long rqend, end;
end = offset + bytes;
+ if (nfs_wait_on_write_congestion(page->mapping, server->flags & NFS_MOUNT_INTR))
+ return ERR_PTR(-ERESTARTSYS);
for (;;) {
/* Loop over all inode entries and see if we find
* A request for the page we wish to update
@@ -668,8 +728,8 @@ nfs_flush_incompatible(struct file *file, struct page *page)
* XXX: Keep an eye on generic_file_read to make sure it doesn't do bad
* things with a page scheduled for an RPC call (e.g. invalidate it).
*/
-int
-nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsigned int count)
+int nfs_updatepage(struct file *file, struct page *page,
+ unsigned int offset, unsigned int count)
{
struct dentry *dentry = file->f_dentry;
struct inode *inode = page->mapping->host;
@@ -680,12 +740,8 @@ nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsign
dentry->d_parent->d_name.name, dentry->d_name.name,
count, (long long)(page_offset(page) +offset));
- /*
- * If wsize is smaller than page size, update and write
- * page synchronously.
- */
- if (NFS_SERVER(inode)->wsize < PAGE_CACHE_SIZE || IS_SYNC(inode)) {
- status = nfs_writepage_sync(file, inode, page, offset, count);
+ if (IS_SYNC(inode)) {
+ status = nfs_writepage_sync(file, inode, page, offset, count, 0);
if (status > 0) {
if (offset == 0 && status == PAGE_CACHE_SIZE)
SetPageUptodate(page);
@@ -747,43 +803,162 @@ done:
return status;
}
+static void nfs_writepage_release(struct nfs_page *req)
+{
+ end_page_writeback(req->wb_page);
+
+#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
+ if (!PageError(req->wb_page)) {
+ if (NFS_NEED_RESCHED(req)) {
+ nfs_mark_request_dirty(req);
+ goto out;
+ } else if (NFS_NEED_COMMIT(req)) {
+ nfs_mark_request_commit(req);
+ goto out;
+ }
+ }
+ nfs_inode_remove_request(req);
+
+out:
+ nfs_clear_commit(req);
+ nfs_clear_reschedule(req);
+#else
+ nfs_inode_remove_request(req);
+#endif
+ nfs_unlock_request(req);
+}
+
+static inline int flush_task_priority(int how)
+{
+ switch (how & (FLUSH_HIGHPRI|FLUSH_LOWPRI)) {
+ case FLUSH_HIGHPRI:
+ return RPC_PRIORITY_HIGH;
+ case FLUSH_LOWPRI:
+ return RPC_PRIORITY_LOW;
+ }
+ return RPC_PRIORITY_NORMAL;
+}
+
/*
* Set up the argument/result storage required for the RPC call.
*/
-static void
-nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data, int how)
+static void nfs_write_rpcsetup(struct nfs_page *req,
+ struct nfs_write_data *data,
+ unsigned int count, unsigned int offset,
+ int how)
{
struct rpc_task *task = &data->task;
struct inode *inode;
- struct nfs_page *req;
- struct page **pages;
- unsigned int count;
/* Set up the RPC argument and reply structs
* NB: take care not to mess about with data->commit et al. */
- pages = data->pagevec;
- count = 0;
- while (!list_empty(head)) {
- req = nfs_list_entry(head->next);
- nfs_list_remove_request(req);
- nfs_list_add_request(req, &data->pages);
- set_page_writeback(req->wb_page);
- *pages++ = req->wb_page;
- count += req->wb_bytes;
- }
- req = nfs_list_entry(data->pages.next);
+ data->req = req;
data->inode = inode = req->wb_inode;
data->cred = req->wb_cred;
- NFS_PROTO(inode)->write_setup(data, count, how);
+ data->args.fh = NFS_FH(inode);
+ data->args.offset = req_offset(req) + offset;
+ data->args.pgbase = req->wb_pgbase + offset;
+ data->args.pages = data->pagevec;
+ data->args.count = count;
+ data->args.lockowner = req->wb_lockowner;
+ data->args.state = req->wb_state;
+
+ data->res.fattr = &data->fattr;
+ data->res.count = count;
+ data->res.verf = &data->verf;
+
+ NFS_PROTO(inode)->write_setup(data, how);
+
+ data->task.tk_priority = flush_task_priority(how);
+ data->task.tk_cookie = (unsigned long)inode;
+ data->task.tk_calldata = data;
+ /* Release requests */
+ data->task.tk_release = nfs_writedata_release;
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));
+ (unsigned long long)data->args.offset);
+}
+
+static void nfs_execute_write(struct nfs_write_data *data)
+{
+ struct rpc_clnt *clnt = NFS_CLIENT(data->inode);
+ sigset_t oldset;
+
+ rpc_clnt_sigmask(clnt, &oldset);
+ lock_kernel();
+ rpc_execute(&data->task);
+ unlock_kernel();
+ rpc_clnt_sigunmask(clnt, &oldset);
+}
+
+/*
+ * Generate multiple small requests to write out a single
+ * contiguous dirty area on one page.
+ */
+static int nfs_flush_multi(struct list_head *head, struct inode *inode, int how)
+{
+ struct nfs_page *req = nfs_list_entry(head->next);
+ struct page *page = req->wb_page;
+ struct nfs_write_data *data;
+ unsigned int wsize = NFS_SERVER(inode)->wsize;
+ unsigned int nbytes, offset;
+ int requests = 0;
+ LIST_HEAD(list);
+
+ nfs_list_remove_request(req);
+
+ nbytes = req->wb_bytes;
+ for (;;) {
+ data = nfs_writedata_alloc();
+ if (!data)
+ goto out_bad;
+ list_add(&data->pages, &list);
+ requests++;
+ if (nbytes <= wsize)
+ break;
+ nbytes -= wsize;
+ }
+ atomic_set(&req->wb_complete, requests);
+
+ ClearPageError(page);
+ SetPageWriteback(page);
+ offset = 0;
+ nbytes = req->wb_bytes;
+ do {
+ data = list_entry(list.next, struct nfs_write_data, pages);
+ list_del_init(&data->pages);
+
+ data->pagevec[0] = page;
+ data->complete = nfs_writeback_done_partial;
+
+ if (nbytes > wsize) {
+ nfs_write_rpcsetup(req, data, wsize, offset, how);
+ offset += wsize;
+ nbytes -= wsize;
+ } else {
+ nfs_write_rpcsetup(req, data, nbytes, offset, how);
+ nbytes = 0;
+ }
+ nfs_execute_write(data);
+ } while (nbytes != 0);
+
+ return 0;
+
+out_bad:
+ while (!list_empty(&list)) {
+ data = list_entry(list.next, struct nfs_write_data, pages);
+ list_del(&data->pages);
+ nfs_writedata_free(data);
+ }
+ nfs_mark_request_dirty(req);
+ nfs_unlock_request(req);
+ return -ENOMEM;
}
/*
@@ -794,25 +969,38 @@ nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data, int how)
* This is the case if nfs_updatepage detects a conflicting request
* that has been written but not committed.
*/
-static int
-nfs_flush_one(struct list_head *head, struct inode *inode, int how)
+static int nfs_flush_one(struct list_head *head, struct inode *inode, int how)
{
- struct rpc_clnt *clnt = NFS_CLIENT(inode);
+ struct nfs_page *req;
+ struct page **pages;
struct nfs_write_data *data;
- sigset_t oldset;
+ unsigned int count;
+
+ if (NFS_SERVER(inode)->wsize < PAGE_CACHE_SIZE)
+ return nfs_flush_multi(head, inode, how);
data = nfs_writedata_alloc();
if (!data)
goto out_bad;
+ pages = data->pagevec;
+ count = 0;
+ while (!list_empty(head)) {
+ req = nfs_list_entry(head->next);
+ nfs_list_remove_request(req);
+ nfs_list_add_request(req, &data->pages);
+ ClearPageError(req->wb_page);
+ SetPageWriteback(req->wb_page);
+ *pages++ = req->wb_page;
+ count += req->wb_bytes;
+ }
+ req = nfs_list_entry(data->pages.next);
+
+ data->complete = nfs_writeback_done_full;
/* Set up the argument struct */
- nfs_write_rpcsetup(head, data, how);
+ nfs_write_rpcsetup(req, data, count, 0, how);
- rpc_clnt_sigmask(clnt, &oldset);
- lock_kernel();
- rpc_execute(&data->task);
- unlock_kernel();
- rpc_clnt_sigunmask(clnt, &oldset);
+ nfs_execute_write(data);
return 0;
out_bad:
while (!list_empty(head)) {
@@ -851,59 +1039,59 @@ nfs_flush_list(struct list_head *head, int wpages, int how)
return error;
}
-
/*
- * This function is called when the WRITE call is complete.
+ * Handle a write reply that flushed part of a page.
*/
-void
-nfs_writeback_done(struct rpc_task *task)
+static void nfs_writeback_done_partial(struct nfs_write_data *data, int status)
{
- struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
- struct nfs_writeargs *argp = &data->args;
- struct nfs_writeres *resp = &data->res;
- struct nfs_page *req;
- struct page *page;
+ struct nfs_page *req = data->req;
+ struct page *page = req->wb_page;
- dprintk("NFS: %4d nfs_writeback_done (status %d)\n",
- task->tk_pid, task->tk_status);
+ dprintk("NFS: write (%s/%Ld %d@%Ld)",
+ req->wb_inode->i_sb->s_id,
+ (long long)NFS_FILEID(req->wb_inode),
+ req->wb_bytes,
+ (long long)req_offset(req));
- /* We can't handle that yet but we check for it nevertheless */
- if (resp->count < argp->count && task->tk_status >= 0) {
- static unsigned long complain;
- if (time_before(complain, jiffies)) {
- printk(KERN_WARNING
- "NFS: Server wrote less than requested.\n");
- complain = jiffies + 300 * HZ;
- }
- /* Can't do anything about it right now except throw
- * an error. */
- task->tk_status = -EIO;
- }
+ if (status < 0) {
+ ClearPageUptodate(page);
+ SetPageError(page);
+ if (req->wb_file)
+ req->wb_file->f_error = status;
+ dprintk(", error = %d\n", status);
+ } else {
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
- if (data->verf.committed < argp->stable && task->tk_status >= 0) {
- /* We tried a write call, but the server did not
- * commit data to stable storage even though we
- * requested it.
- * Note: There is a known bug in Tru64 < 5.0 in which
- * the server reports NFS_DATA_SYNC, but performs
- * NFS_FILE_SYNC. We therefore implement this checking
- * as a dprintk() in order to avoid filling syslog.
- */
- static unsigned long complain;
-
- if (time_before(complain, jiffies)) {
- dprintk("NFS: faulty NFS server %s:"
- " (committed = %d) != (stable = %d)\n",
- NFS_SERVER(data->inode)->hostname,
- data->verf.committed, argp->stable);
- complain = jiffies + 300 * HZ;
- }
- }
+ if (data->verf.committed < NFS_FILE_SYNC) {
+ if (!NFS_NEED_COMMIT(req)) {
+ nfs_defer_commit(req);
+ memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf));
+ dprintk(" defer commit\n");
+ } else if (memcmp(&req->wb_verf, &data->verf, sizeof(req->wb_verf))) {
+ nfs_defer_reschedule(req);
+ dprintk(" server reboot detected\n");
+ }
+ } else
#endif
+ dprintk(" OK\n");
+ }
- /*
- * Process the nfs_page list
- */
+ if (atomic_dec_and_test(&req->wb_complete))
+ nfs_writepage_release(req);
+}
+
+/*
+ * Handle a write reply that flushes a whole page.
+ *
+ * FIXME: There is an inherent race with invalidate_inode_pages and
+ * writebacks since the page->count is kept > 1 for as long
+ * as the page has a write request pending.
+ */
+static void nfs_writeback_done_full(struct nfs_write_data *data, int status)
+{
+ struct nfs_page *req;
+ struct page *page;
+
+ /* Update attributes as result of writeback. */
while (!list_empty(&data->pages)) {
req = nfs_list_entry(data->pages.next);
nfs_list_remove_request(req);
@@ -915,20 +1103,20 @@ nfs_writeback_done(struct rpc_task *task)
req->wb_bytes,
(long long)req_offset(req));
- if (task->tk_status < 0) {
+ if (status < 0) {
ClearPageUptodate(page);
SetPageError(page);
if (req->wb_file)
- req->wb_file->f_error = task->tk_status;
+ req->wb_file->f_error = status;
end_page_writeback(page);
nfs_inode_remove_request(req);
- dprintk(", error = %d\n", task->tk_status);
+ dprintk(", error = %d\n", status);
goto next;
}
end_page_writeback(page);
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
- if (argp->stable != NFS_UNSTABLE || data->verf.committed == NFS_FILE_SYNC) {
+ if (data->args.stable != NFS_UNSTABLE || data->verf.committed == NFS_FILE_SYNC) {
nfs_inode_remove_request(req);
dprintk(" OK\n");
goto next;
@@ -944,13 +1132,88 @@ nfs_writeback_done(struct rpc_task *task)
}
}
+/*
+ * This function is called when the WRITE call is complete.
+ */
+void nfs_writeback_done(struct rpc_task *task)
+{
+ struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
+ struct nfs_writeargs *argp = &data->args;
+ struct nfs_writeres *resp = &data->res;
+
+ dprintk("NFS: %4d nfs_writeback_done (status %d)\n",
+ task->tk_pid, task->tk_status);
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
+ if (resp->verf->committed < argp->stable && task->tk_status >= 0) {
+ /* We tried a write call, but the server did not
+ * commit data to stable storage even though we
+ * requested it.
+ * Note: There is a known bug in Tru64 < 5.0 in which
+ * the server reports NFS_DATA_SYNC, but performs
+ * NFS_FILE_SYNC. We therefore implement this checking
+ * as a dprintk() in order to avoid filling syslog.
+ */
+ static unsigned long complain;
+
+ if (time_before(complain, jiffies)) {
+ dprintk("NFS: faulty NFS server %s:"
+ " (committed = %d) != (stable = %d)\n",
+ NFS_SERVER(data->inode)->hostname,
+ resp->verf->committed, argp->stable);
+ complain = jiffies + 300 * HZ;
+ }
+ }
+#endif
+ /* Is this a short write? */
+ if (task->tk_status >= 0 && resp->count < argp->count) {
+ static unsigned long complain;
+
+ /* Has the server at least made some progress? */
+ if (resp->count != 0) {
+ /* Was this an NFSv2 write or an NFSv3 stable write? */
+ if (resp->verf->committed != NFS_UNSTABLE) {
+ /* Resend from where the server left off */
+ argp->offset += resp->count;
+ argp->pgbase += resp->count;
+ argp->count -= resp->count;
+ } else {
+ /* Resend as a stable write in order to avoid
+ * headaches in the case of a server crash.
+ */
+ argp->stable = NFS_FILE_SYNC;
+ }
+ rpc_restart_call(task);
+ return;
+ }
+ if (time_before(complain, jiffies)) {
+ printk(KERN_WARNING
+ "NFS: Server wrote less than requested.\n");
+ complain = jiffies + 300 * HZ;
+ }
+ /* Can't do anything about it except throw an error. */
+ task->tk_status = -EIO;
+ }
+
+ /*
+ * Process the nfs_page list
+ */
+ data->complete(data, task->tk_status);
+}
+
+
+#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
+static void nfs_commit_release(struct rpc_task *task)
+{
+ struct nfs_write_data *wdata = (struct nfs_write_data *)task->tk_calldata;
+ nfs_commit_free(wdata);
+}
+
/*
* Set up the argument/result storage required for the RPC call.
*/
-static void
-nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data, int how)
+static void 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;
@@ -979,7 +1242,20 @@ nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data, int how
data->inode = inode;
data->cred = first->wb_cred;
- NFS_PROTO(inode)->commit_setup(data, start, len, how);
+ 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;
+
+ NFS_PROTO(inode)->commit_setup(data, how);
+
+ data->task.tk_priority = flush_task_priority(how);
+ data->task.tk_cookie = (unsigned long)inode;
+ data->task.tk_calldata = data;
+ /* Release requests */
+ data->task.tk_release = nfs_commit_release;
dprintk("NFS: %4d initiated commit call\n", task->tk_pid);
}
@@ -990,10 +1266,8 @@ nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data, int how
int
nfs_commit_list(struct list_head *head, int how)
{
- struct rpc_clnt *clnt;
struct nfs_write_data *data;
struct nfs_page *req;
- sigset_t oldset;
data = nfs_commit_alloc();
@@ -1002,13 +1276,8 @@ nfs_commit_list(struct list_head *head, int how)
/* Set up the argument struct */
nfs_commit_rpcsetup(head, data, how);
- clnt = NFS_CLIENT(data->inode);
- rpc_clnt_sigmask(clnt, &oldset);
- lock_kernel();
- rpc_execute(&data->task);
- unlock_kernel();
- rpc_clnt_sigunmask(clnt, &oldset);
+ nfs_execute_write(data);
return 0;
out_bad:
while (!list_empty(head)) {
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 520545881a52..89da81cca477 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -47,6 +47,11 @@
#define NFS4_ACE_SYSTEM_AUDIT_ACE_TYPE 2
#define NFS4_ACE_SYSTEM_ALARM_ACE_TYPE 3
+#define ACL4_SUPPORT_ALLOW_ACL 0x01
+#define ACL4_SUPPORT_DENY_ACL 0x02
+#define ACL4_SUPPORT_AUDIT_ACL 0x04
+#define ACL4_SUPPORT_ALARM_ACL 0x08
+
typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier;
typedef struct { char data[16]; } nfs4_stateid;
@@ -217,64 +222,64 @@ enum lock_type4 {
/* Mandatory Attributes */
-#define FATTR4_WORD0_SUPPORTED_ATTRS (1)
-#define FATTR4_WORD0_TYPE (1 << 1)
-#define FATTR4_WORD0_FH_EXPIRE_TYPE (1 << 2)
-#define FATTR4_WORD0_CHANGE (1 << 3)
-#define FATTR4_WORD0_SIZE (1 << 4)
-#define FATTR4_WORD0_LINK_SUPPORT (1 << 5)
-#define FATTR4_WORD0_SYMLINK_SUPPORT (1 << 6)
-#define FATTR4_WORD0_NAMED_ATTR (1 << 7)
-#define FATTR4_WORD0_FSID (1 << 8)
-#define FATTR4_WORD0_UNIQUE_HANDLES (1 << 9)
-#define FATTR4_WORD0_LEASE_TIME (1 << 10)
-#define FATTR4_WORD0_RDATTR_ERROR (1 << 11)
+#define FATTR4_WORD0_SUPPORTED_ATTRS (1UL << 0)
+#define FATTR4_WORD0_TYPE (1UL << 1)
+#define FATTR4_WORD0_FH_EXPIRE_TYPE (1UL << 2)
+#define FATTR4_WORD0_CHANGE (1UL << 3)
+#define FATTR4_WORD0_SIZE (1UL << 4)
+#define FATTR4_WORD0_LINK_SUPPORT (1UL << 5)
+#define FATTR4_WORD0_SYMLINK_SUPPORT (1UL << 6)
+#define FATTR4_WORD0_NAMED_ATTR (1UL << 7)
+#define FATTR4_WORD0_FSID (1UL << 8)
+#define FATTR4_WORD0_UNIQUE_HANDLES (1UL << 9)
+#define FATTR4_WORD0_LEASE_TIME (1UL << 10)
+#define FATTR4_WORD0_RDATTR_ERROR (1UL << 11)
/* Recommended Attributes */
-#define FATTR4_WORD0_ACL (1 << 12)
-#define FATTR4_WORD0_ACLSUPPORT (1 << 13)
-#define FATTR4_WORD0_ARCHIVE (1 << 14)
-#define FATTR4_WORD0_CANSETTIME (1 << 15)
-#define FATTR4_WORD0_CASE_INSENSITIVE (1 << 16)
-#define FATTR4_WORD0_CASE_PRESERVING (1 << 17)
-#define FATTR4_WORD0_CHOWN_RESTRICTED (1 << 18)
-#define FATTR4_WORD0_FILEHANDLE (1 << 19)
-#define FATTR4_WORD0_FILEID (1 << 20)
-#define FATTR4_WORD0_FILES_AVAIL (1 << 21)
-#define FATTR4_WORD0_FILES_FREE (1 << 22)
-#define FATTR4_WORD0_FILES_TOTAL (1 << 23)
-#define FATTR4_WORD0_FS_LOCATIONS (1 << 24)
-#define FATTR4_WORD0_HIDDEN (1 << 25)
-#define FATTR4_WORD0_HOMOGENEOUS (1 << 26)
-#define FATTR4_WORD0_MAXFILESIZE (1 << 27)
-#define FATTR4_WORD0_MAXLINK (1 << 28)
-#define FATTR4_WORD0_MAXNAME (1 << 29)
-#define FATTR4_WORD0_MAXREAD (1 << 30)
-#define FATTR4_WORD0_MAXWRITE (1 << 31)
-#define FATTR4_WORD1_MIMETYPE (1)
-#define FATTR4_WORD1_MODE (1 << 1)
-#define FATTR4_WORD1_NO_TRUNC (1 << 2)
-#define FATTR4_WORD1_NUMLINKS (1 << 3)
-#define FATTR4_WORD1_OWNER (1 << 4)
-#define FATTR4_WORD1_OWNER_GROUP (1 << 5)
-#define FATTR4_WORD1_QUOTA_HARD (1 << 6)
-#define FATTR4_WORD1_QUOTA_SOFT (1 << 7)
-#define FATTR4_WORD1_QUOTA_USED (1 << 8)
-#define FATTR4_WORD1_RAWDEV (1 << 9)
-#define FATTR4_WORD1_SPACE_AVAIL (1 << 10)
-#define FATTR4_WORD1_SPACE_FREE (1 << 11)
-#define FATTR4_WORD1_SPACE_TOTAL (1 << 12)
-#define FATTR4_WORD1_SPACE_USED (1 << 13)
-#define FATTR4_WORD1_SYSTEM (1 << 14)
-#define FATTR4_WORD1_TIME_ACCESS (1 << 15)
-#define FATTR4_WORD1_TIME_ACCESS_SET (1 << 16)
-#define FATTR4_WORD1_TIME_BACKUP (1 << 17)
-#define FATTR4_WORD1_TIME_CREATE (1 << 18)
-#define FATTR4_WORD1_TIME_DELTA (1 << 19)
-#define FATTR4_WORD1_TIME_METADATA (1 << 20)
-#define FATTR4_WORD1_TIME_MODIFY (1 << 21)
-#define FATTR4_WORD1_TIME_MODIFY_SET (1 << 22)
-#define FATTR4_WORD1_MOUNTED_ON_FILEID (1 << 23)
+#define FATTR4_WORD0_ACL (1UL << 12)
+#define FATTR4_WORD0_ACLSUPPORT (1UL << 13)
+#define FATTR4_WORD0_ARCHIVE (1UL << 14)
+#define FATTR4_WORD0_CANSETTIME (1UL << 15)
+#define FATTR4_WORD0_CASE_INSENSITIVE (1UL << 16)
+#define FATTR4_WORD0_CASE_PRESERVING (1UL << 17)
+#define FATTR4_WORD0_CHOWN_RESTRICTED (1UL << 18)
+#define FATTR4_WORD0_FILEHANDLE (1UL << 19)
+#define FATTR4_WORD0_FILEID (1UL << 20)
+#define FATTR4_WORD0_FILES_AVAIL (1UL << 21)
+#define FATTR4_WORD0_FILES_FREE (1UL << 22)
+#define FATTR4_WORD0_FILES_TOTAL (1UL << 23)
+#define FATTR4_WORD0_FS_LOCATIONS (1UL << 24)
+#define FATTR4_WORD0_HIDDEN (1UL << 25)
+#define FATTR4_WORD0_HOMOGENEOUS (1UL << 26)
+#define FATTR4_WORD0_MAXFILESIZE (1UL << 27)
+#define FATTR4_WORD0_MAXLINK (1UL << 28)
+#define FATTR4_WORD0_MAXNAME (1UL << 29)
+#define FATTR4_WORD0_MAXREAD (1UL << 30)
+#define FATTR4_WORD0_MAXWRITE (1UL << 31)
+#define FATTR4_WORD1_MIMETYPE (1UL << 0)
+#define FATTR4_WORD1_MODE (1UL << 1)
+#define FATTR4_WORD1_NO_TRUNC (1UL << 2)
+#define FATTR4_WORD1_NUMLINKS (1UL << 3)
+#define FATTR4_WORD1_OWNER (1UL << 4)
+#define FATTR4_WORD1_OWNER_GROUP (1UL << 5)
+#define FATTR4_WORD1_QUOTA_HARD (1UL << 6)
+#define FATTR4_WORD1_QUOTA_SOFT (1UL << 7)
+#define FATTR4_WORD1_QUOTA_USED (1UL << 8)
+#define FATTR4_WORD1_RAWDEV (1UL << 9)
+#define FATTR4_WORD1_SPACE_AVAIL (1UL << 10)
+#define FATTR4_WORD1_SPACE_FREE (1UL << 11)
+#define FATTR4_WORD1_SPACE_TOTAL (1UL << 12)
+#define FATTR4_WORD1_SPACE_USED (1UL << 13)
+#define FATTR4_WORD1_SYSTEM (1UL << 14)
+#define FATTR4_WORD1_TIME_ACCESS (1UL << 15)
+#define FATTR4_WORD1_TIME_ACCESS_SET (1UL << 16)
+#define FATTR4_WORD1_TIME_BACKUP (1UL << 17)
+#define FATTR4_WORD1_TIME_CREATE (1UL << 18)
+#define FATTR4_WORD1_TIME_DELTA (1UL << 19)
+#define FATTR4_WORD1_TIME_METADATA (1UL << 20)
+#define FATTR4_WORD1_TIME_MODIFY (1UL << 21)
+#define FATTR4_WORD1_TIME_MODIFY_SET (1UL << 22)
+#define FATTR4_WORD1_MOUNTED_ON_FILEID (1UL << 23)
#define NFSPROC4_NULL 0
#define NFSPROC4_COMPOUND 1
@@ -287,7 +292,6 @@ enum lock_type4 {
enum {
NFSPROC4_CLNT_NULL = 0, /* Unused */
- NFSPROC4_CLNT_COMPOUND, /* Soon to be unused */
NFSPROC4_CLNT_READ,
NFSPROC4_CLNT_WRITE,
NFSPROC4_CLNT_COMMIT,
@@ -304,6 +308,19 @@ enum {
NFSPROC4_CLNT_LOCK,
NFSPROC4_CLNT_LOCKT,
NFSPROC4_CLNT_LOCKU,
+ NFSPROC4_CLNT_ACCESS,
+ NFSPROC4_CLNT_GETATTR,
+ NFSPROC4_CLNT_LOOKUP,
+ NFSPROC4_CLNT_LOOKUP_ROOT,
+ NFSPROC4_CLNT_REMOVE,
+ NFSPROC4_CLNT_RENAME,
+ NFSPROC4_CLNT_LINK,
+ NFSPROC4_CLNT_CREATE,
+ NFSPROC4_CLNT_PATHCONF,
+ NFSPROC4_CLNT_STATFS,
+ NFSPROC4_CLNT_READLINK,
+ NFSPROC4_CLNT_READDIR,
+ NFSPROC4_CLNT_SERVER_CAPS,
};
#endif
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 47123702fbd5..fccbab4d02b5 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -69,6 +69,8 @@
#define FLUSH_SYNC 1 /* file being synced, or contention */
#define FLUSH_WAIT 2 /* wait for completion */
#define FLUSH_STABLE 4 /* commit to stable storage */
+#define FLUSH_LOWPRI 8 /* low priority background flush */
+#define FLUSH_HIGHPRI 16 /* high priority memory reclaim flush */
#ifdef __KERNEL__
@@ -275,6 +277,7 @@ extern void nfs_begin_attr_update(struct inode *);
extern void nfs_end_attr_update(struct inode *);
extern void nfs_begin_data_update(struct inode *);
extern void nfs_end_data_update(struct inode *);
+extern void nfs_end_data_update_defer(struct inode *);
/* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */
extern u32 root_nfs_parse_addr(char *name); /*__init*/
@@ -335,10 +338,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
@@ -376,14 +377,18 @@ nfs_wb_all(struct inode *inode)
/*
* Write back all requests on one page - we do this before reading it.
*/
-static inline int
-nfs_wb_page(struct inode *inode, struct page* page)
+static inline int nfs_wb_page_priority(struct inode *inode, struct page* page, int how)
{
int error = nfs_sync_inode(inode, page->index, 1,
- FLUSH_WAIT | FLUSH_STABLE);
+ how | FLUSH_WAIT | FLUSH_STABLE);
return (error < 0) ? error : 0;
}
+static inline int nfs_wb_page(struct inode *inode, struct page* page)
+{
+ return nfs_wb_page_priority(inode, page, 0);
+}
+
/* Hack for future NFS swap support */
#ifndef IS_SWAPFILE
# define IS_SWAPFILE(inode) (0)
@@ -397,7 +402,6 @@ extern int nfs_readpages(struct file *, struct address_space *,
struct list_head *, unsigned);
extern int nfs_pagein_list(struct list_head *, int);
extern void nfs_readpage_result(struct rpc_task *);
-extern void nfs_readdata_release(struct rpc_task *);
/*
* linux/fs/mount_clnt.c
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 1b5f7e130502..428355f8aaf9 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -38,10 +38,19 @@ struct nfs_server {
struct list_head nfs4_siblings; /* List of other nfs_server structs
* that share the same clientid
*/
+ u32 attr_bitmask[2];/* V4 bitmask representing the set
+ of attributes supported on this
+ filesystem */
+ u32 acl_bitmask; /* V4 bitmask representing the ACEs
+ that are supported on this
+ filesystem */
#endif
};
/* Server capabilities */
-#define NFS_CAP_READDIRPLUS (1)
+#define NFS_CAP_READDIRPLUS (1U << 0)
+#define NFS_CAP_HARDLINKS (1U << 1)
+#define NFS_CAP_SYMLINKS (1U << 2)
+#define NFS_CAP_ACLS (1U << 3)
#endif
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h
index c648312afc0c..454587123f33 100644
--- a/include/linux/nfs_page.h
+++ b/include/linux/nfs_page.h
@@ -17,10 +17,14 @@
#include <linux/sunrpc/auth.h>
#include <linux/nfs_xdr.h>
+#include <asm/atomic.h>
+
/*
* Valid flags for a dirty buffer
*/
#define PG_BUSY 0
+#define PG_NEED_COMMIT 1
+#define PG_NEED_RESCHED 2
struct nfs_page {
struct list_head wb_list, /* Defines state of page: */
@@ -31,6 +35,7 @@ struct nfs_page {
struct rpc_cred *wb_cred;
struct nfs4_state *wb_state;
struct page *wb_page; /* page to read in/write out */
+ atomic_t wb_complete; /* i/os we're waiting for */
wait_queue_head_t wb_wait; /* wait queue */
unsigned long wb_index; /* Offset >> PAGE_CACHE_SHIFT */
unsigned int wb_offset, /* Offset & ~PAGE_CACHE_MASK */
@@ -42,6 +47,8 @@ struct nfs_page {
};
#define NFS_WBACK_BUSY(req) (test_bit(PG_BUSY,&(req)->wb_flags))
+#define NFS_NEED_COMMIT(req) (test_bit(PG_NEED_COMMIT,&(req)->wb_flags))
+#define NFS_NEED_RESCHED(req) (test_bit(PG_NEED_RESCHED,&(req)->wb_flags))
extern struct nfs_page *nfs_create_request(struct file *, struct inode *,
struct page *,
@@ -93,8 +100,7 @@ nfs_unlock_request(struct nfs_page *req)
smp_mb__before_clear_bit();
clear_bit(PG_BUSY, &req->wb_flags);
smp_mb__after_clear_bit();
- if (waitqueue_active(&req->wb_wait))
- wake_up_all(&req->wb_wait);
+ wake_up_all(&req->wb_wait);
nfs_release_request(req);
}
@@ -115,6 +121,38 @@ nfs_list_remove_request(struct nfs_page *req)
req->wb_list_head = NULL;
}
+static inline int
+nfs_defer_commit(struct nfs_page *req)
+{
+ if (test_and_set_bit(PG_NEED_COMMIT, &req->wb_flags))
+ return 0;
+ return 1;
+}
+
+static inline void
+nfs_clear_commit(struct nfs_page *req)
+{
+ smp_mb__before_clear_bit();
+ clear_bit(PG_NEED_COMMIT, &req->wb_flags);
+ smp_mb__after_clear_bit();
+}
+
+static inline int
+nfs_defer_reschedule(struct nfs_page *req)
+{
+ if (test_and_set_bit(PG_NEED_RESCHED, &req->wb_flags))
+ return 0;
+ return 1;
+}
+
+static inline void
+nfs_clear_reschedule(struct nfs_page *req)
+{
+ smp_mb__before_clear_bit();
+ clear_bit(PG_NEED_RESCHED, &req->wb_flags);
+ smp_mb__after_clear_bit();
+}
+
static inline struct nfs_page *
nfs_list_entry(struct list_head *head)
{
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 52d87f29fdc4..f47e3c27af27 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -3,6 +3,11 @@
#include <linux/sunrpc/xprt.h>
+struct nfs4_fsid {
+ __u64 major;
+ __u64 minor;
+};
+
struct nfs_fattr {
unsigned short valid; /* which fields are valid */
__u64 pre_size; /* pre_op_attr.size */
@@ -26,10 +31,7 @@ struct nfs_fattr {
dev_t rdev;
union {
__u64 nfs3; /* also nfs2 */
- struct {
- __u64 major;
- __u64 minor;
- } nfs4;
+ struct nfs4_fsid nfs4;
} fsid_u;
__u64 fileid;
struct timespec atime;
@@ -87,6 +89,12 @@ struct nfs_pathconf {
__u32 max_namelen; /* max name length */
};
+struct nfs4_change_info {
+ u32 atomic;
+ u64 before;
+ u64 after;
+};
+
/*
* Arguments to the open call.
*/
@@ -102,20 +110,18 @@ struct nfs_openargs {
struct iattr * attrs; /* UNCHECKED, GUARDED */
nfs4_verifier verifier; /* EXCLUSIVE */
} u;
- struct qstr * name;
- struct nfs4_getattr * f_getattr;
- struct nfs4_getattr * d_getattr;
- struct nfs_server * server; /* Needed for ID mapping */
+ const struct qstr * name;
+ const struct nfs_server *server; /* Needed for ID mapping */
+ const u32 * bitmask;
};
struct nfs_openres {
nfs4_stateid stateid;
struct nfs_fh fh;
- struct nfs4_change_info * cinfo;
+ struct nfs4_change_info cinfo;
__u32 rflags;
- struct nfs4_getattr * f_getattr;
- struct nfs4_getattr * d_getattr;
- struct nfs_server * server;
+ struct nfs_fattr * f_attr;
+ const struct nfs_server *server;
};
/*
@@ -141,7 +147,7 @@ struct nfs_open_reclaimargs {
__u32 id;
__u32 share_access;
__u32 claim;
- struct nfs4_getattr * f_getattr;
+ const __u32 * bitmask;
};
/*
@@ -215,7 +221,7 @@ struct nfs_lockres {
nfs4_stateid stateid;/* LOCK success, LOCKU */
struct nfs_lock_denied denied; /* LOCK failed, LOCKT success */
} u;
- struct nfs_server * server;
+ const struct nfs_server * server;
};
/*
@@ -229,7 +235,8 @@ struct nfs_lockres {
struct nfs_readargs {
struct nfs_fh * fh;
- nfs4_stateid stateid;
+ fl_owner_t lockowner;
+ struct nfs4_state * state;
__u64 offset;
__u32 count;
unsigned int pgbase;
@@ -252,7 +259,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;
@@ -319,13 +327,13 @@ struct nfs_setattrargs {
struct nfs_fh * fh;
nfs4_stateid stateid;
struct iattr * iap;
- struct nfs4_getattr * attr;
- struct nfs_server * server; /* Needed for name mapping */
+ const struct nfs_server * server; /* Needed for name mapping */
+ const u32 * bitmask;
};
struct nfs_setattrres {
- struct nfs4_getattr * attr;
- struct nfs_server * server;
+ struct nfs_fattr * fattr;
+ const struct nfs_server * server;
};
struct nfs_linkargs {
@@ -476,124 +484,116 @@ struct nfs3_readdirres {
typedef u64 clientid4;
-struct nfs4_change_info {
- u32 atomic;
- u64 before;
- u64 after;
+struct nfs4_accessargs {
+ const struct nfs_fh * fh;
+ u32 access;
};
-struct nfs4_access {
- u32 ac_req_access; /* request */
- u32 * ac_resp_supported; /* response */
- u32 * ac_resp_access; /* response */
+struct nfs4_accessres {
+ u32 supported;
+ u32 access;
};
-struct nfs4_close {
- char * cl_stateid; /* request */
- u32 cl_seqid; /* request */
-};
-
-struct nfs4_create {
- u32 cr_ftype; /* request */
- union { /* request */
- struct {
- u32 textlen;
- const char * text;
- } symlink; /* NF4LNK */
+struct nfs4_create_arg {
+ u32 ftype;
+ union {
+ struct qstr * symlink; /* NF4LNK */
struct {
u32 specdata1;
u32 specdata2;
} device; /* NF4BLK, NF4CHR */
} u;
- u32 cr_namelen; /* request */
- const char * cr_name; /* request */
- struct iattr * cr_attrs; /* request */
- struct nfs4_change_info * cr_cinfo; /* response */
+ const struct qstr * name;
+ const struct nfs_server * server;
+ const struct iattr * attrs;
+ const struct nfs_fh * dir_fh;
+ const u32 * bitmask;
};
-#define cr_textlen u.symlink.textlen
-#define cr_text u.symlink.text
-#define cr_specdata1 u.device.specdata1
-#define cr_specdata2 u.device.specdata2
-struct nfs4_getattr {
- u32 * gt_bmval; /* request */
- struct nfs_fattr * gt_attrs; /* response */
- struct nfs_fsstat * gt_fsstat; /* response */
- struct nfs_pathconf * gt_pathconf; /* response */
+struct nfs4_create_res {
+ const struct nfs_server * server;
+ struct nfs_fh * fh;
+ struct nfs_fattr * fattr;
+ struct nfs4_change_info dir_cinfo;
};
-struct nfs4_getfh {
- struct nfs_fh * gf_fhandle; /* response */
+struct nfs4_fsinfo_arg {
+ const struct nfs_fh * fh;
+ const u32 * bitmask;
};
-struct nfs4_link {
- u32 ln_namelen; /* request */
- const char * ln_name; /* request */
- struct nfs4_change_info * ln_cinfo; /* response */
+struct nfs4_getattr_arg {
+ const struct nfs_fh * fh;
+ const u32 * bitmask;
};
-struct nfs4_lookup {
- struct qstr * lo_name; /* request */
+struct nfs4_getattr_res {
+ const struct nfs_server * server;
+ struct nfs_fattr * fattr;
};
-struct nfs4_open {
- struct nfs4_client * op_client_state; /* request */
- u32 op_share_access; /* request */
- u32 op_opentype; /* request */
- u32 op_createmode; /* request */
- union { /* request */
- struct iattr * attrs; /* UNCHECKED, GUARDED */
- nfs4_verifier verifier; /* EXCLUSIVE */
- } u;
- struct qstr * op_name; /* request */
- char * op_stateid; /* response */
- struct nfs4_change_info * op_cinfo; /* response */
- u32 * op_rflags; /* response */
+struct nfs4_link_arg {
+ const struct nfs_fh * fh;
+ const struct nfs_fh * dir_fh;
+ const struct qstr * name;
+};
+
+struct nfs4_lookup_arg {
+ const struct nfs_fh * dir_fh;
+ const struct qstr * name;
+ const u32 * bitmask;
};
-#define op_attrs u.attrs
-#define op_verifier u.verifier
-struct nfs4_open_confirm {
- char * oc_stateid; /* request */
+struct nfs4_lookup_res {
+ const struct nfs_server * server;
+ struct nfs_fattr * fattr;
+ struct nfs_fh * fh;
};
-struct nfs4_putfh {
- struct nfs_fh * pf_fhandle; /* request */
+struct nfs4_lookup_root_arg {
+ const u32 * bitmask;
};
-struct nfs4_readdir {
- u64 rd_cookie; /* request */
- nfs4_verifier rd_req_verifier; /* request */
- u32 rd_count; /* request */
- u32 rd_bmval[2]; /* request */
- nfs4_verifier rd_resp_verifier; /* response */
- struct page ** rd_pages; /* zero-copy data */
- unsigned int rd_pgbase; /* zero-copy data */
+struct nfs4_pathconf_arg {
+ const struct nfs_fh * fh;
+ const u32 * bitmask;
+};
+
+struct nfs4_readdir_arg {
+ const struct nfs_fh * fh;
+ u64 cookie;
+ nfs4_verifier verifier;
+ u32 count;
+ struct page ** pages; /* zero-copy data */
+ unsigned int pgbase; /* zero-copy data */
+};
+
+struct nfs4_readdir_res {
+ nfs4_verifier verifier;
+ unsigned int pgbase;
};
struct nfs4_readlink {
- u32 rl_count; /* zero-copy data */
- struct page ** rl_pages; /* zero-copy data */
+ const struct nfs_fh * fh;
+ u32 count; /* zero-copy data */
+ struct page ** pages; /* zero-copy data */
};
-struct nfs4_remove {
- u32 rm_namelen; /* request */
- const char * rm_name; /* request */
- struct nfs4_change_info * rm_cinfo; /* response */
+struct nfs4_remove_arg {
+ const struct nfs_fh * fh;
+ const struct qstr * name;
};
-struct nfs4_rename {
- u32 rn_oldnamelen; /* request */
- const char * rn_oldname; /* request */
- u32 rn_newnamelen; /* request */
- const char * rn_newname; /* request */
- struct nfs4_change_info * rn_src_cinfo; /* response */
- struct nfs4_change_info * rn_dst_cinfo; /* response */
+struct nfs4_rename_arg {
+ const struct nfs_fh * old_dir;
+ const struct nfs_fh * new_dir;
+ const struct qstr * old_name;
+ const struct qstr * new_name;
};
-struct nfs4_setattr {
- char * st_stateid; /* request */
- struct iattr * st_iap; /* request */
+struct nfs4_rename_res {
+ struct nfs4_change_info old_cinfo;
+ struct nfs4_change_info new_cinfo;
};
struct nfs4_setclientid {
@@ -606,70 +606,37 @@ struct nfs4_setclientid {
struct nfs4_client * sc_state; /* response */
};
-struct nfs4_op {
- u32 opnum;
- union {
- struct nfs4_access access;
- struct nfs4_close close;
- struct nfs4_create create;
- struct nfs4_getattr getattr;
- struct nfs4_getfh getfh;
- struct nfs4_link link;
- struct nfs4_lookup lookup;
- struct nfs4_open open;
- struct nfs4_open_confirm open_confirm;
- struct nfs4_putfh putfh;
- struct nfs4_readdir readdir;
- struct nfs4_readlink readlink;
- struct nfs4_remove remove;
- struct nfs4_rename rename;
- struct nfs4_client * renew;
- struct nfs4_setattr setattr;
- } u;
+struct nfs4_statfs_arg {
+ const struct nfs_fh * fh;
+ const u32 * bitmask;
};
-struct nfs4_compound {
- unsigned int flags; /* defined below */
- struct nfs_server * server;
-
- /* RENEW information */
- int renew_index;
- unsigned long timestamp;
-
- /* scratch variables for XDR encode/decode */
- int nops;
- u32 * p;
- u32 * end;
-
- /* the individual COMPOUND operations */
- struct nfs4_op *ops;
-
- /* request */
- int req_nops;
- u32 taglen;
- char * tag;
-
- /* response */
- int resp_nops;
- int toplevel_status;
+struct nfs4_server_caps_res {
+ u32 attr_bitmask[2];
+ u32 acl_bitmask;
+ u32 has_links;
+ u32 has_symlinks;
};
#endif /* CONFIG_NFS_V4 */
+struct nfs_page;
+
struct nfs_read_data {
int flags;
struct rpc_task task;
struct inode *inode;
struct rpc_cred *cred;
- fl_owner_t lockowner;
struct nfs_fattr fattr; /* fattr storage */
struct list_head pages; /* Coalesced read requests */
+ struct nfs_page *req; /* multi ops per nfs_page */
struct page *pagevec[NFS_READ_MAXIOV];
struct nfs_readargs args;
struct nfs_readres res;
#ifdef CONFIG_NFS_V4
unsigned long timestamp; /* For lease renewal */
#endif
+ void (*complete) (struct nfs_read_data *, int);
};
struct nfs_write_data {
@@ -677,20 +644,19 @@ 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 */
+ struct nfs_page *req; /* multi ops per nfs_page */
struct page *pagevec[NFS_WRITE_MAXIOV];
struct nfs_writeargs args; /* argument struct */
struct nfs_writeres res; /* result struct */
#ifdef CONFIG_NFS_V4
unsigned long timestamp; /* For lease renewal */
#endif
+ void (*complete) (struct nfs_write_data *, int);
};
-struct nfs_page;
-
/*
* RPC procedure vector for NFSv2/NFSv3 demuxing
*/
@@ -737,9 +703,9 @@ struct nfs_rpc_ops {
int (*pathconf) (struct nfs_server *, struct nfs_fh *,
struct nfs_pathconf *);
u32 * (*decode_dirent)(u32 *, struct nfs_entry *, int plus);
- 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);
+ void (*read_setup) (struct nfs_read_data *);
+ 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 *);
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h
index 6b8e3eb91513..be2e6ef3b793 100644
--- a/include/linux/sunrpc/sched.h
+++ b/include/linux/sunrpc/sched.h
@@ -49,6 +49,8 @@ struct rpc_task {
tk_cred_retry,
tk_suid_retry;
+ unsigned long tk_cookie; /* Cookie for batching tasks */
+
/*
* timeout_fn to be executed by timer bottom half
* callback to be executed after waking up
@@ -72,7 +74,9 @@ struct rpc_task {
unsigned long tk_timeout; /* timeout for rpc_sleep() */
unsigned short tk_flags; /* misc flags */
unsigned char tk_active : 1;/* Task has been activated */
+ unsigned char tk_priority : 2;/* Task priority */
unsigned long tk_runstate; /* Task run status */
+ struct list_head tk_links; /* links to related tasks */
#ifdef RPC_DEBUG
unsigned short tk_pid; /* debugging aid */
#endif
@@ -138,28 +142,58 @@ typedef void (*rpc_action)(struct rpc_task *);
} while(0)
/*
+ * Task priorities.
+ * Note: if you change these, you must also change
+ * the task initialization definitions below.
+ */
+#define RPC_PRIORITY_LOW 0
+#define RPC_PRIORITY_NORMAL 1
+#define RPC_PRIORITY_HIGH 2
+#define RPC_NR_PRIORITY (RPC_PRIORITY_HIGH+1)
+
+/*
* RPC synchronization objects
*/
struct rpc_wait_queue {
- struct list_head tasks;
+ struct list_head tasks[RPC_NR_PRIORITY]; /* task queue for each priority level */
+ unsigned long cookie; /* cookie of last task serviced */
+ unsigned char maxpriority; /* maximum priority (0 if queue is not a priority queue) */
+ unsigned char priority; /* current priority */
+ unsigned char count; /* # task groups remaining serviced so far */
+ unsigned char nr; /* # tasks remaining for cookie */
#ifdef RPC_DEBUG
- char * name;
+ const char * name;
#endif
};
+/*
+ * This is the # requests to send consecutively
+ * from a single cookie. The aim is to improve
+ * performance of NFS operations such as read/write.
+ */
+#define RPC_BATCH_COUNT 16
+
#ifndef RPC_DEBUG
-# define RPC_WAITQ_INIT(var,qname) ((struct rpc_wait_queue) {LIST_HEAD_INIT(var)})
-# define RPC_WAITQ(var,qname) struct rpc_wait_queue var = RPC_WAITQ_INIT(var.tasks,qname)
-# define INIT_RPC_WAITQ(ptr,qname) do { \
- INIT_LIST_HEAD(&(ptr)->tasks); \
- } while(0)
+# define RPC_WAITQ_INIT(var,qname) { \
+ .tasks = { \
+ [0] = LIST_HEAD_INIT(var.tasks[0]), \
+ [1] = LIST_HEAD_INIT(var.tasks[1]), \
+ [2] = LIST_HEAD_INIT(var.tasks[2]), \
+ }, \
+ }
#else
-# define RPC_WAITQ_INIT(var,qname) ((struct rpc_wait_queue) {LIST_HEAD_INIT(var.tasks), qname})
-# define RPC_WAITQ(var,qname) struct rpc_wait_queue var = RPC_WAITQ_INIT(var,qname)
-# define INIT_RPC_WAITQ(ptr,qname) do { \
- INIT_LIST_HEAD(&(ptr)->tasks); (ptr)->name = qname; \
- } while(0)
+# define RPC_WAITQ_INIT(var,qname) { \
+ .tasks = { \
+ [0] = LIST_HEAD_INIT(var.tasks[0]), \
+ [1] = LIST_HEAD_INIT(var.tasks[1]), \
+ [2] = LIST_HEAD_INIT(var.tasks[2]), \
+ }, \
+ .name = qname, \
+ }
#endif
+# define RPC_WAITQ(var,qname) struct rpc_wait_queue var = RPC_WAITQ_INIT(var,qname)
+
+#define RPC_IS_PRIORITY(q) ((q)->maxpriority > 0)
/*
* Function prototypes
@@ -175,6 +209,8 @@ void rpc_run_child(struct rpc_task *parent, struct rpc_task *child,
rpc_action action);
int rpc_add_wait_queue(struct rpc_wait_queue *, struct rpc_task *);
void rpc_remove_wait_queue(struct rpc_task *);
+void rpc_init_priority_wait_queue(struct rpc_wait_queue *, const char *);
+void rpc_init_wait_queue(struct rpc_wait_queue *, const char *);
void rpc_sleep_on(struct rpc_wait_queue *, struct rpc_task *,
rpc_action action, rpc_action timer);
void rpc_add_timer(struct rpc_task *, rpc_action);
@@ -194,16 +230,14 @@ void rpc_show_tasks(void);
int rpc_init_mempool(void);
void rpc_destroy_mempool(void);
-static __inline__ void
-rpc_exit(struct rpc_task *task, int status)
+static inline void rpc_exit(struct rpc_task *task, int status)
{
task->tk_status = status;
task->tk_action = NULL;
}
#ifdef RPC_DEBUG
-static __inline__ char *
-rpc_qname(struct rpc_wait_queue *q)
+static inline const char * rpc_qname(struct rpc_wait_queue *q)
{
return ((q && q->name) ? q->name : "unknown");
}
diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
index 2b334dc19962..0b9aecd9b8c3 100644
--- a/include/linux/sunrpc/xdr.h
+++ b/include/linux/sunrpc/xdr.h
@@ -55,7 +55,8 @@ struct xdr_buf {
unsigned int page_base, /* Start of page data */
page_len; /* Length of page data */
- unsigned int len; /* Total length of data */
+ unsigned int buflen, /* Total length of storage buffer */
+ len; /* Length of XDR encoded message */
};
@@ -87,7 +88,8 @@ struct xdr_buf {
/*
* Miscellaneous XDR helper functions
*/
-u32 * xdr_encode_array(u32 *p, const void *s, unsigned int len);
+u32 * xdr_encode_opaque_fixed(u32 *p, const void *ptr, unsigned int len);
+u32 * xdr_encode_opaque(u32 *p, const void *ptr, unsigned int len);
u32 * xdr_encode_string(u32 *p, const char *s);
u32 * xdr_decode_string(u32 *p, char **sp, int *lenp, int maxlen);
u32 * xdr_decode_string_inplace(u32 *p, char **sp, int *lenp, int maxlen);
@@ -100,6 +102,11 @@ void xdr_encode_pages(struct xdr_buf *, struct page **, unsigned int,
void xdr_inline_pages(struct xdr_buf *, unsigned int,
struct page **, unsigned int, unsigned int);
+static inline u32 *xdr_encode_array(u32 *p, const void *s, unsigned int len)
+{
+ return xdr_encode_opaque(p, s, len);
+}
+
/*
* Decode 64bit quantities (NFSv3 support)
*/
@@ -178,86 +185,14 @@ struct xdr_stream {
struct iovec *iov; /* pointer to the current iovec */
};
-/*
- * Initialize an xdr_stream for encoding data.
- *
- * Note: at the moment the RPC client only passes the length of our
- * scratch buffer in the xdr_buf's header iovec. Previously this
- * meant we needed to call xdr_adjust_iovec() after encoding the
- * data. With the new scheme, the xdr_stream manages the details
- * of the buffer length, and takes care of adjusting the iovec
- * length for us.
- */
-static inline void
-xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p)
-{
- struct iovec *iov = buf->head;
-
- xdr->buf = buf;
- xdr->iov = iov;
- xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len);
- buf->len = iov->iov_len = (char *)p - (char *)iov->iov_base;
- xdr->p = p;
-}
-
-/*
- * Check that we have enough buffer space to encode 'nbytes' more
- * bytes of data. If so, update the total xdr_buf length, and
- * adjust the length of the current iovec.
- */
-static inline uint32_t *
-xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes)
-{
- uint32_t *p = xdr->p;
- uint32_t *q;
-
- /* align nbytes on the next 32-bit boundary */
- nbytes += 3;
- nbytes &= ~3;
- q = p + (nbytes >> 2);
- if (unlikely(q > xdr->end || q < p))
- return NULL;
- xdr->p = q;
- xdr->iov->iov_len += nbytes;
- xdr->buf->len += nbytes;
- return p;
-}
-
+extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p);
+extern uint32_t *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes);
extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages,
unsigned int base, unsigned int len);
+extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p);
+extern uint32_t *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes);
extern void xdr_read_pages(struct xdr_stream *xdr, unsigned int len);
-/*
- * Initialize an xdr_stream for decoding data.
- */
-static inline void
-xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p)
-{
- struct iovec *iov = buf->head;
- xdr->buf = buf;
- xdr->iov = iov;
- xdr->p = p;
- xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len);
-}
-
-/*
- * Check if the input buffer is long enough to enable us to decode
- * 'nbytes' more bytes of data starting at the current position.
- * If so return the current pointer, then update the current
- * position.
- */
-static inline uint32_t *
-xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
-{
- uint32_t *p = xdr->p;
- uint32_t *q = p + XDR_QUADLEN(nbytes);
-
- if (unlikely(q > xdr->end || q < p))
- return NULL;
- xdr->p = q;
- return p;
-}
-
#endif /* __KERNEL__ */
#endif /* _SUNRPC_XDR_H_ */
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index e6d79afcb50c..5222a8f4c580 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -120,8 +120,6 @@ struct rpc_rqst {
};
#define rq_svec rq_snd_buf.head
#define rq_slen rq_snd_buf.len
-#define rq_rvec rq_rcv_buf.head
-#define rq_rlen rq_rcv_buf.len
#define XPRT_LAST_FRAG (1 << 0)
#define XPRT_COPY_RECM (1 << 1)
@@ -218,12 +216,15 @@ void xprt_connect(struct rpc_task *);
int xprt_clear_backlog(struct rpc_xprt *);
void xprt_sock_setbufsize(struct rpc_xprt *);
-#define XPRT_CONNECT 0
-#define XPRT_LOCKED 1
+#define XPRT_LOCKED 0
+#define XPRT_CONNECT 1
+#define XPRT_CONNECTING 2
#define xprt_connected(xp) (test_bit(XPRT_CONNECT, &(xp)->sockstate))
#define xprt_set_connected(xp) (set_bit(XPRT_CONNECT, &(xp)->sockstate))
#define xprt_test_and_set_connected(xp) (test_and_set_bit(XPRT_CONNECT, &(xp)->sockstate))
+#define xprt_test_and_clear_connected(xp) \
+ (test_and_clear_bit(XPRT_CONNECT, &(xp)->sockstate))
#define xprt_clear_connected(xp) (clear_bit(XPRT_CONNECT, &(xp)->sockstate))
#endif /* __KERNEL__*/
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index ccfd79a71e54..b1b922f09257 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -365,7 +365,7 @@ retry:
gss_msg = gss_new;
memset(gss_new, 0, sizeof(*gss_new));
INIT_LIST_HEAD(&gss_new->list);
- INIT_RPC_WAITQ(&gss_new->waitq, "RPCSEC_GSS upcall waitq");
+ rpc_init_wait_queue(&gss_new->waitq, "RPCSEC_GSS upcall waitq");
atomic_set(&gss_new->count, 2);
msg = &gss_new->msg;
msg->data = &gss_new->uid;
@@ -721,8 +721,7 @@ gss_marshal(struct rpc_task *task, u32 *p, int ruid)
printk("gss_marshal: gss_get_mic FAILED (%d)\n", maj_stat);
goto out_put_ctx;
}
- *p++ = htonl(mic.len);
- p += XDR_QUADLEN(mic.len);
+ p = xdr_encode_opaque(p, NULL, mic.len);
gss_put_ctx(ctx);
return p;
out_put_ctx:
@@ -857,9 +856,7 @@ gss_wrap_req(struct rpc_task *task,
status = -EIO; /* XXX? */
if (maj_stat)
goto out;
- q = p;
- *q++ = htonl(mic.len);
- q += XDR_QUADLEN(mic.len);
+ q = xdr_encode_opaque(p, NULL, mic.len);
offset = (u8 *)q - (u8 *)p;
iov->iov_len += offset;
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index 5a5f859ad628..9c53c74943ae 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -40,6 +40,7 @@
#include <asm/scatterlist.h>
#include <linux/crypto.h>
#include <linux/highmem.h>
+#include <linux/pagemap.h>
#include <linux/sunrpc/gss_krb5.h>
#ifdef RPC_DEBUG
@@ -171,22 +172,24 @@ krb5_make_checksum(s32 cksumtype, char *header, struct xdr_buf *body,
}
len = body->page_len;
- offset = body->page_base;
- i = 0;
- while (len) {
- sg->page = body->pages[i];
- sg->offset = offset;
- offset = 0;
- if (PAGE_SIZE > len)
- thislen = len;
- else
- thislen = PAGE_SIZE;
- sg->length = thislen;
- kmap(sg->page); /* XXX kmap_atomic? */
- crypto_digest_update(tfm, sg, 1);
- kunmap(sg->page);
- len -= thislen;
- i++;
+ if (len != 0) {
+ offset = body->page_base & (PAGE_CACHE_SIZE - 1);
+ i = body->page_base >> PAGE_CACHE_SHIFT;
+ thislen = PAGE_CACHE_SIZE - offset;
+ do {
+ if (thislen > len)
+ thislen = len;
+ sg->page = body->pages[i];
+ sg->offset = offset;
+ sg->length = thislen;
+ kmap(sg->page); /* XXX kmap_atomic? */
+ crypto_digest_update(tfm, sg, 1);
+ kunmap(sg->page);
+ len -= thislen;
+ i++;
+ offset = 0;
+ thislen = PAGE_CACHE_SIZE;
+ } while(len != 0);
}
if (body->tail[0].iov_len) {
buf_to_sg(sg, body->tail[0].iov_base, body->tail[0].iov_len);
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 43f6e8e27b6a..1696c16b2bc9 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -144,7 +144,7 @@ rpc_create_client(struct rpc_xprt *xprt, char *servname,
clnt->cl_vers = version->number;
clnt->cl_prot = xprt->prot;
clnt->cl_stats = program->stats;
- INIT_RPC_WAITQ(&clnt->cl_pmap_default.pm_bindwait, "bindwait");
+ rpc_init_wait_queue(&clnt->cl_pmap_default.pm_bindwait, "bindwait");
if (!clnt->cl_port)
clnt->cl_autobind = 1;
@@ -605,11 +605,13 @@ call_encode(struct rpc_task *task)
sndbuf->tail[0].iov_len = 0;
sndbuf->page_len = 0;
sndbuf->len = 0;
+ sndbuf->buflen = bufsiz;
rcvbuf->head[0].iov_base = (void *)((char *)task->tk_buffer + bufsiz);
rcvbuf->head[0].iov_len = bufsiz;
rcvbuf->tail[0].iov_len = 0;
rcvbuf->page_len = 0;
- rcvbuf->len = bufsiz;
+ rcvbuf->len = 0;
+ rcvbuf->buflen = bufsiz;
/* Encode header and provided arguments */
encode = task->tk_msg.rpc_proc->p_encode;
@@ -849,6 +851,8 @@ call_decode(struct rpc_task *task)
return;
}
+ req->rq_rcv_buf.len = req->rq_private_buf.len;
+
/* Check that the softirq receive buffer is valid */
WARN_ON(memcmp(&req->rq_rcv_buf, &req->rq_private_buf,
sizeof(req->rq_rcv_buf)) != 0);
@@ -884,7 +888,7 @@ call_decode(struct rpc_task *task)
task->tk_status);
return;
out_retry:
- req->rq_received = 0;
+ req->rq_received = req->rq_private_buf.len = 0;
task->tk_status = 0;
}
@@ -956,7 +960,7 @@ call_header(struct rpc_task *task)
static u32 *
call_verify(struct rpc_task *task)
{
- u32 *p = task->tk_rqstp->rq_rvec[0].iov_base, n;
+ u32 *p = task->tk_rqstp->rq_rcv_buf.head[0].iov_base, n;
p += 1; /* skip XID */
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index 3d3f79aae25f..374b6764331a 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -162,6 +162,26 @@ rpc_delete_timer(struct rpc_task *task)
}
/*
+ * Add new request to a priority queue.
+ */
+static void __rpc_add_wait_queue_priority(struct rpc_wait_queue *queue, struct rpc_task *task)
+{
+ struct list_head *q;
+ struct rpc_task *t;
+
+ q = &queue->tasks[task->tk_priority];
+ if (unlikely(task->tk_priority > queue->maxpriority))
+ q = &queue->tasks[queue->maxpriority];
+ list_for_each_entry(t, q, tk_list) {
+ if (t->tk_cookie == task->tk_cookie) {
+ list_add_tail(&task->tk_list, &t->tk_links);
+ return;
+ }
+ }
+ list_add_tail(&task->tk_list, q);
+}
+
+/*
* Add new request to wait queue.
*
* Swapper tasks always get inserted at the head of the queue.
@@ -169,8 +189,7 @@ rpc_delete_timer(struct rpc_task *task)
* improve overall performance.
* Everyone else gets appended to the queue to ensure proper FIFO behavior.
*/
-static inline int
-__rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task)
+static int __rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task)
{
if (task->tk_rpcwait == queue)
return 0;
@@ -179,10 +198,12 @@ __rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task)
printk(KERN_WARNING "RPC: doubly enqueued task!\n");
return -EWOULDBLOCK;
}
- if (RPC_IS_SWAPPER(task))
- list_add(&task->tk_list, &queue->tasks);
+ if (RPC_IS_PRIORITY(queue))
+ __rpc_add_wait_queue_priority(queue, task);
+ else if (RPC_IS_SWAPPER(task))
+ list_add(&task->tk_list, &queue->tasks[0]);
else
- list_add_tail(&task->tk_list, &queue->tasks);
+ list_add_tail(&task->tk_list, &queue->tasks[0]);
task->tk_rpcwait = queue;
dprintk("RPC: %4d added to queue %p \"%s\"\n",
@@ -191,8 +212,7 @@ __rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task)
return 0;
}
-int
-rpc_add_wait_queue(struct rpc_wait_queue *q, struct rpc_task *task)
+int rpc_add_wait_queue(struct rpc_wait_queue *q, struct rpc_task *task)
{
int result;
@@ -203,18 +223,35 @@ rpc_add_wait_queue(struct rpc_wait_queue *q, struct rpc_task *task)
}
/*
+ * Remove request from a priority queue.
+ */
+static void __rpc_remove_wait_queue_priority(struct rpc_task *task)
+{
+ struct rpc_task *t;
+
+ if (!list_empty(&task->tk_links)) {
+ t = list_entry(task->tk_links.next, struct rpc_task, tk_list);
+ list_move(&t->tk_list, &task->tk_list);
+ list_splice_init(&task->tk_links, &t->tk_links);
+ }
+ list_del(&task->tk_list);
+}
+
+/*
* Remove request from queue.
* Note: must be called with spin lock held.
*/
-static inline void
-__rpc_remove_wait_queue(struct rpc_task *task)
+static void __rpc_remove_wait_queue(struct rpc_task *task)
{
struct rpc_wait_queue *queue = task->tk_rpcwait;
if (!queue)
return;
- list_del(&task->tk_list);
+ if (RPC_IS_PRIORITY(queue))
+ __rpc_remove_wait_queue_priority(task);
+ else
+ list_del(&task->tk_list);
task->tk_rpcwait = NULL;
dprintk("RPC: %4d removed from queue %p \"%s\"\n",
@@ -231,6 +268,48 @@ rpc_remove_wait_queue(struct rpc_task *task)
spin_unlock_bh(&rpc_queue_lock);
}
+static inline void rpc_set_waitqueue_priority(struct rpc_wait_queue *queue, int priority)
+{
+ queue->priority = priority;
+ queue->count = 1 << (priority * 2);
+}
+
+static inline void rpc_set_waitqueue_cookie(struct rpc_wait_queue *queue, unsigned long cookie)
+{
+ queue->cookie = cookie;
+ queue->nr = RPC_BATCH_COUNT;
+}
+
+static inline void rpc_reset_waitqueue_priority(struct rpc_wait_queue *queue)
+{
+ rpc_set_waitqueue_priority(queue, queue->maxpriority);
+ rpc_set_waitqueue_cookie(queue, 0);
+}
+
+static void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname, int maxprio)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(queue->tasks); i++)
+ INIT_LIST_HEAD(&queue->tasks[i]);
+ queue->maxpriority = maxprio;
+ rpc_reset_waitqueue_priority(queue);
+#ifdef RPC_DEBUG
+ queue->name = qname;
+#endif
+}
+
+void rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname)
+{
+ __rpc_init_priority_wait_queue(queue, qname, RPC_PRIORITY_HIGH);
+}
+
+void rpc_init_wait_queue(struct rpc_wait_queue *queue, const char *qname)
+{
+ __rpc_init_priority_wait_queue(queue, qname, 0);
+}
+EXPORT_SYMBOL(rpc_init_wait_queue);
+
/*
* Make an RPC task runnable.
*
@@ -255,13 +334,11 @@ rpc_make_runnable(struct rpc_task *task)
return;
}
rpc_clear_sleeping(task);
- if (waitqueue_active(&rpciod_idle))
- wake_up(&rpciod_idle);
+ wake_up(&rpciod_idle);
}
} else {
rpc_clear_sleeping(task);
- if (waitqueue_active(&task->tk_wait))
- wake_up(&task->tk_wait);
+ wake_up(&task->tk_wait);
}
}
@@ -287,8 +364,7 @@ void rpciod_wake_up(void)
{
if(rpciod_pid==0)
printk(KERN_ERR "rpciod: wot no daemon?\n");
- if (waitqueue_active(&rpciod_idle))
- wake_up(&rpciod_idle);
+ wake_up(&rpciod_idle);
}
/*
@@ -406,17 +482,72 @@ rpc_wake_up_task(struct rpc_task *task)
}
/*
+ * Wake up the next task on a priority queue.
+ */
+static struct rpc_task * __rpc_wake_up_next_priority(struct rpc_wait_queue *queue)
+{
+ struct list_head *q;
+ struct rpc_task *task;
+
+ /*
+ * Service a batch of tasks from a single cookie.
+ */
+ q = &queue->tasks[queue->priority];
+ if (!list_empty(q)) {
+ task = list_entry(q->next, struct rpc_task, tk_list);
+ if (queue->cookie == task->tk_cookie) {
+ if (--queue->nr)
+ goto out;
+ list_move_tail(&task->tk_list, q);
+ }
+ /*
+ * Check if we need to switch queues.
+ */
+ if (--queue->count)
+ goto new_cookie;
+ }
+
+ /*
+ * Service the next queue.
+ */
+ do {
+ if (q == &queue->tasks[0])
+ q = &queue->tasks[queue->maxpriority];
+ else
+ q = q - 1;
+ if (!list_empty(q)) {
+ task = list_entry(q->next, struct rpc_task, tk_list);
+ goto new_queue;
+ }
+ } while (q != &queue->tasks[queue->priority]);
+
+ rpc_reset_waitqueue_priority(queue);
+ return NULL;
+
+new_queue:
+ rpc_set_waitqueue_priority(queue, (unsigned int)(q - &queue->tasks[0]));
+new_cookie:
+ rpc_set_waitqueue_cookie(queue, task->tk_cookie);
+out:
+ __rpc_wake_up_task(task);
+ return task;
+}
+
+/*
* Wake up the next task on the wait queue.
*/
-struct rpc_task *
-rpc_wake_up_next(struct rpc_wait_queue *queue)
+struct rpc_task * rpc_wake_up_next(struct rpc_wait_queue *queue)
{
struct rpc_task *task = NULL;
dprintk("RPC: wake_up_next(%p \"%s\")\n", queue, rpc_qname(queue));
spin_lock_bh(&rpc_queue_lock);
- task_for_first(task, &queue->tasks)
- __rpc_wake_up_task(task);
+ if (RPC_IS_PRIORITY(queue))
+ task = __rpc_wake_up_next_priority(queue);
+ else {
+ task_for_first(task, &queue->tasks[0])
+ __rpc_wake_up_task(task);
+ }
spin_unlock_bh(&rpc_queue_lock);
return task;
@@ -428,15 +559,22 @@ rpc_wake_up_next(struct rpc_wait_queue *queue)
*
* Grabs rpc_queue_lock
*/
-void
-rpc_wake_up(struct rpc_wait_queue *queue)
+void rpc_wake_up(struct rpc_wait_queue *queue)
{
struct rpc_task *task;
+ struct list_head *head;
spin_lock_bh(&rpc_queue_lock);
- while (!list_empty(&queue->tasks))
- task_for_first(task, &queue->tasks)
+ head = &queue->tasks[queue->maxpriority];
+ for (;;) {
+ while (!list_empty(head)) {
+ task = list_entry(head->next, struct rpc_task, tk_list);
__rpc_wake_up_task(task);
+ }
+ if (head == &queue->tasks[0])
+ break;
+ head--;
+ }
spin_unlock_bh(&rpc_queue_lock);
}
@@ -447,17 +585,22 @@ rpc_wake_up(struct rpc_wait_queue *queue)
*
* Grabs rpc_queue_lock
*/
-void
-rpc_wake_up_status(struct rpc_wait_queue *queue, int status)
+void rpc_wake_up_status(struct rpc_wait_queue *queue, int status)
{
+ struct list_head *head;
struct rpc_task *task;
spin_lock_bh(&rpc_queue_lock);
- while (!list_empty(&queue->tasks)) {
- task_for_first(task, &queue->tasks) {
+ head = &queue->tasks[queue->maxpriority];
+ for (;;) {
+ while (!list_empty(head)) {
+ task = list_entry(head->next, struct rpc_task, tk_list);
task->tk_status = status;
__rpc_wake_up_task(task);
}
+ if (head == &queue->tasks[0])
+ break;
+ head--;
}
spin_unlock_bh(&rpc_queue_lock);
}
@@ -643,21 +786,22 @@ __rpc_schedule(void)
dprintk("RPC: rpc_schedule enter\n");
while (1) {
- spin_lock_bh(&rpc_queue_lock);
- task_for_first(task, &schedq.tasks) {
+ task_for_first(task, &schedq.tasks[0]) {
__rpc_remove_wait_queue(task);
spin_unlock_bh(&rpc_queue_lock);
__rpc_execute(task);
+ spin_lock_bh(&rpc_queue_lock);
} else {
- spin_unlock_bh(&rpc_queue_lock);
break;
}
if (++count >= 200 || need_resched()) {
count = 0;
+ spin_unlock_bh(&rpc_queue_lock);
schedule();
+ spin_lock_bh(&rpc_queue_lock);
}
}
dprintk("RPC: rpc_schedule leave\n");
@@ -709,9 +853,7 @@ rpc_free(struct rpc_task *task)
/*
* Creation and deletion of RPC task structures
*/
-inline void
-rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt,
- rpc_action callback, int flags)
+void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, rpc_action callback, int flags)
{
memset(task, 0, sizeof(*task));
init_timer(&task->tk_timer);
@@ -729,6 +871,10 @@ rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt,
task->tk_cred_retry = 2;
task->tk_suid_retry = 1;
+ task->tk_priority = RPC_PRIORITY_NORMAL;
+ task->tk_cookie = (unsigned long)current;
+ INIT_LIST_HEAD(&task->tk_links);
+
/* Add to global list of all tasks */
spin_lock(&rpc_sched_lock);
list_add(&task->tk_task, &all_tasks);
@@ -866,7 +1012,7 @@ rpc_find_parent(struct rpc_task *child)
struct list_head *le;
parent = (struct rpc_task *) child->tk_calldata;
- task_for_each(task, le, &childq.tasks)
+ task_for_each(task, le, &childq.tasks[0])
if (task == parent)
return parent;
@@ -946,7 +1092,7 @@ static DECLARE_MUTEX_LOCKED(rpciod_running);
static inline int
rpciod_task_pending(void)
{
- return !list_empty(&schedq.tasks);
+ return !list_empty(&schedq.tasks[0]);
}
@@ -969,27 +1115,41 @@ rpciod(void *ptr)
allow_signal(SIGKILL);
dprintk("RPC: rpciod starting (pid %d)\n", rpciod_pid);
+ spin_lock_bh(&rpc_queue_lock);
while (rpciod_users) {
+ DEFINE_WAIT(wait);
if (signalled()) {
+ spin_unlock_bh(&rpc_queue_lock);
rpciod_killall();
flush_signals(current);
+ spin_lock_bh(&rpc_queue_lock);
}
__rpc_schedule();
- if (current->flags & PF_FREEZE)
+ if (current->flags & PF_FREEZE) {
+ spin_unlock_bh(&rpc_queue_lock);
refrigerator(PF_IOTHREAD);
+ spin_lock_bh(&rpc_queue_lock);
+ }
if (++rounds >= 64) { /* safeguard */
+ spin_unlock_bh(&rpc_queue_lock);
schedule();
rounds = 0;
+ spin_lock_bh(&rpc_queue_lock);
}
- if (!rpciod_task_pending()) {
- dprintk("RPC: rpciod back to sleep\n");
- wait_event_interruptible(rpciod_idle, rpciod_task_pending());
- dprintk("RPC: switch to rpciod\n");
+ dprintk("RPC: rpciod back to sleep\n");
+ prepare_to_wait(&rpciod_idle, &wait, TASK_INTERRUPTIBLE);
+ if (!rpciod_task_pending() && !signalled()) {
+ spin_unlock_bh(&rpc_queue_lock);
+ schedule();
rounds = 0;
+ spin_lock_bh(&rpc_queue_lock);
}
+ finish_wait(&rpciod_idle, &wait);
+ dprintk("RPC: switch to rpciod\n");
}
+ spin_unlock_bh(&rpc_queue_lock);
dprintk("RPC: rpciod shutdown commences\n");
if (!list_empty(&all_tasks)) {
@@ -1013,7 +1173,9 @@ rpciod_killall(void)
while (!list_empty(&all_tasks)) {
clear_thread_flag(TIF_SIGPENDING);
rpc_killall_tasks(NULL);
+ spin_lock_bh(&rpc_queue_lock);
__rpc_schedule();
+ spin_unlock_bh(&rpc_queue_lock);
if (!list_empty(&all_tasks)) {
dprintk("rpciod_killall: waiting for tasks to exit\n");
yield();
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index 1ae41edbb0f1..b6ef7772b3aa 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -120,7 +120,6 @@ EXPORT_SYMBOL(svcauth_unix_purge);
EXPORT_SYMBOL(unix_domain_find);
/* Generic XDR */
-EXPORT_SYMBOL(xdr_encode_array);
EXPORT_SYMBOL(xdr_encode_string);
EXPORT_SYMBOL(xdr_decode_string);
EXPORT_SYMBOL(xdr_decode_string_inplace);
@@ -129,8 +128,6 @@ EXPORT_SYMBOL(xdr_encode_netobj);
EXPORT_SYMBOL(xdr_encode_pages);
EXPORT_SYMBOL(xdr_inline_pages);
EXPORT_SYMBOL(xdr_shift_buf);
-EXPORT_SYMBOL(xdr_write_pages);
-EXPORT_SYMBOL(xdr_read_pages);
EXPORT_SYMBOL(xdr_buf_from_iov);
EXPORT_SYMBOL(xdr_buf_subsegment);
EXPORT_SYMBOL(xdr_buf_read_netobj);
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index cae451e8db8d..c7d8bb459c9a 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -53,16 +53,50 @@ xdr_decode_netobj(u32 *p, struct xdr_netobj *obj)
return p + XDR_QUADLEN(len);
}
-u32 *
-xdr_encode_array(u32 *p, const void *array, unsigned int len)
+/**
+ * xdr_encode_opaque_fixed - Encode fixed length opaque data
+ * @p - pointer to current position in XDR buffer.
+ * @ptr - pointer to data to encode (or NULL)
+ * @nbytes - size of data.
+ *
+ * Copy the array of data of length nbytes at ptr to the XDR buffer
+ * at position p, then align to the next 32-bit boundary by padding
+ * with zero bytes (see RFC1832).
+ * Note: if ptr is NULL, only the padding is performed.
+ *
+ * Returns the updated current XDR buffer position
+ *
+ */
+u32 *xdr_encode_opaque_fixed(u32 *p, const void *ptr, unsigned int nbytes)
{
- int quadlen = XDR_QUADLEN(len);
+ if (likely(nbytes != 0)) {
+ unsigned int quadlen = XDR_QUADLEN(nbytes);
+ unsigned int padding = (quadlen << 2) - nbytes;
+
+ if (ptr != NULL)
+ memcpy(p, ptr, nbytes);
+ if (padding != 0)
+ memset((char *)p + nbytes, 0, padding);
+ p += quadlen;
+ }
+ return p;
+}
+EXPORT_SYMBOL(xdr_encode_opaque_fixed);
- p[quadlen] = 0;
- *p++ = htonl(len);
- memcpy(p, array, len);
- return p + quadlen;
+/**
+ * xdr_encode_opaque - Encode variable length opaque data
+ * @p - pointer to current position in XDR buffer.
+ * @ptr - pointer to data to encode (or NULL)
+ * @nbytes - size of data.
+ *
+ * Returns the updated current XDR buffer position
+ */
+u32 *xdr_encode_opaque(u32 *p, const void *ptr, unsigned int nbytes)
+{
+ *p++ = htonl(nbytes);
+ return xdr_encode_opaque_fixed(p, ptr, nbytes);
}
+EXPORT_SYMBOL(xdr_encode_opaque);
u32 *
xdr_encode_string(u32 *p, const char *string)
@@ -126,6 +160,7 @@ xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base,
tail->iov_len = pad;
len += pad;
}
+ xdr->buflen += len;
xdr->len += len;
}
@@ -147,7 +182,7 @@ xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset,
tail->iov_base = buf + offset;
tail->iov_len = buflen - offset;
- xdr->len += len;
+ xdr->buflen += len;
}
/*
@@ -641,7 +676,10 @@ xdr_shrink_bufhead(struct xdr_buf *buf, size_t len)
copy);
}
head->iov_len -= len;
- buf->len -= len;
+ buf->buflen -= len;
+ /* Have we truncated the message? */
+ if (buf->len > buf->buflen)
+ buf->len = buf->buflen;
}
/*
@@ -671,7 +709,7 @@ xdr_shrink_pagelen(struct xdr_buf *buf, size_t len)
copy = tail->iov_len - len;
memmove(p, tail->iov_base, copy);
} else
- buf->len -= len;
+ buf->buflen -= len;
/* Copy from the inlined pages into the tail */
copy = len;
if (copy > tail->iov_len)
@@ -681,7 +719,10 @@ xdr_shrink_pagelen(struct xdr_buf *buf, size_t len)
copy);
}
buf->page_len -= len;
- buf->len -= len;
+ buf->buflen -= len;
+ /* Have we truncated the message? */
+ if (buf->len > buf->buflen)
+ buf->len = buf->buflen;
}
void
@@ -690,8 +731,67 @@ xdr_shift_buf(struct xdr_buf *buf, size_t len)
xdr_shrink_bufhead(buf, len);
}
-void
-xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int base,
+/**
+ * xdr_init_encode - Initialize a struct xdr_stream for sending data.
+ * @xdr: pointer to xdr_stream struct
+ * @buf: pointer to XDR buffer in which to encode data
+ * @p: current pointer inside XDR buffer
+ *
+ * Note: at the moment the RPC client only passes the length of our
+ * scratch buffer in the xdr_buf's header iovec. Previously this
+ * meant we needed to call xdr_adjust_iovec() after encoding the
+ * data. With the new scheme, the xdr_stream manages the details
+ * of the buffer length, and takes care of adjusting the iovec
+ * length for us.
+ */
+void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p)
+{
+ struct iovec *iov = buf->head;
+
+ xdr->buf = buf;
+ xdr->iov = iov;
+ xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len);
+ buf->len = iov->iov_len = (char *)p - (char *)iov->iov_base;
+ xdr->p = p;
+}
+EXPORT_SYMBOL(xdr_init_encode);
+
+/**
+ * xdr_reserve_space - Reserve buffer space for sending
+ * @xdr: pointer to xdr_stream
+ * @nbytes: number of bytes to reserve
+ *
+ * Checks that we have enough buffer space to encode 'nbytes' more
+ * bytes of data. If so, update the total xdr_buf length, and
+ * adjust the length of the current iovec.
+ */
+uint32_t * xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes)
+{
+ uint32_t *p = xdr->p;
+ uint32_t *q;
+
+ /* align nbytes on the next 32-bit boundary */
+ nbytes += 3;
+ nbytes &= ~3;
+ q = p + (nbytes >> 2);
+ if (unlikely(q > xdr->end || q < p))
+ return NULL;
+ xdr->p = q;
+ xdr->iov->iov_len += nbytes;
+ xdr->buf->len += nbytes;
+ return p;
+}
+EXPORT_SYMBOL(xdr_reserve_space);
+
+/**
+ * xdr_write_pages - Insert a list of pages into an XDR buffer for sending
+ * @xdr: pointer to xdr_stream
+ * @pages: list of pages
+ * @base: offset of first byte
+ * @len: length of data in bytes
+ *
+ */
+void xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int base,
unsigned int len)
{
struct xdr_buf *buf = xdr->buf;
@@ -713,15 +813,69 @@ xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int base,
len += pad;
*xdr->p++ = 0;
}
+ buf->buflen += len;
buf->len += len;
}
+EXPORT_SYMBOL(xdr_write_pages);
-void
-xdr_read_pages(struct xdr_stream *xdr, unsigned int len)
+/**
+ * xdr_init_decode - Initialize an xdr_stream for decoding data.
+ * @xdr: pointer to xdr_stream struct
+ * @buf: pointer to XDR buffer from which to decode data
+ * @p: current pointer inside XDR buffer
+ */
+void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p)
+{
+ struct iovec *iov = buf->head;
+ unsigned int len = iov->iov_len;
+
+ if (len > buf->len)
+ len = buf->len;
+ xdr->buf = buf;
+ xdr->iov = iov;
+ xdr->p = p;
+ xdr->end = (uint32_t *)((char *)iov->iov_base + len);
+}
+EXPORT_SYMBOL(xdr_init_decode);
+
+/**
+ * xdr_inline_decode - Retrieve non-page XDR data to decode
+ * @xdr: pointer to xdr_stream struct
+ * @nbytes: number of bytes of data to decode
+ *
+ * Check if the input buffer is long enough to enable us to decode
+ * 'nbytes' more bytes of data starting at the current position.
+ * If so return the current pointer, then update the current
+ * pointer position.
+ */
+uint32_t * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
+{
+ uint32_t *p = xdr->p;
+ uint32_t *q = p + XDR_QUADLEN(nbytes);
+
+ if (unlikely(q > xdr->end || q < p))
+ return NULL;
+ xdr->p = q;
+ return p;
+}
+EXPORT_SYMBOL(xdr_inline_decode);
+
+/**
+ * xdr_read_pages - Ensure page-based XDR data to decode is aligned at current pointer position
+ * @xdr: pointer to xdr_stream struct
+ * @len: number of bytes of page data
+ *
+ * Moves data beyond the current pointer position from the XDR head[] buffer
+ * into the page list. Any data that lies beyond current position + "len"
+ * bytes is moved into the XDR tail[]. The current pointer is then
+ * repositioned at the beginning of the XDR tail.
+ */
+void xdr_read_pages(struct xdr_stream *xdr, unsigned int len)
{
struct xdr_buf *buf = xdr->buf;
struct iovec *iov;
ssize_t shift;
+ unsigned int end;
int padding;
/* Realign pages to current pointer position */
@@ -735,9 +889,21 @@ xdr_read_pages(struct xdr_stream *xdr, unsigned int len)
xdr_shrink_pagelen(buf, buf->page_len - len);
padding = (XDR_QUADLEN(len) << 2) - len;
xdr->iov = iov = buf->tail;
+ /* Compute remaining message length. */
+ end = iov->iov_len;
+ shift = buf->buflen - buf->len;
+ if (shift < end)
+ end -= shift;
+ else if (shift > 0)
+ end = 0;
+ /*
+ * Position current pointer at beginning of tail, and
+ * set remaining message length.
+ */
xdr->p = (uint32_t *)((char *)iov->iov_base + padding);
- xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len);
+ xdr->end = (uint32_t *)((char *)iov->iov_base + end);
}
+EXPORT_SYMBOL(xdr_read_pages);
static struct iovec empty_iov = {.iov_base = NULL, .iov_len = 0};
@@ -747,7 +913,7 @@ xdr_buf_from_iov(struct iovec *iov, struct xdr_buf *buf)
buf->head[0] = *iov;
buf->tail[0] = empty_iov;
buf->page_len = 0;
- buf->len = iov->iov_len;
+ buf->buflen = buf->len = iov->iov_len;
}
/* Sets subiov to the intersection of iov with the buffer of length len
@@ -777,7 +943,7 @@ xdr_buf_subsegment(struct xdr_buf *buf, struct xdr_buf *subbuf,
{
int i;
- subbuf->len = len;
+ subbuf->buflen = subbuf->len = len;
iov_subsegment(buf->head, subbuf->head, &base, &len);
if (base < buf->page_len) {
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 699ea68c03ee..757f39cf1f36 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -405,7 +405,6 @@ xprt_close(struct rpc_xprt *xprt)
sk->sk_write_space = xprt->old_write_space;
write_unlock_bh(&sk->sk_callback_lock);
- xprt_disconnect(xprt);
sk->sk_no_check = 0;
sock_release(sock);
@@ -416,6 +415,7 @@ xprt_socket_autoclose(void *args)
{
struct rpc_xprt *xprt = (struct rpc_xprt *)args;
+ xprt_disconnect(xprt);
xprt_close(xprt);
xprt_release_write(xprt, NULL);
}
@@ -448,7 +448,10 @@ xprt_init_autodisconnect(unsigned long data)
goto out_abort;
spin_unlock(&xprt->sock_lock);
/* Let keventd close the socket */
- schedule_work(&xprt->task_cleanup);
+ if (test_bit(XPRT_CONNECTING, &xprt->sockstate) != 0)
+ xprt_release_write(xprt, NULL);
+ else
+ schedule_work(&xprt->task_cleanup);
return;
out_abort:
spin_unlock(&xprt->sock_lock);
@@ -460,12 +463,8 @@ static void xprt_socket_connect(void *args)
struct socket *sock = xprt->sock;
int status = -EIO;
- if (xprt->shutdown) {
- rpc_wake_up_status(&xprt->pending, -EIO);
- return;
- }
- if (!xprt->addr.sin_port)
- goto out_err;
+ if (xprt->shutdown || xprt->addr.sin_port == 0)
+ goto out;
/*
* Start by resetting any existing state
@@ -475,12 +474,12 @@ static void xprt_socket_connect(void *args)
if (sock == NULL) {
/* couldn't create socket or bind to reserved port;
* this is likely a permanent error, so cause an abort */
- goto out_err;
- return;
+ goto out;
}
xprt_bind_socket(xprt, sock);
xprt_sock_setbufsize(xprt);
+ status = 0;
if (!xprt->stream)
goto out;
@@ -491,28 +490,22 @@ static void xprt_socket_connect(void *args)
sizeof(xprt->addr), O_NONBLOCK);
dprintk("RPC: %p connect status %d connected %d sock state %d\n",
xprt, -status, xprt_connected(xprt), sock->sk->sk_state);
- if (status >= 0)
- goto out;
- switch (status) {
- case -EINPROGRESS:
- case -EALREADY:
- return;
- default:
- goto out_err;
+ if (status < 0) {
+ switch (status) {
+ case -EINPROGRESS:
+ case -EALREADY:
+ goto out_clear;
+ }
}
out:
- spin_lock_bh(&xprt->sock_lock);
- if (xprt->snd_task)
- rpc_wake_up_task(xprt->snd_task);
- spin_unlock_bh(&xprt->sock_lock);
- return;
-out_err:
- spin_lock_bh(&xprt->sock_lock);
- if (xprt->snd_task) {
- xprt->snd_task->tk_status = status;
- rpc_wake_up_task(xprt->snd_task);
- }
- spin_unlock_bh(&xprt->sock_lock);
+ if (status < 0)
+ rpc_wake_up_status(&xprt->pending, status);
+ else
+ rpc_wake_up(&xprt->pending);
+out_clear:
+ smp_mb__before_clear_bit();
+ clear_bit(XPRT_CONNECTING, &xprt->sockstate);
+ smp_mb__after_clear_bit();
}
/*
@@ -544,7 +537,8 @@ void xprt_connect(struct rpc_task *task)
task->tk_timeout = RPC_CONNECT_TIMEOUT;
rpc_sleep_on(&xprt->pending, task, xprt_connect_status, NULL);
- schedule_work(&xprt->sock_connect);
+ if (!test_and_set_bit(XPRT_CONNECTING, &xprt->sockstate))
+ schedule_work(&xprt->sock_connect);
return;
out_write:
xprt_release_write(xprt, task);
@@ -647,8 +641,8 @@ xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied)
#endif
dprintk("RPC: %4d has input (%d bytes)\n", task->tk_pid, copied);
- req->rq_received = copied;
list_del_init(&req->rq_list);
+ req->rq_received = req->rq_private_buf.len = copied;
/* ... and wake up the process. */
rpc_wake_up_task(task);
@@ -765,7 +759,7 @@ udp_data_ready(struct sock *sk, int len)
dprintk("RPC: %4d received reply\n", task->tk_pid);
- if ((copied = rovr->rq_private_buf.len) > repsize)
+ if ((copied = rovr->rq_private_buf.buflen) > repsize)
copied = repsize;
/* Suck it into the iovec, verify checksum if not done by hw. */
@@ -782,8 +776,6 @@ udp_data_ready(struct sock *sk, int len)
dropit:
skb_free_datagram(sk, skb);
out:
- if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
- wake_up_interruptible(sk->sk_sleep);
read_unlock(&sk->sk_callback_lock);
}
@@ -910,7 +902,7 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc)
xprt->tcp_copied += len;
xprt->tcp_offset += len;
- if (xprt->tcp_copied == req->rq_private_buf.len)
+ if (xprt->tcp_copied == req->rq_private_buf.buflen)
xprt->tcp_flags &= ~XPRT_COPY_DATA;
else if (xprt->tcp_offset == xprt->tcp_reclen) {
if (xprt->tcp_flags & XPRT_LAST_FRAG)
@@ -1028,9 +1020,6 @@ tcp_state_change(struct sock *sk)
xprt->tcp_reclen = 0;
xprt->tcp_copied = 0;
xprt->tcp_flags = XPRT_COPY_RECM | XPRT_COPY_XID;
-
- if (xprt->snd_task)
- rpc_wake_up_task(xprt->snd_task);
rpc_wake_up(&xprt->pending);
}
spin_unlock_bh(&xprt->sock_lock);
@@ -1039,12 +1028,11 @@ tcp_state_change(struct sock *sk)
case TCP_SYN_RECV:
break;
default:
- xprt_disconnect(xprt);
+ if (xprt_test_and_clear_connected(xprt))
+ rpc_wake_up_status(&xprt->pending, -ENOTCONN);
break;
}
out:
- if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
- wake_up_interruptible_all(sk->sk_sleep);
read_unlock(&sk->sk_callback_lock);
}
@@ -1084,8 +1072,6 @@ xprt_write_space(struct sock *sk)
if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->pending)
rpc_wake_up_task(xprt->snd_task);
spin_unlock_bh(&xprt->sock_lock);
- if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
- wake_up_interruptible(sk->sk_sleep);
out:
read_unlock(&sk->sk_callback_lock);
}
@@ -1464,10 +1450,10 @@ xprt_setup(int proto, struct sockaddr_in *ap, struct rpc_timeout *to)
} else
xprt_default_timeout(&xprt->timeout, xprt->prot);
- INIT_RPC_WAITQ(&xprt->pending, "xprt_pending");
- INIT_RPC_WAITQ(&xprt->sending, "xprt_sending");
- INIT_RPC_WAITQ(&xprt->resend, "xprt_resend");
- INIT_RPC_WAITQ(&xprt->backlog, "xprt_backlog");
+ rpc_init_wait_queue(&xprt->pending, "xprt_pending");
+ rpc_init_wait_queue(&xprt->sending, "xprt_sending");
+ rpc_init_wait_queue(&xprt->resend, "xprt_resend");
+ rpc_init_priority_wait_queue(&xprt->backlog, "xprt_backlog");
/* initialize free list */
for (req = &xprt->slot[entries-1]; req >= &xprt->slot[0]; req--)
@@ -1626,8 +1612,7 @@ xprt_shutdown(struct rpc_xprt *xprt)
rpc_wake_up(&xprt->resend);
rpc_wake_up(&xprt->pending);
rpc_wake_up(&xprt->backlog);
- if (waitqueue_active(&xprt->cong_wait))
- wake_up(&xprt->cong_wait);
+ wake_up(&xprt->cong_wait);
del_timer_sync(&xprt->timer);
}
@@ -1637,8 +1622,7 @@ xprt_shutdown(struct rpc_xprt *xprt)
int
xprt_clear_backlog(struct rpc_xprt *xprt) {
rpc_wake_up_next(&xprt->backlog);
- if (waitqueue_active(&xprt->cong_wait))
- wake_up(&xprt->cong_wait);
+ wake_up(&xprt->cong_wait);
return 1;
}
@@ -1650,6 +1634,7 @@ xprt_destroy(struct rpc_xprt *xprt)
{
dprintk("RPC: destroying transport %p\n", xprt);
xprt_shutdown(xprt);
+ xprt_disconnect(xprt);
xprt_close(xprt);
kfree(xprt->slot);
kfree(xprt);