Messages in this thread Patch in this message | | | Subject | [alpha patch] knfsd version 3 | Date | Sun, 02 May 1999 14:47:28 -0700 | From | "G. Allen Morris III" <> |
| |
linux-2.2.7-knfsdv3-1.diff
This patch add nfs version 3 to the linux kernel nfs server.
It must be applied after Trond's nfs version 3 patch.
http://www.fys.uio.no/~trondmy/src/linux-2.2.7-nfsv3-0.8.1.dif.bz2
You may also need to update mount to the one found at:
http://www.fys.uio.no/~trondmy/src/nfsv3-mount/
Allen ------------------------------------------------------------------ diff -u --new-file -X exclude linux-2.2.7-nfsv3/fs/nfsd/Makefile linux/fs/nfsd/Makefile --- linux-2.2.7-nfsv3/fs/nfsd/Makefile Tue Dec 29 11:42:25 1998 +++ linux/fs/nfsd/Makefile Fri Apr 30 23:44:22 1999 @@ -11,6 +11,9 @@ O_OBJS := nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \ export.o auth.o lockd.o nfscache.o nfsxdr.o \ stats.o +ifdef CONFIG_NFS_V3 + O_OBJS += nfs3proc.o nfs3xdr.o +endif M_OBJS := $(O_TARGET) diff -u --new-file -X exclude linux-2.2.7-nfsv3/fs/nfsd/nfs3proc.c linux/fs/nfsd/nfs3proc.c --- linux-2.2.7-nfsv3/fs/nfsd/nfs3proc.c Mon Apr 19 22:22:02 1999 +++ linux/fs/nfsd/nfs3proc.c Fri Apr 30 23:44:22 1999 @@ -3,7 +3,7 @@ * * Process version 3 NFS requests. * - * Copyright (C) 1996 Olaf Kirch <okir@monad.swb.de> + * Copyright (C) 1996, 1997, 1998 Olaf Kirch <okir@monad.swb.de> */ #include <linux/linkage.h> @@ -18,19 +18,32 @@ #include <linux/version.h> #include <linux/unistd.h> #include <linux/malloc.h> +#include <linux/major.h> #include <linux/sunrpc/svc.h> #include <linux/nfsd/nfsd.h> #include <linux/nfsd/cache.h> #include <linux/nfsd/xdr3.h> - -typedef struct svc_rqst svc_rqst; -typedef struct svc_buf svc_buf; +#include <linux/nfs3.h> #define NFSDDBG_FACILITY NFSDDBG_PROC #define RETURN(st) { resp->status = (st); return (st); } +static int nfs3_ftypes[] = { + 0, /* NF3NON */ + S_IFREG, /* NF3REG */ + S_IFDIR, /* NF3DIR */ + S_IFBLK, /* NF3BLK */ + S_IFCHR, /* NF3CHR */ + S_IFLNK, /* NF3LNK */ + S_IFIFO, /* NF3FIFO */ + S_IFSOCK, /* NF3SOCK */ +}; + +/* + * Reserve room in the send buffer + */ static void svcbuf_reserve(struct svc_buf *buf, u32 **ptr, int *len, int nr) { @@ -38,6 +51,9 @@ *len = buf->buflen - buf->len - nr; } +/* + * NULL call. + */ static int nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) { @@ -46,7 +62,6 @@ /* * Get a file's attributes - * N.B. After this call resp->fh needs an fh_put */ static int nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, @@ -54,18 +69,17 @@ { int nfserr; - dprintk("nfsd: GETATTR %x/%ld\n", + dprintk("nfsd: GETATTR(3) %x/%ld\n", SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh)); - resp->fh = argp->fh; + fh_copy(&resp->fh, &argp->fh); nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP); RETURN(nfserr); } /* * Set a file's attributes - * N.B. After this call resp->fh needs an fh_put */ static int nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp, @@ -73,31 +87,30 @@ { int nfserr; - dprintk("nfsd: SETATTR %x/%ld\n", + dprintk("nfsd: SETATTR(3) %x/%ld\n", SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh)); - resp->fh = argp->fh; + fh_copy(&resp->fh, &argp->fh); nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs); RETURN(nfserr); } /* * Look up a path name component - * N.B. After this call _both_ resp->dirfh and resp->fh need an fh_put */ static int nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, - struct nfsd3_lookupres *resp) + struct nfsd3_diropres *resp) { int nfserr; - dprintk("nfsd: LOOKUP %x/%ld %s\n", + dprintk("nfsd: LOOKUP(3) %x/%ld %s\n", SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh), argp->name); - resp->dirfh = argp->fh; + fh_copy(&resp->dirfh, &argp->fh); nfserr = nfsd_lookup(rqstp, &resp->dirfh, argp->name, argp->len, @@ -109,12 +122,20 @@ * Check file access */ static int -nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, +nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp, struct nfsd3_accessres *resp) { - /* to be done */ - resp->fh = argp->fh; - return nfserr_notsupp; + int nfserr; + + dprintk("nfsd: ACCESS(3) %x/%ld 0x%x\n", + SVCFH_DEV(&argp->fh), + SVCFH_INO(&argp->fh), + argp->access); + + fh_copy(&resp->fh, &argp->fh); + resp->access = argp->access; + nfserr = nfsd_access(rqstp, &resp->fh, &resp->access); + RETURN(nfserr); } /* @@ -127,23 +148,23 @@ u32 *path; int dummy, nfserr; - dprintk("nfsd: READLINK %x/%ld\n", + dprintk("nfsd: READLINK(3) %x/%ld\n", SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh)); /* Reserve room for status, post_op_attr, and path length */ - svcbuf_reserve(&rqstp->rq_resbuf, &path, &dummy, 1 + 22 + 1); + svcbuf_reserve(&rqstp->rq_resbuf, &path, &dummy, + 1 + NFS3_POST_OP_ATTR_WORDS + 1); /* Read the symlink. */ + fh_copy(&resp->fh, &argp->fh); resp->len = NFS3_MAXPATHLEN; - nfserr = nfsd_readlink(rqstp, &argp->fh, (char *) path, &resp->len); - fh_put(&argp->fh); + nfserr = nfsd_readlink(rqstp, &resp->fh, (char *) path, &resp->len); RETURN(nfserr); } /* * Read a portion of a file. - * N.B. After this call resp->fh needs an fh_put */ static int nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp, @@ -152,7 +173,7 @@ u32 * buffer; int nfserr, avail; - dprintk("nfsd: READ %x/%ld %lu bytes at %lu\n", + dprintk("nfsd: READ(3) %x/%ld %lu bytes at %lu\n", SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh), (unsigned long) argp->count, @@ -162,30 +183,29 @@ * 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof) * + 1 (xdr opaque byte count) = 26 */ - svcbuf_reserve(&rqstp->rq_resbuf, &buffer, &avail, 26); - - if ((avail << 2) < argp->count) { - printk(KERN_NOTICE - "oversized read request from %08lx:%d (%d bytes)\n", - ntohl(rqstp->rq_addr.sin_addr.s_addr), - ntohs(rqstp->rq_addr.sin_port), - argp->count); - argp->count = avail; - } + svcbuf_reserve(&rqstp->rq_resbuf, &buffer, &avail, + 1 + NFS3_POST_OP_ATTR_WORDS + 3); resp->count = argp->count; - resp->fh = argp->fh; + if ((avail << 2) < resp->count) + resp->count = avail << 2; + + fh_copy(&resp->fh, &argp->fh); nfserr = nfsd_read(rqstp, &resp->fh, argp->offset, (char *) buffer, &resp->count); + if (nfserr == 0) { + struct inode *inode = resp->fh.fh_dentry->d_inode; + + resp->eof = (argp->offset + resp->count) >= inode->i_size; + } RETURN(nfserr); } /* * Write data to a file - * N.B. After this call resp->fh needs an fh_put */ static int nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp, @@ -193,19 +213,21 @@ { int nfserr; - dprintk("nfsd: WRITE %x/%ld %d bytes at %ld\n", + dprintk("nfsd: WRITE(3) %x/%ld %d bytes at %ld%s\n", SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh), argp->len, - (unsigned long) argp->offset); + (unsigned long) argp->offset, + argp->stable? " stable" : ""); - resp->fh = argp->fh; + fh_copy(&resp->fh, &argp->fh); nfserr = nfsd_write(rqstp, &resp->fh, argp->offset, argp->data, argp->len, argp->stable); resp->committed = argp->stable; + resp->count = argp->count; RETURN(nfserr); } @@ -213,18 +235,16 @@ * With NFSv3, CREATE processing is a lot easier than with NFSv2. * At least in theory; we'll see how it fares in practice when the * first reports about SunOS compatibility problems start to pour in... - * N.B. After this call _both_ resp->dirfh and resp->fh need an fh_put */ static int nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, - struct nfsd3_createres *resp) + struct nfsd3_diropres *resp) { svc_fh *dirfhp, *newfhp = NULL; struct iattr *attr; - int mode; u32 nfserr; - dprintk("nfsd: CREATE %x/%ld %s\n", + dprintk("nfsd: CREATE(3) %x/%ld %s\n", SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh), argp->name); @@ -243,131 +263,114 @@ if (!(attr->ia_valid & ATTR_MODE)) { attr->ia_valid |= ATTR_MODE; attr->ia_mode = S_IFREG; + } else { + attr->ia_mode = (attr->ia_mode & ~S_IFMT) | S_IFREG; } - mode = attr->ia_mode & ~S_IFMT; /* Now create the file and set attributes */ - nfserr = nfsd_create(rqstp, dirfhp, argp->name, argp->len, - attr, S_IFREG, 0, newfhp); + nfserr = nfsd_create_v3(rqstp, dirfhp, argp->name, argp->len, + attr, newfhp, + argp->createmode, argp->verf); RETURN(nfserr); } -/* N.B. Is nfsd3_attrstat * correct for resp?? table says "void" */ +/* + * Make directory. This operation is not idempotent. + */ static int -nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, - struct nfsd3_attrstat *resp) +nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, + struct nfsd3_diropres *resp) { int nfserr; - dprintk("nfsd: REMOVE %x/%ld %s\n", + dprintk("nfsd: MKDIR(3) %x/%ld %s\n", SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh), argp->name); - /* Is this correct?? */ - fh_copy(&resp->fh, &argp->fh); + argp->attrs.ia_valid &= ~ATTR_SIZE; + fh_copy(&resp->dirfh, &argp->fh); + fh_init(&resp->fh); + nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len, + &argp->attrs, S_IFDIR, 0, &resp->fh); - /* Unlink. -S_IFDIR means file must not be a directory */ - nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len); - /* - * N.B. Should be an fh_put here ... nfsd3_proc_rmdir has one, - * or else as an xdr release function - */ - fh_put(&resp->fh); RETURN(nfserr); } static int -nfsd3_proc_rename(struct svc_rqst *rqstp, struct nfsd3_renameargs *argp, - void *resp) +nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp, + struct nfsd3_diropres *resp) { int nfserr; - dprintk("nfsd: RENAME %x/%ld %s -> %x/%ld %s\n", + dprintk("nfsd: SYMLINK(3) %x/%ld %s -> %s\n", SVCFH_DEV(&argp->ffh), SVCFH_INO(&argp->ffh), - argp->fname, - SVCFH_DEV(&argp->tfh), - SVCFH_INO(&argp->tfh), - argp->tname); + argp->fname, argp->tname); - nfserr = nfsd_rename(rqstp, &argp->ffh, argp->fname, argp->flen, - &argp->tfh, argp->tname, argp->tlen); - fh_put(&argp->ffh); - fh_put(&argp->tfh); + fh_copy(&resp->dirfh, &argp->ffh); + fh_init(&resp->fh); + nfserr = nfsd_symlink(rqstp, &resp->dirfh, argp->fname, argp->flen, + argp->tname, argp->tlen, + &resp->fh, &argp->attrs); RETURN(nfserr); } +/* + * Make socket/fifo/device. + */ static int -nfsd3_proc_link(struct svc_rqst *rqstp, struct nfsd3_linkargs *argp, - void *resp) +nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp, + struct nfsd3_diropres *resp) { - int nfserr; - - dprintk("nfsd: LINK %x/%ld -> %x/%ld %s\n", - SVCFH_DEV(&argp->ffh), - SVCFH_INO(&argp->ffh), - SVCFH_DEV(&argp->tfh), - SVCFH_INO(&argp->tfh), - argp->tname); + int nfserr, type; + dev_t rdev = 0; - nfserr = nfsd_link(rqstp, &argp->tfh, argp->tname, argp->tlen, - &argp->ffh); - fh_put(&argp->ffh); - fh_put(&argp->tfh); - RETURN(nfserr); -} - -static int -nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp, - void *resp) -{ - struct svc_fh newfh; - int nfserr; + dprintk("nfsd: MKNOD(3) %x/%ld %s\n", + SVCFH_DEV(&argp->fh), + SVCFH_INO(&argp->fh), + argp->name); - dprintk("nfsd: SYMLINK %x/%ld %s -> %s\n", - SVCFH_DEV(&argp->ffh), - SVCFH_INO(&argp->ffh), - argp->fname, argp->tname); + fh_copy(&resp->dirfh, &argp->fh); + fh_init(&resp->fh); - memset(&newfh, 0, sizeof(newfh)); + if (argp->ftype == 0 || argp->ftype >= NF3BAD) + return nfserr_inval; + if (argp->ftype == NF3CHR || argp->ftype == NF3BLK) { + if ((argp->ftype == NF3CHR && argp->major >= MAX_CHRDEV) + || (argp->ftype == NF3BLK && argp->major >= MAX_BLKDEV) + || argp->minor > 0xFF) + return nfserr_inval; + rdev = ((argp->major) << 8) | (argp->minor); + } else + if (argp->ftype != NF3SOCK || argp->ftype != NF3FIFO) + return nfserr_inval; - /* - * Create the link, look up new file and set attrs. - */ - nfserr = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen, - argp->tname, argp->tlen, - &newfh); - if (!nfserr) { - argp->attrs.ia_valid &= ~ATTR_SIZE; - nfserr = nfsd_setattr(rqstp, &newfh, &argp->attrs); - } + type = nfs3_ftypes[argp->ftype]; + nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len, + &argp->attrs, type, rdev, &resp->fh); - fh_put(&argp->ffh); - fh_put(&newfh); RETURN(nfserr); } /* - * Make directory. This operation is not idempotent. - * N.B. After this call resp->fh needs an fh_put + * Remove file/fifo/socket etc. */ static int -nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, - struct nfsd3_diropres *resp) +nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, + struct nfsd3_attrstat *resp) { int nfserr; - dprintk("nfsd: MKDIR %x/%ld %s\n", + dprintk("nfsd: REMOVE(3) %x/%ld %s\n", SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh), argp->name); - argp->attrs.ia_valid &= ~ATTR_SIZE; - nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len, - &argp->attrs, S_IFDIR, 0, &resp->fh); - fh_put(&argp->fh); + /* Unlink. -S_IFDIR means file must not be a directory */ + fh_copy(&resp->fh, &argp->fh); + nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len); RETURN(nfserr); } @@ -376,17 +379,58 @@ */ static int nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, - void *resp) + struct nfsd3_attrstat *resp) { int nfserr; - dprintk("nfsd: RMDIR %x/%ld %s\n", + dprintk("nfsd: RMDIR(3) %x/%ld %s\n", SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh), argp->name); - nfserr = nfsd_unlink(rqstp, &argp->fh, S_IFDIR, argp->name, argp->len); - fh_put(&argp->fh); + fh_copy(&resp->fh, &argp->fh); + nfserr = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, argp->name, argp->len); + RETURN(nfserr); +} + +static int +nfsd3_proc_rename(struct svc_rqst *rqstp, struct nfsd3_renameargs *argp, + struct nfsd3_renameres *resp) +{ + int nfserr; + + dprintk("nfsd: RENAME(3) %x/%ld %s -> %x/%ld %s\n", + SVCFH_DEV(&argp->ffh), + SVCFH_INO(&argp->ffh), + argp->fname, + SVCFH_DEV(&argp->tfh), + SVCFH_INO(&argp->tfh), + argp->tname); + + fh_copy(&resp->ffh, &argp->ffh); + fh_copy(&resp->tfh, &argp->tfh); + nfserr = nfsd_rename(rqstp, &resp->ffh, argp->fname, argp->flen, + &resp->tfh, argp->tname, argp->tlen); + RETURN(nfserr); +} + +static int +nfsd3_proc_link(struct svc_rqst *rqstp, struct nfsd3_linkargs *argp, + struct nfsd3_linkres *resp) +{ + int nfserr; + + dprintk("nfsd: LINK(3) %x/%ld -> %x/%ld %s\n", + SVCFH_DEV(&argp->ffh), + SVCFH_INO(&argp->ffh), + SVCFH_DEV(&argp->tfh), + SVCFH_INO(&argp->tfh), + argp->tname); + + fh_copy(&resp->fh, &argp->ffh); + fh_copy(&resp->tfh, &argp->tfh); + nfserr = nfsd_link(rqstp, &resp->tfh, argp->tname, argp->tlen, + &resp->fh); RETURN(nfserr); } @@ -395,44 +439,83 @@ */ static int nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp, - struct nfsd3_readdirres *resp) + struct nfsd3_readdirres *resp) +{ + u32 * buffer; + int nfserr, count; + unsigned int want; + + dprintk("nfsd: READDIR(3) %x/%ld %d bytes at %d\n", + SVCFH_DEV(&argp->fh), + SVCFH_INO(&argp->fh), + argp->count, (u32) argp->cookie); + + /* Reserve buffer space for status, attributes and verifier */ + svcbuf_reserve(&rqstp->rq_resbuf, &buffer, &count, + 1 + NFS3_POST_OP_ATTR_WORDS + 2); + + /* Make sure we've room for the NULL ptr & eof flag, and shrink to + * client read size */ + if ((count -= 2) > (want = (argp->count >> 2) - 2)) + count = want; + + /* Read directory and encode entries on the fly */ + fh_copy(&resp->fh, &argp->fh); + nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t) argp->cookie, + nfs3svc_encode_entry, + buffer, &count, argp->verf); + memcpy(resp->verf, argp->verf, 8); + resp->count = count; + + RETURN(nfserr); +} + +/* + * Read a portion of a directory, including file handles and attrs. + * For now, we choose to ignore the dircount parameter. + */ +static int +nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp, + struct nfsd3_readdirres *resp) { u32 * buffer; - int nfserr, count; + int nfserr, count, want; - dprintk("nfsd: READDIR %x/%ld %d bytes at %d\n", + dprintk("nfsd: READDIR+(3) %x/%ld %d bytes at %d\n", SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh), - argp->count, argp->cookie); + argp->count, (u32) argp->cookie); - /* Reserve buffer space for status */ - svcbuf_reserve(&rqstp->rq_resbuf, &buffer, &count, 1); + /* Reserve buffer space for status, attributes and verifier */ + svcbuf_reserve(&rqstp->rq_resbuf, &buffer, &count, + 1 + NFS3_POST_OP_ATTR_WORDS + 2); /* Make sure we've room for the NULL ptr & eof flag, and shrink to * client read size */ - if ((count -= 8) > argp->count) - count = argp->count; + if ((count -= 2) > (want = argp->count >> 2)) + count = want; /* Read directory and encode entries on the fly */ - nfserr = nfsd_readdir(rqstp, &argp->fh, (loff_t) argp->cookie, - nfssvc_encode_entry, - buffer, &count); + fh_copy(&resp->fh, &argp->fh); + nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t) argp->cookie, + nfs3svc_encode_entry_plus, + buffer, &count, argp->verf); + memcpy(resp->verf, argp->verf, 8); resp->count = count; - fh_put(&argp->fh); RETURN(nfserr); } /* - * Get file system info + * Get file system stats */ static int -nfsd3_proc_statfs(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, - struct nfsd3_statfsres *resp) +nfsd3_proc_fsstat(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, + struct nfsd3_fsstatres *resp) { int nfserr; - dprintk("nfsd: STATFS %x/%ld\n", + dprintk("nfsd: FSSTAT(3) %x/%ld\n", SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh)); @@ -442,104 +525,166 @@ } /* - * NFSv2 Server procedures. - * Only the results of non-idempotent operations are cached. + * Get file system info */ -#define nfsd3_proc_none NULL -#define nfssvc_encode_void NULL -#define nfssvc_decode_void NULL -#define nfssvc_release_void NULL -struct nfsd3_void { int dummy; }; +static int +nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, + struct nfsd3_fsinfores *resp) +{ + int nfserr; -#define PROC(name, argt, rest, relt, cache) \ - { (svc_procfunc) nfsd3_proc_##name, \ - (kxdrproc_t) nfssvc_decode_##argt, \ - (kxdrproc_t) nfssvc_encode_##rest, \ - (kxdrproc_t) nfssvc_release_##relt, \ - sizeof(struct nfsd3_##argt), \ - sizeof(struct nfsd3_##rest), \ - 0, \ - cache \ - } -struct svc_procedure nfsd3_procedures2[18] = { - PROC(null, void, void, void, RC_NOCACHE), - PROC(getattr, fhandle, attrstat, fhandle, RC_NOCACHE), - PROC(setattr, sattrargs, attrstat, fhandle, RC_REPLBUFF), - PROC(none, void, void, void, RC_NOCACHE), - PROC(lookup, diropargs, diropres, fhandle2,RC_NOCACHE), - PROC(readlink, fhandle, readlinkres, void, RC_NOCACHE), - PROC(read, readargs, readres, fhandle, RC_NOCACHE), - PROC(none, void, void, void, RC_NOCACHE), - PROC(write, writeargs, attrstat, fhandle, RC_REPLBUFF), - PROC(create, createargs, diropres, fhandle2,RC_REPLBUFF), - PROC(remove, diropargs, void,/* ??*/ void, RC_REPLSTAT), - PROC(rename, renameargs, void, void, RC_REPLSTAT), - PROC(link, linkargs, void, void, RC_REPLSTAT), - PROC(symlink, symlinkargs, void, void, RC_REPLSTAT), - PROC(mkdir, createargs, diropres, fhandle, RC_REPLBUFF), - PROC(rmdir, diropargs, void, void, RC_REPLSTAT), - PROC(readdir, readdirargs, readdirres, void, RC_REPLSTAT), - PROC(statfs, fhandle, statfsres, void, RC_NOCACHE), -}; + dprintk("nfsd: FSINFO(3) %x/%ld\n", + SVCFH_DEV(&argp->fh), + SVCFH_INO(&argp->fh)); + + resp->f_rtmax = NFSSVC_MAXBLKSIZE; + resp->f_rtpref = NFSSVC_MAXBLKSIZE; + resp->f_rtmult = PAGE_SIZE; + resp->f_wtmax = NFSSVC_MAXBLKSIZE; + resp->f_wtpref = NFSSVC_MAXBLKSIZE; + resp->f_wtmult = PAGE_SIZE; + resp->f_dtpref = PAGE_SIZE; + resp->f_maxfilesize = ~(u32) 0; + resp->f_properties = NFS3_FSF_DEFAULT; + + nfserr = fh_verify(rqstp, &argp->fh, 0, MAY_NOP); + + /* Check special features of the file system. May request + * different read/write sizes for file systems known to have + * problems with large blocks */ + if (nfserr == 0) { + struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb; + + /* Note that we don't care for remote fs's here */ + if (sb->s_magic == 0x4d44 /* MSDOS_SUPER_MAGIC */) { + resp->f_properties = NFS3_FSF_BILLYBOY; + } + } + fh_put(&argp->fh); + RETURN(nfserr); +} /* - * Map errnos to NFS errnos. + * Get pathconf info for the specified file */ -int -nfserrno (int errno) +static int +nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, + struct nfsd3_pathconfres *resp) { - static struct { - int nfserr; - int syserr; - } nfs_errtbl[] = { - { NFS_OK, 0 }, - { NFSERR_PERM, EPERM }, - { NFSERR_NOENT, ENOENT }, - { NFSERR_IO, EIO }, - { NFSERR_NXIO, ENXIO }, - { NFSERR_ACCES, EACCES }, - { NFSERR_EXIST, EEXIST }, - { NFSERR_NODEV, ENODEV }, - { NFSERR_NOTDIR, ENOTDIR }, - { NFSERR_ISDIR, EISDIR }, - { NFSERR_INVAL, EINVAL }, - { NFSERR_FBIG, EFBIG }, - { NFSERR_NOSPC, ENOSPC }, - { NFSERR_ROFS, EROFS }, - { NFSERR_NAMETOOLONG, ENAMETOOLONG }, - { NFSERR_NOTEMPTY, ENOTEMPTY }, -#ifdef EDQUOT - { NFSERR_DQUOT, EDQUOT }, -#endif - { NFSERR_STALE, ESTALE }, - { NFSERR_WFLUSH, EIO }, - { -1, EIO } - }; - int i; - - for (i = 0; nfs_errtbl[i].nfserr != -1; i++) { - if (nfs_errtbl[i].syserr == errno) - return htonl (nfs_errtbl[i].nfserr); + int nfserr; + + dprintk("nfsd: PATHCONF(3) %x/%ld\n", + SVCFH_DEV(&argp->fh), + SVCFH_INO(&argp->fh)); + + /* Set default pathconf */ + resp->p_link_max = 255; /* at least */ + resp->p_name_max = 255; /* at least */ + resp->p_no_trunc = 0; + resp->p_chown_restricted = 1; + resp->p_case_insensitive = 0; + resp->p_case_preserving = 1; + + nfserr = fh_verify(rqstp, &argp->fh, 0, MAY_NOP); + + if (nfserr == 0) { + struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb; + + /* Note that we don't care for remote fs's here */ + switch (sb->s_magic) { + case EXT2_SUPER_MAGIC: + resp->p_link_max = EXT2_LINK_MAX; + resp->p_name_max = EXT2_NAME_LEN; + break; + case 0x4d44: /* MSDOS_SUPER_MAGIC */ + resp->p_case_insensitive = 1; + resp->p_case_preserving = 0; + break; + } } - printk (KERN_INFO "nfsd: non-standard errno: %d\n", errno); - return nfserr_io; + + fh_put(&argp->fh); + RETURN(nfserr); } -#if 0 -static void -nfsd3_dump(char *tag, u32 *buf, int len) + +/* + * Commit a file (range) to stable storage. + */ +static int +nfsd3_proc_commit(struct svc_rqst * rqstp, struct nfsd3_commitargs *argp, + struct nfsd3_commitres *resp) { - int i; + int nfserr; - printk(KERN_NOTICE - "nfsd: %s (%d words)\n", tag, len); + dprintk("nfsd: COMMIT(3) %x/%ld %d@%ld\n", + SVCFH_DEV(&argp->fh), + SVCFH_INO(&argp->fh), + argp->count, + (unsigned long) argp->offset); + + if (argp->offset > NFS_OFFSET_MAX) + return nfserr_inval; - for (i = 0; i < len && i < 32; i += 8) - printk(KERN_NOTICE - " %08lx %08lx %08lx %08lx" - " %08lx %08lx %08lx %08lx\n", - buf[i], buf[i+1], buf[i+2], buf[i+3], - buf[i+4], buf[i+5], buf[i+6], buf[i+7]); + fh_copy(&resp->fh, &argp->fh); + nfserr = nfsd_commit(rqstp, &resp->fh, argp->offset, argp->count); + + RETURN(nfserr); } -#endif + + +/* + * NFSv3 Server procedures. + * Only the results of non-idempotent operations are cached. + */ +#define nfs3svc_decode_voidargs NULL +#define nfs3svc_encode_voidres NULL +#define nfs3svc_release_void NULL +#define nfs3svc_decode_fhandleargs nfs3svc_decode_fhandle +#define nfs3svc_encode_attrstatres nfs3svc_encode_attrstat +#define nfs3svc_encode_wccstatres nfs3svc_encode_wccstat +#define nfsd3_mkdirargs nfsd3_createargs +#define nfsd3_readdirplusargs nfsd3_readdirargs +#define nfsd3_fhandleargs nfsd_fhandle +#define nfsd3_fhandleres nfsd3_attrstat +#define nfsd3_attrstatres nfsd3_attrstat +#define nfsd3_wccstatres nfsd3_attrstat +#define nfsd3_createres nfsd3_diropres +#define nfsd3_voidres nfsd3_voidargs +struct nfsd3_voidargs { int dummy; }; + +#define PROC(name, argt, rest, relt, cache) \ + { (svc_procfunc) nfsd3_proc_##name, \ + (kxdrproc_t) nfs3svc_decode_##argt##args, \ + (kxdrproc_t) nfs3svc_encode_##rest##res, \ + (kxdrproc_t) nfs3svc_release_##relt, \ + sizeof(struct nfsd3_##argt##args), \ + sizeof(struct nfsd3_##rest##res), \ + 0, \ + cache \ + } +struct svc_procedure nfsd_procedures3[22] = { + PROC(null, void, void, void, RC_NOCACHE), + PROC(getattr, fhandle, attrstat, fhandle, RC_NOCACHE), + PROC(setattr, sattr, wccstat, fhandle, RC_REPLBUFF), + PROC(lookup, dirop, dirop, fhandle2, RC_NOCACHE), + PROC(access, access, access, fhandle, RC_NOCACHE), + PROC(readlink, fhandle, readlink, fhandle, RC_NOCACHE), + PROC(read, read, read, fhandle, RC_NOCACHE), + PROC(write, write, write, fhandle, RC_REPLBUFF), + PROC(create, create, create, fhandle2, RC_REPLBUFF), + PROC(mkdir, mkdir, create, fhandle2, RC_REPLBUFF), + PROC(symlink, symlink, create, fhandle2, RC_REPLBUFF), + PROC(mknod, mknod, create, fhandle2, RC_REPLBUFF), + PROC(remove, dirop, wccstat, fhandle, RC_REPLBUFF), + PROC(rmdir, dirop, wccstat, fhandle, RC_REPLBUFF), + PROC(rename, rename, rename, fhandle, RC_REPLSTAT), + PROC(link, link, link, fhandle2, RC_REPLSTAT), + PROC(readdir, readdir, readdir, fhandle, RC_NOCACHE), + PROC(readdirplus,readdirplus, readdir, fhandle, RC_NOCACHE), + PROC(fsstat, fhandle, fsstat, void, RC_NOCACHE), + PROC(fsinfo, fhandle, fsinfo, void, RC_NOCACHE), + PROC(pathconf, fhandle, pathconf, void, RC_NOCACHE), + PROC(commit, commit, commit, fhandle, RC_NOCACHE) +}; diff -u --new-file -X exclude linux-2.2.7-nfsv3/fs/nfsd/nfs3xdr.c linux/fs/nfsd/nfs3xdr.c --- linux-2.2.7-nfsv3/fs/nfsd/nfs3xdr.c Mon Apr 7 11:35:31 1997 +++ linux/fs/nfsd/nfs3xdr.c Fri Apr 30 23:44:22 1999 @@ -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,44 +37,13 @@ }; /* - * 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); + *p++ = htonl(val >> 32); + *p++ = htonl(val & 0xffffffff); return p; } @@ -103,13 +72,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,18 +145,24 @@ 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) { - iap->ia_valid |= ATTR_ATIME; - } else if (tmp == 2) { + if ((tmp = ntohl(*p++)) == 1) { /* set to server time */ iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET; + } else if (tmp == 2) { /* set to client time */ + iap->ia_valid |= ATTR_ATIME; iap->ia_atime = ntohl(*p++), p++; } - if ((tmp = *p++) != 0) { + if ((tmp = ntohl(*p++)) == 1) { /* set to server time */ iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET; - } else if (tmp == 2) { + } else if (tmp == 2) { /* set to client time */ iap->ia_valid |= ATTR_MTIME; iap->ia_mtime = ntohl(*p++), p++; } @@ -198,8 +170,10 @@ } 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; @@ -227,19 +201,50 @@ 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); + } + p = enc64(p, fhp->fh_post_blksize * fhp->fh_post_blocks); + *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->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 +253,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 +309,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 +345,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 +357,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 +378,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 +473,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 +487,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 +499,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); @@ -501,7 +515,8 @@ 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 +533,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 +549,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 +560,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 +573,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 +601,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 +627,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 +637,107 @@ 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 */ - memcpy(p, name, namlen); - p += slen; + *p++ = xdr_one; /* mark entry present */ + p = enc64(p, ino); /* file id */ + p = xdr_encode_string(p, name, namlen); /* name length & name */ + + 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; @@ -723,8 +772,8 @@ *p++ = htonl(resp->f_wtmult); *p++ = htonl(resp->f_dtpref); *p++ = htonl(resp->f_maxfilesize); + *p++ = xdr_one; *p++ = xdr_zero; - *p++ = htonl(1000000000 / HZ); *p++ = htonl(resp->f_properties); } @@ -741,8 +790,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 +818,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 +826,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); diff -u --new-file -X exclude linux-2.2.7-nfsv3/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c --- linux-2.2.7-nfsv3/fs/nfsd/nfsfh.c Sun Apr 11 22:03:43 1999 +++ linux/fs/nfsd/nfsfh.c Fri Apr 30 23:44:22 1999 @@ -1235,6 +1235,30 @@ goto out; } +void +__fh_unlock(struct svc_fh *fhp) +{ + struct inode *inode = fhp->fh_dentry->d_inode; + + if (fhp->fh_post_saved) + printk("nfsd: inode locked twice during operation.\n"); + + fhp->fh_post_mode = inode->i_mode; + fhp->fh_post_nlink = inode->i_nlink; + fhp->fh_post_uid = inode->i_uid; + fhp->fh_post_gid = inode->i_gid; + fhp->fh_post_size = inode->i_size; + fhp->fh_post_blksize = inode->i_blksize; + fhp->fh_post_blocks = inode->i_blocks; + fhp->fh_post_rdev = inode->i_rdev; + fhp->fh_post_atime = inode->i_atime; + fhp->fh_post_mtime = inode->i_mtime; + fhp->fh_post_ctime = inode->i_ctime; + fhp->fh_post_saved = 1; + fhp->fh_locked = 0; + up(&inode->i_sem); +} + /* * Release a file handle. If the file handle carries a dentry count, * we add the dentry to the short-term cache rather than release it. diff -u --new-file -X exclude linux-2.2.7-nfsv3/fs/nfsd/nfsproc.c linux/fs/nfsd/nfsproc.c --- linux-2.2.7-nfsv3/fs/nfsd/nfsproc.c Mon Apr 19 22:22:02 1999 +++ linux/fs/nfsd/nfsproc.c Fri Apr 30 23:44:22 1999 @@ -1,7 +1,10 @@ /* * nfsproc2.c Process version 2 NFS requests. + * linux/fs/nfsd/nfs2proc.c + * + * Process version 2 NFS requests. * - * Copyright (C) 1995 Olaf Kirch <okir@monad.swb.de> + * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de> */ #include <linux/linkage.h> @@ -87,7 +90,11 @@ dprintk("nfsd: LOOKUP %d/%d %s\n", SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh), argp->name); - +#ifdef NFSD_DEBUG + /* XXX: should go in the released version */ + if (!memcmp(argp->name, "..nfsd.xyzzy..", 14)) + nfsd_debug = ~nfsd_debug; +#endif nfserr = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len, &resp->fh); @@ -144,7 +151,7 @@ ntohl(rqstp->rq_addr.sin_addr.s_addr), ntohs(rqstp->rq_addr.sin_port), argp->count); - argp->count = avail; + argp->count = avail << 2; } resp->count = argp->count; @@ -276,7 +283,7 @@ type = S_IFIFO; } else if (size != rdev) { /* dev got truncated because of 16bit Linux dev_t */ - nfserr = nfserr_io; /* or nfserr_inval? */ + nfserr = nfserr_inval; goto out_unlock; } else { /* Okay, char or block special */ @@ -367,7 +374,7 @@ static int nfsd_proc_symlink(struct svc_rqst *rqstp, struct nfsd_symlinkargs *argp, - void *resp) + struct nfsd_fhandle *resp) { struct svc_fh newfh; int nfserr; @@ -381,7 +388,8 @@ */ nfserr = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen, argp->tname, argp->tlen, - &newfh); + &newfh, &argp->attrs); + if (!nfserr) { argp->attrs.ia_valid &= ~ATTR_SIZE; nfserr = nfsd_setattr(rqstp, &newfh, &argp->attrs); @@ -439,8 +447,8 @@ nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp, struct nfsd_readdirres *resp) { - u32 * buffer; - int nfserr, count; + u32 * buffer; + int nfserr, count; dprintk("nfsd: READDIR %d/%d %d bytes at %d\n", SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh), @@ -460,7 +468,8 @@ /* Read directory and encode entries on the fly */ nfserr = nfsd_readdir(rqstp, &argp->fh, (loff_t) argp->cookie, - nfssvc_encode_entry, buffer, &count); + nfssvc_encode_entry, + buffer, &count, NULL); resp->count = count; fh_put(&argp->fh); @@ -540,6 +549,8 @@ { NFSERR_NXIO, ENXIO }, { NFSERR_ACCES, EACCES }, { NFSERR_EXIST, EEXIST }, + { NFSERR_XDEV, EXDEV }, + { NFSERR_MLINK, EMLINK }, { NFSERR_NODEV, ENODEV }, { NFSERR_NOTDIR, ENOTDIR }, { NFSERR_ISDIR, EISDIR }, @@ -547,39 +558,22 @@ { NFSERR_FBIG, EFBIG }, { NFSERR_NOSPC, ENOSPC }, { NFSERR_ROFS, EROFS }, + { NFSERR_MLINK, EMLINK }, { NFSERR_NAMETOOLONG, ENAMETOOLONG }, { NFSERR_NOTEMPTY, ENOTEMPTY }, #ifdef EDQUOT { NFSERR_DQUOT, EDQUOT }, #endif { NFSERR_STALE, ESTALE }, - { NFSERR_WFLUSH, EIO }, { -1, EIO } }; int i; for (i = 0; nfs_errtbl[i].nfserr != -1; i++) { if (nfs_errtbl[i].syserr == errno) - return htonl (nfs_errtbl[i].nfserr); + return htonl(nfs_errtbl[i].nfserr); } printk (KERN_INFO "nfsd: non-standard errno: %d\n", errno); return nfserr_io; } -#if 0 -static void -nfsd_dump(char *tag, u32 *buf, int len) -{ - int i; - - printk(KERN_NOTICE - "nfsd: %s (%d words)\n", tag, len); - - for (i = 0; i < len && i < 32; i += 8) - printk(KERN_NOTICE - " %08lx %08lx %08lx %08lx" - " %08lx %08lx %08lx %08lx\n", - buf[i], buf[i+1], buf[i+2], buf[i+3], - buf[i+4], buf[i+5], buf[i+6], buf[i+7]); -} -#endif diff -u --new-file -X exclude linux-2.2.7-nfsv3/fs/nfsd/nfssvc.c linux/fs/nfsd/nfssvc.c --- linux-2.2.7-nfsv3/fs/nfsd/nfssvc.c Sun Apr 11 22:03:43 1999 +++ linux/fs/nfsd/nfssvc.c Fri Apr 30 23:44:22 1999 @@ -121,6 +121,8 @@ } lockd_up(); /* start lockd */ +/* nfsd_debug = -1; */ +/* rpc_debug = -1; */ /* * The main request loop */ @@ -202,7 +204,8 @@ kxdrproc_t xdr; u32 nfserr; - dprintk("nfsd_dispatch: proc %d\n", rqstp->rq_proc); + dprintk("nfsd_dispatch: vers %d proc %d\n", + rqstp->rq_vers, rqstp->rq_proc); proc = rqstp->rq_procinfo; /* Check whether we have this call in the cache. */ @@ -231,16 +234,17 @@ svc_putlong(&rqstp->rq_resbuf, nfserr); /* Encode result. - * FIXME: Most NFSv3 calls return wcc data even when the call failed + * For NFSv2, additional info is never returned in case of an error. */ - xdr = proc->pc_encode; - if (!nfserr && xdr - && !xdr(rqstp, rqstp->rq_resbuf.buf, rqstp->rq_resp)) { - /* Failed to encode result. Release cache entry */ - dprintk("nfsd: failed to encode result!\n"); - nfsd_cache_update(rqstp, RC_NOCACHE, NULL); - *statp = rpc_system_err; - return 1; + if (!(nfserr && rqstp->rq_vers == 2)) { + xdr = proc->pc_encode; + if (xdr && !xdr(rqstp, rqstp->rq_resbuf.buf, rqstp->rq_resp)) { + /* Failed to encode result. Release cache entry */ + dprintk("nfsd: failed to encode result!\n"); + nfsd_cache_update(rqstp, RC_NOCACHE, NULL); + *statp = rpc_system_err; + return 1; + } } /* Store reply in cache. */ @@ -251,16 +255,16 @@ static struct svc_version nfsd_version2 = { 2, 18, nfsd_procedures2, nfsd_dispatch }; -#ifdef CONFIG_NFSD_NFS3 +#ifdef CONFIG_NFS_V3 static struct svc_version nfsd_version3 = { - 3, 23, nfsd_procedures3, nfsd_dispatch + 3, 22, nfsd_procedures3, nfsd_dispatch }; #endif static struct svc_version * nfsd_version[] = { NULL, NULL, &nfsd_version2, -#ifdef CONFIG_NFSD_NFS3 +#ifdef CONFIG_NFS_V3 &nfsd_version3, #endif }; diff -u --new-file -X exclude linux-2.2.7-nfsv3/fs/nfsd/nfsxdr.c linux/fs/nfsd/nfsxdr.c --- linux-2.2.7-nfsv3/fs/nfsd/nfsxdr.c Wed Nov 26 13:08:38 1997 +++ linux/fs/nfsd/nfsxdr.c Fri Apr 30 23:44:22 1999 @@ -18,9 +18,14 @@ #define NFSDDBG_FACILITY NFSDDBG_XDR u32 nfs_ok, nfserr_perm, nfserr_noent, nfserr_io, nfserr_nxio, - nfserr_inval, nfserr_acces, nfserr_exist, nfserr_nodev, nfserr_notdir, - nfserr_isdir, nfserr_fbig, nfserr_nospc, nfserr_rofs, - nfserr_nametoolong, nfserr_dquot, nfserr_stale; + nfserr_acces, nfserr_exist, nfserr_xdev, nfserr_nodev, + nfserr_notdir, nfserr_isdir, nfserr_inval, nfserr_fbig, + nfserr_nospc, nfserr_rofs, nfserr_mlink, + nfserr_nametoolong, nfserr_notempty, nfserr_dquot, nfserr_stale, + nfserr_remote, nfserr_badhandle, nfserr_notsync, + nfserr_badcookie, nfserr_notsupp, nfserr_toosmall, + nfserr_serverfault, nfserr_badtype, nfserr_jukebox; + #ifdef NFSD_OPTIMIZE_SPACE # define inline @@ -52,18 +57,32 @@ nfserr_noent = htonl(NFSERR_NOENT); nfserr_io = htonl(NFSERR_IO); nfserr_inval = htonl(NFSERR_INVAL); - 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_nxio = htonl(NFSERR_NXIO); + nfserr_acces = htonl(NFSERR_ACCES); + nfserr_exist = htonl(NFSERR_EXIST); + nfserr_xdev = htonl(NFSERR_XDEV); + nfserr_nodev = htonl(NFSERR_NODEV); + nfserr_notdir = htonl(NFSERR_NOTDIR); + nfserr_isdir = htonl(NFSERR_ISDIR); + nfserr_inval = htonl(NFSERR_INVAL); + nfserr_fbig = htonl(NFSERR_FBIG); + nfserr_nospc = htonl(NFSERR_NOSPC); + nfserr_rofs = htonl(NFSERR_ROFS); + nfserr_mlink = htonl(NFSERR_MLINK); nfserr_nametoolong = htonl(NFSERR_NAMETOOLONG); - nfserr_dquot = htonl(NFSERR_DQUOT); - nfserr_stale = htonl(NFSERR_STALE); + nfserr_notempty = htonl(NFSERR_NOTEMPTY); + nfserr_dquot = htonl(NFSERR_DQUOT); + nfserr_stale = htonl(NFSERR_STALE); + nfserr_remote = htonl(NFSERR_REMOTE); + nfserr_badhandle = htonl(NFSERR_BADHANDLE); + nfserr_notsync = htonl(NFSERR_NOT_SYNC); + nfserr_badcookie = htonl(NFSERR_BAD_COOKIE); + nfserr_notsupp = htonl(NFSERR_NOTSUPP); + nfserr_toosmall = htonl(NFSERR_TOOSMALL); + nfserr_serverfault = htonl(NFSERR_SERVERFAULT); + nfserr_badtype = htonl(NFSERR_BADTYPE); + nfserr_jukebox = htonl(NFSERR_JUKEBOX); + inited = 1; } @@ -438,6 +457,12 @@ return -EINVAL; if (cd->offset) *cd->offset = htonl(offset); + + /* nfsd_readdir calls us with name == 0 if it wants us to + * set the last entry's offset. */ + if (name == 0) + return 0; + if (namlen > NFS2_MAXNAMLEN) namlen = NFS2_MAXNAMLEN;/* truncate filename */ diff -u --new-file -X exclude linux-2.2.7-nfsv3/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c --- linux-2.2.7-nfsv3/fs/nfsd/vfs.c Mon Apr 19 22:22:02 1999 +++ linux/fs/nfsd/vfs.c Fri Apr 30 23:44:22 1999 @@ -32,6 +32,7 @@ #include <linux/sunrpc/svc.h> #include <linux/nfsd/nfsd.h> +#include <linux/nfs3.h> #include <linux/nfsd/nfsfh.h> #include <linux/quotaops.h> @@ -239,6 +240,9 @@ if (err) goto out_nfserr; + /* Lock the inode */ + fh_lock(fhp); + /* The size case is special... */ if (iap->ia_valid & ATTR_SIZE) { if (!S_ISREG(inode->i_mode)) @@ -258,8 +262,8 @@ mark_inode_dirty(inode); put_write_access(inode); iap->ia_valid &= ~ATTR_SIZE; - iap->ia_valid |= ATTR_MTIME; - iap->ia_mtime = CURRENT_TIME; + iap->ia_valid |= ATTR_CTIME; + iap->ia_ctime = CURRENT_TIME; } imode = inode->i_mode; @@ -299,6 +303,9 @@ write_inode_now(inode); } err = 0; + + /* Don't unlock inode; the nfssvc_release functions are supposed + * to do this. */ out: return err; @@ -307,6 +314,83 @@ goto out; } +#ifdef CONFIG_NFS_V3 +/* + * Check server access rights to a file system object + */ +struct accessmap { + u32 access; + int how; +}; +static struct accessmap nfs3_regaccess[] = { + { NFS3_ACCESS_READ, MAY_READ }, + { NFS3_ACCESS_EXECUTE, MAY_EXEC }, + { NFS3_ACCESS_MODIFY, MAY_WRITE|MAY_TRUNC }, + { NFS3_ACCESS_EXTEND, MAY_WRITE }, + + { 0, 0 } +}; + +static struct accessmap nfs3_diraccess[] = { + { NFS3_ACCESS_READ, MAY_READ }, + { NFS3_ACCESS_LOOKUP, MAY_EXEC }, + { NFS3_ACCESS_MODIFY, MAY_EXEC|MAY_WRITE|MAY_TRUNC }, + { NFS3_ACCESS_EXTEND, MAY_EXEC|MAY_WRITE }, + + { 0, 0 } +}; + +static struct accessmap nfs3_anyaccess[] = { + /* XXX: should we try to cover read/write here for clients that + * rely on us to do their access checking for special files? */ + + { 0, 0 } +}; + +int +nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access) +{ + struct accessmap *map; + struct svc_export *export; + struct dentry *dentry; + u32 query, result = 0; + int error; + + error = fh_verify(rqstp, fhp, 0, MAY_NOP); + if (error < 0) + goto out; + + export = fhp->fh_export; + dentry = fhp->fh_dentry; + + if (S_ISREG(dentry->d_inode->i_mode)) { + map = nfs3_regaccess; + } else if (S_ISDIR(dentry->d_inode->i_mode)) { + map = nfs3_diraccess; + } else { + map = nfs3_anyaccess; + } + + query = *access; + while (map->access) { + if (map->access & query) { + error = nfsd_permission(export, dentry, map->how); + if (error == 0) + result |= map->access; + else if (error != -EPERM) + goto out; + } + map++; + } + *access = result; + +out: + return error; +} +#endif + + + /* * Open an existing file or directory. * The wflag argument indicates write access. @@ -396,8 +480,9 @@ * Sync a file */ void -nfsd_sync(struct inode *inode, struct file *filp) +nfsd_sync(struct file *filp) { + dprintk("nfsd: sync file %s\n", filp->f_dentry->d_name.name); filp->f_op->fsync(filp, filp->f_dentry); } @@ -529,10 +614,15 @@ * Request sync writes if * - the sync export option has been set, or * - the client requested O_SYNC behavior (NFSv3 feature). + * - The file system doesn't support fsync(). * When gathered writes have been configured for this volume, * flushing the data to disk is handled separately below. */ - if ((stable || (stable = EX_ISSYNC(exp))) && !EX_WGATHER(exp)) + if (rqstp->rq_vers == 2) + stable = EX_ISSYNC(exp); + else if (file.f_op->fsync == 0) + stable = 1; + if (stable && !EX_WGATHER(exp)) file.f_flags |= O_SYNC; fh_lock(fhp); /* lock inode */ @@ -554,7 +644,7 @@ /* clear setuid/setgid flag after write */ if (err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID))) { struct iattr ia; - kernel_cap_t saved_cap; + kernel_cap_t saved_cap = 0; ia.ia_valid = ATTR_MODE; ia.ia_mode = inode->i_mode & ~(S_ISUID | S_ISGID); @@ -591,6 +681,7 @@ interruptible_sleep_on_timeout(&inode->i_wait, 10 * HZ / 1000); #else dprintk("nfsd: write defer %d\n", current->pid); +/* FIXME: Olaf commented this out [gam3] */ schedule_timeout((HZ+99)/100); dprintk("nfsd: write resume %d\n", current->pid); #endif @@ -598,15 +689,16 @@ if (inode->i_state & I_DIRTY) { dprintk("nfsd: write sync %d\n", current->pid); - nfsd_sync(inode, &file); - write_inode_now(inode); + nfsd_sync(&file); + if (EX_ISSYNC(exp)) + write_inode_now(inode); } wake_up(&inode->i_wait); last_ino = inode->i_ino; last_dev = inode->i_dev; } - dprintk("nfsd: write complete\n"); + dprintk("nfsd: write complete err=%d\n", err); if (err >= 0) err = 0; else @@ -617,6 +709,40 @@ return err; } + +#ifdef CONFIG_NFS_V3 +/* + * Commit all pendig writes to stable storage. + * Strictly speaking, we could sync just indicated the file region here, + * but there's currently no way we can ask the VFS to do so. + * + * We lock the file to make sure we return full WCC data to the client. + */ +int +nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, + off_t offset, unsigned long count) +{ + struct file file; + int err; + + if ((err = nfsd_open(rqstp, fhp, S_IFREG, OPEN_WRITE, &file)) != 0) + return err; + + if (file.f_op && file.f_op->fsync) { + fh_lock(fhp); + nfsd_sync(&file); + fh_unlock(fhp); + if (EX_ISSYNC(fhp->fh_export)) + write_inode_now(fhp->fh_dentry->d_inode); + } else { + err = nfserr_notsupp; + } + + nfsd_close(&file); + return err; +} +#endif + /* * Create a file (regular, directory, device, fifo); UNIX sockets * not yet implemented. @@ -704,6 +830,9 @@ case S_IFSOCK: opfunc = dirp->i_op->mknod; break; + default: + printk("nfsd: bad file type %o in nfsd_create\n", type); + err = nfserr_inval; } if (!opfunc) goto out; @@ -744,6 +873,109 @@ goto out; } +#ifdef CONFIG_NFS_V3 +/* + * NFSv3 version of nfsd_create + */ +int +nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, + char *fname, int flen, struct iattr *iap, + struct svc_fh *resfhp, int createmode, u32 *verifier) +{ + struct dentry *dentry, *dchild; + struct inode *dirp; + int err; + + err = nfserr_perm; + if (!flen) + goto out; + if (!(iap->ia_valid & ATTR_MODE)) + iap->ia_mode = 0; + err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE); + if (err) + goto out; + + dentry = fhp->fh_dentry; + dirp = dentry->d_inode; + + /* Get all the sanity checks out of the way before + * we lock the parent. */ + err = nfserr_notdir; + if(!dirp->i_op || !dirp->i_op->lookup) + goto out; + err = nfserr_perm; + if(!dirp->i_op->create) + goto out; + + /* + * Compose the response file handle. + */ + dchild = lookup_dentry(fname, dget(dentry), 0); + err = PTR_ERR(dchild); + if(IS_ERR(dchild)) + goto out_nfserr; + fh_compose(resfhp, fhp->fh_export, dchild); + + /* + * We must lock the directory before we check for the inode. + */ + fh_lock(fhp); + + if (dchild->d_inode) { + err = 0; + + switch (createmode) { + case NFS3_CREATE_UNCHECKED: + break; + case NFS3_CREATE_EXCLUSIVE: + if (dchild->d_inode->i_mtime == verifier[0] + && dchild->d_inode->i_atime == verifier[1]) + break; + /* fallthru */ + case NFS3_CREATE_GUARDED: + err = nfserr_exist; + } + goto out; + } + + err = dirp->i_op->create(dirp, dchild, iap->ia_mode); + if (err < 0) + goto out_nfserr; + + if (EX_ISSYNC(fhp->fh_export)) + write_inode_now(dirp); + + /* + * Update the filehandle to get the new inode info. + */ + fh_update(resfhp); + err = 0; + + if (createmode == NFS3_CREATE_EXCLUSIVE) { + /* Cram the verifier into atime/mtime */ + iap->ia_valid = ATTR_MTIME|ATTR_ATIME; + iap->ia_mtime = verifier[0]; + iap->ia_atime = verifier[1]; + } + + /* Set file attributes. Mode has already been set and + * setting uid/gid works only for root. Irix appears to + * send along the gid when it tries to implement setgid + * directories via NFS. Clear out all that cruft. + */ + if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) + err = nfsd_setattr(rqstp, resfhp, iap); + + out: + fh_unlock(fhp); + return err; + + out_nfserr: + err = nfserrno(-err); + goto out; +} +#endif /* CONFIG_NFS_V3 */ + /* * Truncate a file. * The calling routines must make sure to update the ctime @@ -759,7 +991,7 @@ struct inode *inode; struct iattr newattrs; int err; - kernel_cap_t saved_cap; + kernel_cap_t saved_cap = 0; err = fh_verify(rqstp, fhp, S_IFREG, MAY_WRITE | MAY_TRUNC); if (err) @@ -824,7 +1056,10 @@ goto out; UPDATE_ATIME(inode); - /* N.B. Why does this call need a get_fs()?? */ + /* N.B. Why does this call need a get_fs()?? + * Remove the set_fs and watch the fireworks:-) --okir + */ + oldfs = get_fs(); set_fs(KERNEL_DS); err = inode->i_op->readlink(dentry, buf, *lenp); set_fs(oldfs); @@ -849,7 +1084,8 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *fname, int flen, char *path, int plen, - struct svc_fh *resfhp) + struct svc_fh *resfhp, + struct iattr *iap) { struct dentry *dentry, *dnew; struct inode *dirp; @@ -891,6 +1127,16 @@ if (!err) { if (EX_ISSYNC(fhp->fh_export)) write_inode_now(dirp); + if (iap) { + iap->ia_valid &= ~(ATTR_MODE|ATTR_UID|ATTR_GID); + if (iap->ia_valid) { + iap->ia_valid |= ATTR_CTIME; + iap->ia_ctime = CURRENT_TIME; + err = notify_change(dnew, iap); + if (!err && EX_ISSYNC(fhp->fh_export)) + write_inode_now(dnew->d_inode); + } + } } else err = nfserrno(-err); } @@ -1171,8 +1417,10 @@ rdentry->d_count--; DQUOT_DROP(dirp); +#ifdef FIXTHIS if (!fhp->fh_post_version) fhp->fh_post_version = dirp->i_version; +#endif fhp->fh_locked = 0; nfsd_double_up(&dirp->i_sem, &rdentry->d_inode->i_sem); @@ -1193,10 +1441,11 @@ /* * Read entries from a directory. + * The verifier is an NFSv3 thing we ignore for now. */ int nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, - encode_dent_fn func, u32 *buffer, int *countp) + encode_dent_fn func, u32 *buffer, int *countp, u32 *verf) { struct inode *inode; u32 *p; @@ -1222,6 +1471,7 @@ cd.rqstp = rqstp; cd.buffer = buffer; cd.buflen = *countp; /* count of words */ + cd.dirfh = fhp; /* * Read the directory entries. This silly loop is necessary because @@ -1314,7 +1564,7 @@ { struct inode *inode = dentry->d_inode; int err; - kernel_cap_t saved_cap; + kernel_cap_t saved_cap = 0; if (acc == MAY_NOP) return 0; diff -u --new-file -X exclude linux-2.2.7-nfsv3/include/linux/nfsd/const.h linux/include/linux/nfsd/const.h --- linux-2.2.7-nfsv3/include/linux/nfsd/const.h Fri Apr 30 16:27:42 1999 +++ linux/include/linux/nfsd/const.h Sat May 1 22:13:04 1999 @@ -1,19 +1,14 @@ /* - * include/linux/nfsd/nfsconst.h + * include/linux/nfsd/const.h * * Various constants related to NFS. * - * Copyright (C) 1995 Olaf Kirch <okir@monad.swb.de> + * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de> */ -#ifndef __NFSCONST_H__ -#define __NFSCONST_H__ +#ifndef _LINUX_NFSD_CONST_H +#define _LINUX_NFSD_CONST_H -#include <linux/limits.h> -#include <linux/types.h> -#include <linux/unistd.h> -#include <linux/dirent.h> -#include <linux/fs.h> #include <linux/nfs.h> #define NFS_FHSIZE 32 @@ -48,43 +43,6 @@ # define NFS_SUPER_MAGIC 0x6969 #endif -/* - * NFS stats. The good thing with these values is that NFSv3 errors are - * a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which - * no-one uses anyway), so we can happily mix code as long as we make sure - * no NFSv3 errors are returned to NFSv2 clients. - */ -#define NFS_OK 0 /* v2 v3 */ -#define NFSERR_PERM 1 /* v2 v3 */ -#define NFSERR_NOENT 2 /* v2 v3 */ -#define NFSERR_IO 5 /* v2 v3 */ -#define NFSERR_NXIO 6 /* v2 v3 */ -#define NFSERR_ACCES 13 /* v2 v3 */ -#define NFSERR_EXIST 17 /* v2 v3 */ -#define NFSERR_XDEV 18 /* v3 */ -#define NFSERR_NODEV 19 /* v2 v3 */ -#define NFSERR_NOTDIR 20 /* v2 v3 */ -#define NFSERR_ISDIR 21 /* v2 v3 */ -#define NFSERR_INVAL 22 /* v3 */ -#define NFSERR_FBIG 27 /* v2 v3 */ -#define NFSERR_NOSPC 28 /* v2 v3 */ -#define NFSERR_ROFS 30 /* v2 v3 */ -#define NFSERR_MLINK 31 /* v3 */ -#define NFSERR_NAMETOOLONG 63 /* v2 v3 */ -#define NFSERR_NOTEMPTY 66 /* v2 v3 */ -#define NFSERR_DQUOT 69 /* v2 v3 */ -#define NFSERR_STALE 70 /* v2 v3 */ -#define NFSERR_REMOTE 71 /* v3 */ -#define NFSERR_WFLUSH 99 /* v2 */ -#define NFSERR_BADHANDLE 10001 /* v3 */ -#define NFSERR_NOT_SYNC 10002 /* v3 */ -#define NFSERR_BAD_COOKIE 10003 /* v3 */ -#define NFSERR_NOTSUPP 10004 /* v3 */ -#define NFSERR_TOOSMALL 10005 /* v3 */ -#define NFSERR_SERVERFAULT 10006 /* v3 */ -#define NFSERR_BADTYPE 10007 /* v3 */ -#define NFSERR_JUKEBOX 10008 /* v3 */ - #endif /* __KERNEL__ */ -#endif /* __NFSCONST_H__ */ +#endif /* _LINUX_NFSD_CONST_H */ diff -u --new-file -X exclude linux-2.2.7-nfsv3/include/linux/nfsd/export.h linux/include/linux/nfsd/export.h --- linux-2.2.7-nfsv3/include/linux/nfsd/export.h Mon Feb 22 14:50:55 1999 +++ linux/include/linux/nfsd/export.h Sat May 1 01:34:32 1999 @@ -4,16 +4,17 @@ * Public declarations for NFS exports. The definitions for the * syscall interface are in nfsctl.h * - * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> + * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de> */ #ifndef NFSD_EXPORT_H #define NFSD_EXPORT_H -#include <linux/types.h> -#include <linux/socket.h> -#include <linux/in.h> -#include <linux/fs.h> +#include <asm/types.h> +#ifdef __KERNEL__ +# include <linux/types.h> +# include <linux/in.h> +#endif /* * Important limits for the exports stuff. diff -u --new-file -X exclude linux-2.2.7-nfsv3/include/linux/nfsd/nfsd.h linux/include/linux/nfsd/nfsd.h --- linux-2.2.7-nfsv3/include/linux/nfsd/nfsd.h Mon Feb 22 14:50:57 1999 +++ linux/include/linux/nfsd/nfsd.h Sat May 1 22:14:27 1999 @@ -4,7 +4,7 @@ * Hodge-podge collection of knfsd-related stuff. * I will sort this out later. * - * Copyright (C) 1995 Olaf Kirch <okir@monad.swb.de> + * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de> */ #ifndef LINUX_NFSD_NFSD_H @@ -24,7 +24,7 @@ /* * nfsd version */ -#define NFSD_VERSION "0.4" +#define NFSD_VERSION "0.5" #ifdef __KERNEL__ /* @@ -61,6 +61,7 @@ * Procedure table for NFSv2 */ extern struct svc_procedure nfsd_procedures2[]; +extern struct svc_procedure nfsd_procedures3[]; extern struct svc_program nfsd_program; /* @@ -74,11 +75,16 @@ void nfsd_racache_shutdown(void); int nfsd_lookup(struct svc_rqst *, struct svc_fh *, const char *, int, struct svc_fh *); +int nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *); int nfsd_setattr(struct svc_rqst *, struct svc_fh *, struct iattr *); int nfsd_create(struct svc_rqst *, struct svc_fh *, char *name, int len, struct iattr *attrs, int type, dev_t rdev, struct svc_fh *res); +int nfsd_create_v3(struct svc_rqst *, struct svc_fh *, + char *name, int len, struct iattr *attrs, + struct svc_fh *res, int createmode, + u32 *verifier); int nfsd_open(struct svc_rqst *, struct svc_fh *, int, int, struct file *); void nfsd_close(struct file *); @@ -90,7 +96,7 @@ char *, int *); int nfsd_symlink(struct svc_rqst *, struct svc_fh *, char *name, int len, char *path, int plen, - struct svc_fh *res); + struct svc_fh *res, struct iattr *); int nfsd_link(struct svc_rqst *, struct svc_fh *, char *, int, struct svc_fh *); int nfsd_rename(struct svc_rqst *, @@ -104,9 +110,11 @@ unsigned long size); int nfsd_readdir(struct svc_rqst *, struct svc_fh *, loff_t, encode_dent_fn, - u32 *buffer, int *countp); + u32 *buffer, int *countp, u32 *verf); int nfsd_statfs(struct svc_rqst *, struct svc_fh *, struct statfs *); +int nfsd_commit(struct svc_rqst *, struct svc_fh *, + off_t, unsigned long); int nfsd_notify_change(struct inode *, struct iattr *); int nfsd_permission(struct svc_export *, struct dentry *, int); @@ -146,6 +154,7 @@ nfserr_rofs, nfserr_mlink, nfserr_nametoolong, + nfserr_notempty, nfserr_dquot, nfserr_stale, nfserr_remote, diff -u --new-file -X exclude linux-2.2.7-nfsv3/include/linux/nfsd/nfsfh.h linux/include/linux/nfsd/nfsfh.h --- linux-2.2.7-nfsv3/include/linux/nfsd/nfsfh.h Sun Apr 11 22:03:59 1999 +++ linux/include/linux/nfsd/nfsfh.h Sat May 1 22:13:36 1999 @@ -11,12 +11,15 @@ * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de> */ -#ifndef NFSD_FH_H -#define NFSD_FH_H +#ifndef _LINUX_NFSD_FH_H +#define _LINUX_NFSD_FH_H -#include <linux/types.h> -#include <linux/string.h> -#include <linux/fs.h> +#include <asm/types.h> +#ifdef __KERNEL__ +# include <linux/types.h> +# include <linux/string.h> +# include <linux/fs.h> +#endif #include <linux/nfsd/const.h> #include <linux/nfsd/debug.h> @@ -81,20 +84,38 @@ struct knfs_fh fh_handle; /* FH data */ struct dentry * fh_dentry; /* validated dentry */ struct svc_export * fh_export; /* export pointer */ - size_t fh_pre_size; /* size before operation */ - time_t fh_pre_mtime; /* mtime before oper */ - time_t fh_pre_ctime; /* ctime before oper */ - unsigned long fh_post_version;/* inode version after oper */ + + unsigned char fh_post_saved; /* post-op attrs saved */ + unsigned char fh_pre_saved; /* pre-op attrs saved */ unsigned char fh_locked; /* inode locked by us */ unsigned char fh_dverified; /* dentry has been checked */ + + /* Pre-op attributes saved during fh_lock */ + __u64 fh_pre_size; /* size before operation */ + time_t fh_pre_mtime; /* mtime before oper */ + time_t fh_pre_ctime; /* ctime before oper */ + + /* Post-op attributes saved in fh_unlock */ + umode_t fh_post_mode; /* i_mode */ + nlink_t fh_post_nlink; /* i_nlink */ + uid_t fh_post_uid; /* i_uid */ + gid_t fh_post_gid; /* i_gid */ + __u64 fh_post_size; /* i_size */ + unsigned long fh_post_blocks; /* i_blocks */ + unsigned long fh_post_blksize;/* i_blksize */ + kdev_t fh_post_rdev; /* i_rdev */ + time_t fh_post_atime; /* i_atime */ + time_t fh_post_mtime; /* i_mtime */ + time_t fh_post_ctime; /* i_ctime */ + } svc_fh; /* * Shorthand for dprintk()'s */ #define SVCFH_DENTRY(f) ((f)->fh_dentry) -#define SVCFH_INO(f) ((f)->fh_handle.fh_ino) #define SVCFH_DEV(f) ((f)->fh_handle.fh_dev) +#define SVCFH_INO(f) ((f)->fh_handle.fh_ino) /* * Function prototypes @@ -103,6 +124,7 @@ void fh_compose(struct svc_fh *, struct svc_export *, struct dentry *); void fh_update(struct svc_fh *); void fh_put(struct svc_fh *); +void __fh_unlock(struct svc_fh *); void nfsd_fh_flush(kdev_t); void nfsd_fh_init(void); void nfsd_fh_free(void); @@ -139,10 +161,9 @@ struct dentry *dentry = fhp->fh_dentry; struct inode *inode; - /* dfprintk(FILEOP, "nfsd: fh_lock(%x/%ld) locked = %d\n", SVCFH_DEV(fhp), SVCFH_INO(fhp), fhp->fh_locked); - */ + if (!fhp->fh_dverified) { printk(KERN_ERR "fh_lock: fh not verified!\n"); return; @@ -155,8 +176,12 @@ inode = dentry->d_inode; down(&inode->i_sem); - if (!fhp->fh_pre_mtime) + if (!fhp->fh_pre_saved) { fhp->fh_pre_mtime = inode->i_mtime; + fhp->fh_pre_ctime = inode->i_ctime; + fhp->fh_pre_size = inode->i_size; + fhp->fh_pre_saved = 1; + } fhp->fh_locked = 1; } @@ -170,13 +195,7 @@ printk(KERN_ERR "fh_unlock: fh not verified!\n"); if (fhp->fh_locked) { - struct dentry *dentry = fhp->fh_dentry; - struct inode *inode = dentry->d_inode; - - if (!fhp->fh_post_version) - fhp->fh_post_version = inode->i_version; - fhp->fh_locked = 0; - up(&inode->i_sem); + __fh_unlock(fhp); } } @@ -210,4 +229,4 @@ #endif /* __KERNEL__ */ -#endif /* NFSD_FH_H */ +#endif /* _LINUX_NFSD_FH_H */ diff -u --new-file -X exclude linux-2.2.7-nfsv3/include/linux/nfsd/syscall.h linux/include/linux/nfsd/syscall.h --- linux-2.2.7-nfsv3/include/linux/nfsd/syscall.h Mon Dec 28 14:10:01 1998 +++ linux/include/linux/nfsd/syscall.h Sat May 1 22:15:32 1999 @@ -3,15 +3,18 @@ * * This file holds all declarations for the knfsd syscall interface. * - * Copyright (C) 1995 Olaf Kirch <okir@monad.swb.de> + * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de> */ #ifndef NFSD_SYSCALL_H #define NFSD_SYSCALL_H -#include <linux/config.h> -#include <linux/types.h> -#include <linux/socket.h> +#include <asm/types.h> +#ifdef __KERNEL__ +# include <linux/config.h> +# include <linux/types.h> +# include <linux/in.h> +#endif #include <linux/posix_types.h> #include <linux/nfsd/const.h> #include <linux/nfsd/export.h> diff -u --new-file -X exclude linux-2.2.7-nfsv3/include/linux/nfsd/xdr3.h linux/include/linux/nfsd/xdr3.h --- linux-2.2.7-nfsv3/include/linux/nfsd/xdr3.h Mon Apr 7 11:35:32 1997 +++ linux/include/linux/nfsd/xdr3.h Sat May 1 01:38:58 1999 @@ -3,17 +3,18 @@ * * XDR types for NFSv3 in nfsd. * - * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> + * Copyright (C) 1996-1998, Olaf Kirch <okir@monad.swb.de> */ -#ifndef LINUX_NFSD_XDR3_H -#define LINUX_NFSD_XDR3_H +#ifndef _LINUX_NFSD_XDR3_H +#define _LINUX_NFSD_XDR3_H #include <linux/nfsd/xdr.h> struct nfsd3_sattrargs { struct svc_fh fh; struct iattr attrs; + int check_guard; time_t guardtime; }; @@ -88,7 +89,7 @@ struct nfsd3_readdirargs { struct svc_fh fh; - __u32 cookie; + __u64 cookie; __u32 dircount; __u32 count; __u32 * verf; @@ -97,7 +98,7 @@ struct nfsd3_commitargs { struct svc_fh fh; __u64 offset; - __u64 count; + __u32 count; }; struct nfsd3_attrstat { @@ -105,7 +106,8 @@ struct svc_fh fh; }; -struct nfsd3_lookupres { +/* LOOKUP, CREATE, MKDIR, SYMLINK, MKNOD */ +struct nfsd3_diropres { __u32 status; struct svc_fh dirfh; struct svc_fh fh; @@ -137,12 +139,6 @@ int committed; }; -struct nfsd3_createres { - __u32 status; - struct svc_fh dirfh; - struct svc_fh fh; -}; - struct nfsd3_renameres { __u32 status; struct svc_fh ffh; @@ -158,10 +154,11 @@ struct nfsd3_readdirres { __u32 status; struct svc_fh fh; - __u32 * list_end; + int count; + __u32 verf[2]; }; -struct nfsd3_statfsres { +struct nfsd3_fsstatres { __u32 status; struct statfs stats; __u32 invarsec; @@ -184,6 +181,8 @@ __u32 status; __u32 p_link_max; __u32 p_name_max; + __u32 p_no_trunc; + __u32 p_chown_restricted; __u32 p_case_insensitive; __u32 p_case_preserving; }; @@ -194,7 +193,7 @@ }; /* dummy type for release */ -struct nfsd3_fhandle2 { +struct nfsd3_fhandle_pair { __u32 dummy; struct svc_fh fh1; struct svc_fh fh2; @@ -213,16 +212,15 @@ struct nfsd3_linkargs linkargs; struct nfsd3_symlinkargs symlinkargs; struct nfsd3_readdirargs readdirargs; - struct nfsd3_lookupres lookupres; + struct nfsd3_diropres diropres; struct nfsd3_accessres accessres; struct nfsd3_readlinkres readlinkres; struct nfsd3_readres readres; struct nfsd3_writeres writeres; - struct nfsd3_createres createres; struct nfsd3_renameres renameres; struct nfsd3_linkres linkres; struct nfsd3_readdirres readdirres; - struct nfsd3_statfsres statfsres; + struct nfsd3_fsstatres fsstatres; struct nfsd3_fsinfores fsinfores; struct nfsd3_pathconfres pathconfres; struct nfsd3_commitres commitres; @@ -230,39 +228,71 @@ #define NFS3_SVC_XDRSIZE sizeof(union nfsd3_xdrstore) -void nfsxdr_init(void); - int nfs3svc_decode_fhandle(struct svc_rqst *, u32 *, struct svc_fh *); -int nfs3svc_decode_sattr3args(struct svc_rqst *, u32 *, +int nfs3svc_decode_sattrargs(struct svc_rqst *, u32 *, struct nfsd3_sattrargs *); -int nfs3svc_decode_dirop3args(struct svc_rqst *, u32 *, +int nfs3svc_decode_diropargs(struct svc_rqst *, u32 *, struct nfsd3_diropargs *); -int nfs3svc_decode_read3args(struct svc_rqst *, u32 *, +int nfs3svc_decode_accessargs(struct svc_rqst *, u32 *, + struct nfsd3_accessargs *); +int nfs3svc_decode_readargs(struct svc_rqst *, u32 *, struct nfsd3_readargs *); -int nfs3svc_decode_write3args(struct svc_rqst *, u32 *, +int nfs3svc_decode_writeargs(struct svc_rqst *, u32 *, struct nfsd3_writeargs *); -int nfs3svc_decode_create3args(struct svc_rqst *, u32 *, +int nfs3svc_decode_createargs(struct svc_rqst *, u32 *, + struct nfsd3_createargs *); +int nfs3svc_decode_mkdirargs(struct svc_rqst *, u32 *, struct nfsd3_createargs *); -int nfs3svc_decode_rename3args(struct svc_rqst *, u32 *, +int nfs3svc_decode_mknodargs(struct svc_rqst *, u32 *, + struct nfsd3_mknodargs *); +int nfs3svc_decode_renameargs(struct svc_rqst *, u32 *, struct nfsd3_renameargs *); -int nfs3svc_decode_link3args(struct svc_rqst *, u32 *, +int nfs3svc_decode_linkargs(struct svc_rqst *, u32 *, struct nfsd3_linkargs *); -int nfs3svc_decode_symlink3args(struct svc_rqst *, u32 *, +int nfs3svc_decode_symlinkargs(struct svc_rqst *, u32 *, struct nfsd3_symlinkargs *); -int nfs3svc_decode_readdir3args(struct svc_rqst *, u32 *, +int nfs3svc_decode_readdirargs(struct svc_rqst *, u32 *, struct nfsd3_readdirargs *); +int nfs3svc_decode_readdirplusargs(struct svc_rqst *, u32 *, + struct nfsd3_readdirargs *); +int nfs3svc_decode_commitargs(struct svc_rqst *, u32 *, + struct nfsd3_commitargs *); +int nfs3svc_encode_attrstat(struct svc_rqst *, u32 *, + struct nfsd3_attrstat *); +int nfs3svc_encode_wccstat(struct svc_rqst *, u32 *, + struct nfsd3_attrstat *); +int nfs3svc_encode_diropres(struct svc_rqst *, u32 *, + struct nfsd3_diropres *); +int nfs3svc_encode_accessres(struct svc_rqst *, u32 *, + struct nfsd3_accessres *); int nfs3svc_encode_readlinkres(struct svc_rqst *, u32 *, struct nfsd3_readlinkres *); int nfs3svc_encode_readres(struct svc_rqst *, u32 *, struct nfsd3_readres *); -int nfs3svc_encode_statfsres(struct svc_rqst *, u32 *, - struct nfsd3_statfsres *); +int nfs3svc_encode_writeres(struct svc_rqst *, u32 *, struct nfsd3_writeres *); +int nfs3svc_encode_createres(struct svc_rqst *, u32 *, + struct nfsd3_diropres *); +int nfs3svc_encode_renameres(struct svc_rqst *, u32 *, + struct nfsd3_renameres *); +int nfs3svc_encode_linkres(struct svc_rqst *, u32 *, + struct nfsd3_linkres *); int nfs3svc_encode_readdirres(struct svc_rqst *, u32 *, struct nfsd3_readdirres *); +int nfs3svc_encode_fsstatres(struct svc_rqst *, u32 *, + struct nfsd3_fsstatres *); +int nfs3svc_encode_fsinfores(struct svc_rqst *, u32 *, + struct nfsd3_fsinfores *); +int nfs3svc_encode_pathconfres(struct svc_rqst *, u32 *, + struct nfsd3_pathconfres *); +int nfs3svc_encode_commitres(struct svc_rqst *, u32 *, + struct nfsd3_commitres *); + int nfs3svc_release_fhandle(struct svc_rqst *, u32 *, - struct nfsd_fhandle *); + struct nfsd3_attrstat *); int nfs3svc_release_fhandle2(struct svc_rqst *, u32 *, - struct nfsd3_fhandle2 *); + struct nfsd3_fhandle_pair *); int nfs3svc_encode_entry(struct readdir_cd *, const char *name, - int namlen, unsigned long offset, ino_t ino); + int namlen, off_t offset, ino_t ino); +int nfs3svc_encode_entry_plus(struct readdir_cd *, const char *name, + int namlen, off_t offset, ino_t ino); -#endif /* LINUX_NFSD_XDR3_H */ +#endif /* _LINUX_NFSD_XDR3_H */
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/
| |