[alpha patch] knfsd version 3

G. Allen Morris III (gam3@ann.ixlabs.com)
Sun, 02 May 1999 14:47:28 -0700


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/