patch-2.2.18 linux/fs/nfsd/nfs3xdr.c
Next file: linux/fs/nfsd/nfscache.c
Previous file: linux/fs/nfsd/nfs3proc.c
Back to the patch index
Back to the overall index
- Lines: 626
- Date:
Sun Oct 15 21:15:17 2000
- Orig file:
v2.2.17/fs/nfsd/nfs3xdr.c
- Orig date:
Fri Apr 21 12:46:44 2000
diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/fs/nfsd/nfs3xdr.c linux/fs/nfsd/nfs3xdr.c
@@ -3,7 +3,7 @@
*
* XDR support for nfsd/protocol version 3.
*
- * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
*/
#include <linux/types.h>
@@ -17,16 +17,16 @@
#define NFSDDBG_FACILITY NFSDDBG_XDR
-u32 nfs_ok, nfserr_perm, nfserr_noent, nfserr_io, nfserr_nxio,
- nfserr_acces, nfserr_exist, nfserr_nodev, nfserr_notdir,
- nfserr_isdir, nfserr_fbig, nfserr_nospc, nfserr_rofs,
- nfserr_nametoolong, nfserr_dquot, nfserr_stale;
-
#ifdef NFSD_OPTIMIZE_SPACE
# define inline
#endif
/*
+ * Size of encoded NFS3 file handle, in words
+ */
+#define NFS3_FHANDLE_WORDS (1 + XDR_QUADLEN(sizeof(struct knfs_fh)))
+
+/*
* Mapping of S_IF* types to NFS file types
*/
static u32 nfs3_ftypes[] = {
@@ -37,48 +37,9 @@
};
/*
- * Initialization of NFS status variables
- */
-void
-nfs3xdr_init(void)
-{
- static int inited = 0;
-
- if (inited)
- return;
-
- nfs_ok = htonl(NFS_OK);
- nfserr_perm = htonl(NFSERR_PERM);
- nfserr_noent = htonl(NFSERR_NOENT);
- nfserr_io = htonl(NFSERR_IO);
- nfserr_nxio = htonl(NFSERR_NXIO);
- nfserr_acces = htonl(NFSERR_ACCES);
- nfserr_exist = htonl(NFSERR_EXIST);
- nfserr_nodev = htonl(NFSERR_NODEV);
- nfserr_notdir = htonl(NFSERR_NOTDIR);
- nfserr_isdir = htonl(NFSERR_ISDIR);
- nfserr_fbig = htonl(NFSERR_FBIG);
- nfserr_nospc = htonl(NFSERR_NOSPC);
- nfserr_rofs = htonl(NFSERR_ROFS);
- nfserr_nametoolong = htonl(NFSERR_NAMETOOLONG);
- nfserr_dquot = htonl(NFSERR_DQUOT);
- nfserr_stale = htonl(NFSERR_STALE);
-
- inited = 1;
-}
-
-/*
* XDR functions for basic NFS types
*/
static inline u32 *
-enc64(u32 *p, u64 val)
-{
- *p++ = (val >> 32);
- *p++ = (val & 0xffffffff);
- return p;
-}
-
-static inline u32 *
dec64(u32 *p, u64 *valp)
{
*valp = ((u64) ntohl(*p++)) << 32;
@@ -103,13 +64,10 @@
static inline u32 *
decode_fh(u32 *p, struct svc_fh *fhp)
{
- if (*p++ != sizeof(struct knfs_fh))
+ if (ntohl(*p++) != sizeof(struct knfs_fh))
return NULL;
memcpy(&fhp->fh_handle, p, sizeof(struct knfs_fh));
- fhp->fh_inode = NULL;
- fhp->fh_export = NULL;
-
return p + (sizeof(struct knfs_fh) >> 2);
}
@@ -179,27 +137,35 @@
iap->ia_gid = ntohl(*p++);
}
if (*p++) {
+ u64 newsize;
+
iap->ia_valid |= ATTR_SIZE;
- iap->ia_size = ntohl(*p++);
+ p = dec64(p, &newsize);
+ if (newsize <= NFS_OFFSET_MAX)
+ iap->ia_size = (u32) newsize;
+ else
+ iap->ia_size = ~(size_t) 0;
}
- if ((tmp = *p++) == 1) {
+ if ((tmp = ntohl(*p++)) == 1) { /* set to server time */
iap->ia_valid |= ATTR_ATIME;
- } else if (tmp == 2) {
+ } else if (tmp == 2) { /* set to client time */
iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
iap->ia_atime = ntohl(*p++), p++;
}
- if ((tmp = *p++) != 0) {
- iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
- } else if (tmp == 2) {
+ if ((tmp = ntohl(*p++)) == 1) { /* set to server time */
iap->ia_valid |= ATTR_MTIME;
+ } else if (tmp == 2) { /* set to client time */
+ iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
iap->ia_mtime = ntohl(*p++), p++;
}
return p;
}
static inline u32 *
-encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct inode *inode)
+encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry)
{
+ struct inode *inode = dentry->d_inode;
+
if (!inode) {
printk("nfsd: NULL inode in %s:%d", __FILE__, __LINE__);
return NULL;
@@ -215,7 +181,16 @@
} else {
p = enc64(p, (u64) inode->i_size);
}
- p = enc64(p, inode->i_blksize * inode->i_blocks);
+ /*
+ * For the 'used' member, we take i_blocks if set; assuming 512-byte
+ * units. Some FSs don't set this, so all we can do then is
+ * use the size.
+ */
+ if (inode->i_blocks) {
+ p = enc64(p, ((u64)inode->i_blocks)<<9 );
+ } else {
+ p = enc64(p, (u64) inode->i_size);
+ }
*p++ = htonl((u32) MAJOR(inode->i_rdev));
*p++ = htonl((u32) MINOR(inode->i_rdev));
p = enc64(p, (u64) inode->i_dev);
@@ -227,19 +202,54 @@
return p;
}
+static inline u32 *
+encode_saved_post_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
+{
+ struct inode *inode = fhp->fh_dentry->d_inode;
+
+ /* Attributes to follow */
+ *p++ = xdr_one;
+
+ *p++ = htonl(nfs3_ftypes[(fhp->fh_post_mode & S_IFMT) >> 12]);
+ *p++ = htonl((u32) fhp->fh_post_mode);
+ *p++ = htonl((u32) fhp->fh_post_nlink);
+ *p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid));
+ *p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid));
+ if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) {
+ p = enc64(p, (u64) NFS3_MAXPATHLEN);
+ } else {
+ p = enc64(p, (u64) fhp->fh_post_size);
+ }
+ if (fhp->fh_post_blocks) {
+ p = enc64(p, ((u64)fhp->fh_post_blocks)<<9);
+ } else {
+ p = enc64(p, (u64) fhp->fh_post_size);
+ }
+ *p++ = htonl((u32) MAJOR(fhp->fh_post_rdev));
+ *p++ = htonl((u32) MINOR(fhp->fh_post_rdev));
+ p = enc64(p, (u64) inode->i_dev);
+ p = enc64(p, (u64) inode->i_ino);
+ p = encode_time3(p, fhp->fh_post_atime);
+ p = encode_time3(p, fhp->fh_post_mtime);
+ p = encode_time3(p, fhp->fh_post_ctime);
+
+ return p;
+}
+
/*
* Encode post-operation attributes.
* The inode may be NULL if the call failed because of a stale file
* handle. In this case, no attributes are returned.
*/
static u32 *
-encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct inode *inode)
+encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry)
{
- if (inode == NULL) {
- *p++ = xdr_zero;
- return p;
+ if (dentry && dentry->d_inode != NULL) {
+ *p++ = xdr_one; /* attributes follow */
+ return encode_fattr3(rqstp, p, dentry);
}
- return encode_fattr3(rqstp, p, inode);
+ *p++ = xdr_zero;
+ return p;
}
/*
@@ -248,17 +258,22 @@
static u32 *
encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
{
- struct inode *inode = fhp->fh_inode;
+ struct dentry *dentry = fhp->fh_dentry;
- if (fhp->fh_post_version == inode->i_version) {
- *p++ = xdr_one;
- p = enc64(p, (u64) fhp->fh_pre_size);
- p = encode_time3(p, fhp->fh_pre_mtime);
- p = encode_time3(p, fhp->fh_pre_ctime);
- } else {
- *p++ = xdr_zero;
+ if (dentry && dentry->d_inode && fhp->fh_post_saved) {
+ if (fhp->fh_pre_saved) {
+ *p++ = xdr_one;
+ p = enc64(p, (u64) fhp->fh_pre_size);
+ p = encode_time3(p, fhp->fh_pre_mtime);
+ p = encode_time3(p, fhp->fh_pre_ctime);
+ } else {
+ *p++ = xdr_zero;
+ }
+ return encode_saved_post_attr(rqstp, p, fhp);
}
- return encode_post_op_attr(rqstp, p, inode);
+ /* no pre- or post-attrs */
+ *p++ = xdr_zero;
+ return encode_post_op_attr(rqstp, p, dentry);
}
/*
@@ -299,10 +314,12 @@
struct nfsd3_sattrargs *args)
{
if (!(p = decode_fh(p, &args->fh))
- || !(p = decode_sattr3(p, &args->attrs))
- || (*p++ && !(p = decode_time3(p, &args->guardtime))))
+ || !(p = decode_sattr3(p, &args->attrs)))
return 0;
+ if ((args->check_guard = ntohl(*p++)) != 0)
+ p = decode_time3(p, &args->guardtime);
+
return xdr_argsize_check(rqstp, p);
}
@@ -333,10 +350,10 @@
struct nfsd3_readargs *args)
{
if (!(p = decode_fh(p, &args->fh))
- || !(p = dec64(p, &args->offset))
- || !(p = dec64(p, &args->count)))
+ || !(p = dec64(p, &args->offset)))
return 0;
+ args->count = ntohl(*p++);
return xdr_argsize_check(rqstp, p);
}
@@ -345,14 +362,14 @@
struct nfsd3_writeargs *args)
{
if (!(p = decode_fh(p, &args->fh))
- || !(p = dec64(p, &args->offset))
- || !(p = dec64(p, &args->count)))
+ || !(p = dec64(p, &args->offset)))
return 0;
+ args->count = ntohl(*p++);
args->stable = ntohl(*p++);
args->len = ntohl(*p++);
args->data = (char *) p;
- p += (args->len + 3) >> 2;
+ p += XDR_QUADLEN(args->len);
return xdr_argsize_check(rqstp, p);
}
@@ -366,11 +383,12 @@
return 0;
switch (args->createmode = ntohl(*p++)) {
- case 0: case 1:
+ case NFS3_CREATE_UNCHECKED:
+ case NFS3_CREATE_GUARDED:
if (!(p = decode_sattr3(p, &args->attrs)))
return 0;
break;
- case 2:
+ case NFS3_CREATE_EXCLUSIVE:
args->verf = p;
p += 2;
break;
@@ -460,8 +478,9 @@
{
if (!(p = decode_fh(p, &args->fh)))
return 0;
- args->cookie = ntohl(*p++);
+ p = dec64(p, &args->cookie);
args->verf = p; p += 2;
+ args->dircount = ~0;
args->count = ntohl(*p++);
return xdr_argsize_check(rqstp, p);
@@ -473,7 +492,7 @@
{
if (!(p = decode_fh(p, &args->fh)))
return 0;
- args->cookie = ntohl(*p++);
+ p = dec64(p, &args->cookie);
args->verf = p; p += 2;
args->dircount = ntohl(*p++);
args->count = ntohl(*p++);
@@ -485,9 +504,9 @@
nfs3svc_decode_commitargs(struct svc_rqst *rqstp, u32 *p,
struct nfsd3_commitargs *args)
{
- if (!(p = decode_fh(p, &args->fh))
- || !(p = dec64(p, &args->offset)))
+ if (!(p = decode_fh(p, &args->fh)))
return 0;
+ p = dec64(p, &args->offset);
args->count = ntohl(*p++);
return xdr_argsize_check(rqstp, p);
@@ -496,12 +515,23 @@
/*
* XDR encode functions
*/
+/*
+ * There must be an encoding function for void results so svc_process
+ * will work properly.
+ */
+int
+nfs3svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy)
+{
+ return xdr_ressize_check(rqstp, p);
+}
+
/* GETATTR */
int
nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
struct nfsd3_attrstat *resp)
{
- if (!(p = encode_fattr3(rqstp, p, resp->fh.fh_inode)))
+ if (resp->status == 0
+ && !(p = encode_fattr3(rqstp, p, resp->fh.fh_dentry)))
return 0;
return xdr_ressize_check(rqstp, p);
}
@@ -518,15 +548,14 @@
/* LOOKUP */
int
-nfs3svc_encode_lookupres(struct svc_rqst *rqstp, u32 *p,
- struct nfsd3_lookupres *resp)
+nfs3svc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
+ struct nfsd3_diropres *resp)
{
if (resp->status == 0) {
p = encode_fh(p, &resp->fh);
- if (!(p = encode_fattr3(rqstp, p, resp->fh.fh_inode)))
- return 0;
+ p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
}
- p = encode_post_op_attr(rqstp, p, resp->dirfh.fh_inode);
+ p = encode_post_op_attr(rqstp, p, resp->dirfh.fh_dentry);
return xdr_ressize_check(rqstp, p);
}
@@ -535,7 +564,7 @@
nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
struct nfsd3_accessres *resp)
{
- p = encode_post_op_attr(rqstp, p, resp->fh.fh_inode);
+ p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
if (resp->status == 0)
*p++ = htonl(resp->access);
return xdr_ressize_check(rqstp, p);
@@ -546,7 +575,7 @@
nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
struct nfsd3_readlinkres *resp)
{
- p = encode_post_op_attr(rqstp, p, resp->fh.fh_inode);
+ p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
if (resp->status == 0) {
*p++ = htonl(resp->len);
p += XDR_QUADLEN(resp->len);
@@ -559,7 +588,7 @@
nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p,
struct nfsd3_readres *resp)
{
- p = encode_post_op_attr(rqstp, p, resp->fh.fh_inode);
+ p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
if (resp->status == 0) {
*p++ = htonl(resp->count);
*p++ = htonl(resp->eof);
@@ -587,11 +616,12 @@
/* CREATE, MKDIR, SYMLINK, MKNOD */
int
nfs3svc_encode_createres(struct svc_rqst *rqstp, u32 *p,
- struct nfsd3_createres *resp)
+ struct nfsd3_diropres *resp)
{
if (resp->status == 0) {
+ *p++ = xdr_one;
p = encode_fh(p, &resp->fh);
- p = encode_post_op_attr(rqstp, p, resp->fh.fh_inode);
+ p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
}
p = encode_wcc_data(rqstp, p, &resp->dirfh);
return xdr_ressize_check(rqstp, p);
@@ -612,7 +642,7 @@
nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p,
struct nfsd3_linkres *resp)
{
- p = encode_post_op_attr(rqstp, p, resp->fh.fh_inode);
+ p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
p = encode_wcc_data(rqstp, p, &resp->tfh);
return xdr_ressize_check(rqstp, p);
}
@@ -622,73 +652,116 @@
nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
struct nfsd3_readdirres *resp)
{
- p = encode_post_op_attr(rqstp, p, resp->fh.fh_inode);
+ p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
if (resp->status == 0) {
/* stupid readdir cookie */
- *p++ = ntohl(resp->fh.fh_inode->i_mtime);
- *p++ = xdr_zero;
- p = resp->list_end;
+ memcpy(p, resp->verf, 8); p += 2;
+ p += XDR_QUADLEN(resp->count);
}
return xdr_ressize_check(rqstp, p);
}
-#define NFS3_ENTRYPLUS_BAGGAGE ((1 + 20 + 1 + NFS3_FHSIZE) << 2)
-int
-nfs3svc_encode_entry(struct readdir_cd *cd, const char *name,
- int namlen, unsigned long offset, ino_t ino)
+/*
+ * Encode a directory entry. This one works for both normal readdir
+ * and readdirplus.
+ * The normal readdir reply requires 2 (fileid) + 1 (stringlen)
+ * + string + 2 (cookie) + 1 (next) words, i.e. 6 + strlen.
+ *
+ * The readdirplus baggage is 1+21 words for post_op_attr, plus the
+ * file handle.
+ */
+
+#define NFS3_ENTRY_BAGGAGE (2 + 1 + 2 + 1)
+#define NFS3_ENTRYPLUS_BAGGAGE (1 + 21 + 1 + (NFS3_FHSIZE >> 2))
+static int
+encode_entry(struct readdir_cd *cd, const char *name,
+ int namlen, off_t offset, ino_t ino, int plus)
{
u32 *p = cd->buffer;
int buflen, slen, elen;
- struct svc_fh fh;
- if (offset > ~((u64) 0))
- return -EINVAL;
if (cd->offset)
- *cd->offset = htonl(offset);
+ enc64(cd->offset, (u64) offset);
- /* For readdirplus, look up the inode */
- if (cd->plus && nfsd_lookup(cd->rqstp, cd->dirfh, name, namlen, &fh))
+ /* nfsd_readdir calls us with name == 0 when it wants us to
+ * set the last offset entry. */
+ if (name == 0)
return 0;
+ /*
+ dprintk("encode_entry(%.*s @%ld%s)\n",
+ namlen, name, (long) offset, plus? " plus" : "");
+ */
+
/* truncate filename if too long */
if (namlen > NFS3_MAXNAMLEN)
namlen = NFS3_MAXNAMLEN;
slen = XDR_QUADLEN(namlen);
- elen = slen + (cd->plus? NFS3_ENTRYPLUS_BAGGAGE : 0);
- if ((buflen = cd->buflen - elen - 4) < 0) {
+ elen = slen + NFS3_ENTRY_BAGGAGE
+ + (plus? NFS3_ENTRYPLUS_BAGGAGE : 0);
+ if ((buflen = cd->buflen - elen) < 0) {
cd->eob = 1;
- if (cd->plus)
- fh_put(&fh);
return -EINVAL;
}
- *p++ = xdr_one; /* mark entry present */
- *p++ = xdr_zero; /* file id (64 bit) */
- *p++ = htonl((u32) ino);
- *p++ = htonl((u32) namlen); /* name length & name */
+ *p++ = xdr_one; /* mark entry present */
+ p = enc64(p, ino); /* file id */
+#ifdef XDR_ENCODE_STRING_TAKES_LENGTH
+ p = xdr_encode_string(p, name, namlen); /* name length & name */
+#else
+ /* just like nfsproc.c */
+ *p++ = htonl((u32) namlen);
+ p[slen - 1] = 0; /* don't leak kernel data */
memcpy(p, name, namlen);
p += slen;
+#endif
+
+ cd->offset = p; /* remember pointer */
+ p = enc64(p, NFS_OFFSET_MAX); /* offset of next entry */
/* throw in readdirplus baggage */
- if (cd->plus) {
- p = encode_post_op_attr(cd->rqstp, p, fh.fh_inode);
- p = encode_fh(p, &fh);
- fh_put(&fh);
- }
+ if (plus) {
+ struct svc_fh fh;
- cd->offset = p; /* remember pointer */
- p = enc64(p, ~(u64) 0); /* offset of next entry */
+ fh_init(&fh);
+ /* Disabled for now because of lock-up */
+ if (0 && nfsd_lookup(cd->rqstp, cd->dirfh, name, namlen, &fh) == 0) {
+ p = encode_post_op_attr(cd->rqstp, p, fh.fh_dentry);
+ p = encode_fh(p, &fh);
+ fh_put(&fh);
+ } else {
+ /* Didn't find this entry... weird.
+ * Proceed without the attrs anf fh anyway.
+ */
+ *p++ = 0;
+ *p++ = 0;
+ }
+ }
cd->buflen = buflen;
cd->buffer = p;
return 0;
}
+int
+nfs3svc_encode_entry(struct readdir_cd *cd, const char *name,
+ int namlen, off_t offset, ino_t ino)
+{
+ return encode_entry(cd, name, namlen, offset, ino, 0);
+}
+
+int
+nfs3svc_encode_entry_plus(struct readdir_cd *cd, const char *name,
+ int namlen, off_t offset, ino_t ino)
+{
+ return encode_entry(cd, name, namlen, offset, ino, 1);
+}
+
/* FSSTAT */
int
-nfs3svc_encode_statfsres(struct svc_rqst *rqstp, u32 *p,
- struct nfsd3_statfsres *resp)
+nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, u32 *p,
+ struct nfsd3_fsstatres *resp)
{
struct statfs *s = &resp->stats;
u64 bs = s->f_bsize;
@@ -722,9 +795,9 @@
*p++ = htonl(resp->f_wtpref);
*p++ = htonl(resp->f_wtmult);
*p++ = htonl(resp->f_dtpref);
- *p++ = htonl(resp->f_maxfilesize);
+ p = enc64(p, resp->f_maxfilesize);
+ *p++ = xdr_one;
*p++ = xdr_zero;
- *p++ = htonl(1000000000 / HZ);
*p++ = htonl(resp->f_properties);
}
@@ -741,8 +814,8 @@
if (resp->status == 0) {
*p++ = htonl(resp->p_link_max);
*p++ = htonl(resp->p_name_max);
- *p++ = xdr_one; /* always reject long file names */
- *p++ = xdr_one; /* chown restricted */
+ *p++ = htonl(resp->p_no_trunc);
+ *p++ = htonl(resp->p_chown_restricted);
*p++ = htonl(resp->p_case_insensitive);
*p++ = htonl(resp->p_case_preserving);
}
@@ -769,7 +842,7 @@
*/
int
nfs3svc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
- struct nfsd_fhandle *resp)
+ struct nfsd3_attrstat *resp)
{
fh_put(&resp->fh);
return 1;
@@ -777,7 +850,7 @@
int
nfs3svc_release_fhandle2(struct svc_rqst *rqstp, u32 *p,
- struct nfsd3_fhandle2 *resp)
+ struct nfsd3_fhandle_pair *resp)
{
fh_put(&resp->fh1);
fh_put(&resp->fh2);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)