diff -Nru linux-old/fs/namei.c linux-new/fs/namei.c
--- linux-old/fs/namei.c	2002-10-23 20:57:54.000000000 -0400
+++ linux-new/fs/namei.c	2002-10-23 21:59:11.000000000 -0400
@@ -635,7 +635,7 @@
 		dentry = nd->dentry;
 		if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
 			err = -ESTALE;
-			if (!dentry->d_op->d_revalidate(dentry, 0)) {
+			if (!dentry->d_op->d_revalidate(dentry, lookup_flags & LOOKUP_PARENT)) {
 				d_invalidate(dentry);
 				break;
 			}
diff -Nru linux-old/fs/nfs/dir.c linux-new/fs/nfs/dir.c
--- linux-old/fs/nfs/dir.c	2002-10-23 20:57:54.000000000 -0400
+++ linux-new/fs/nfs/dir.c	2002-10-23 21:59:11.000000000 -0400
@@ -442,7 +442,7 @@
 	 * If we're interested in close-to-open cache consistency,
 	 * then we revalidate the inode upon lookup.
 	 */
-	if (!(server->flags & NFS_MOUNT_NOCTO) && !(flags & LOOKUP_CONTINUE))
+	if (!(server->flags & NFS_MOUNT_NOCTO) && !(flags & (LOOKUP_CONTINUE|LOOKUP_PARENT)))
 		NFS_CACHEINV(inode);
 	return nfs_revalidate_inode(server, inode);
 }
diff -Nru linux-old/fs/nfs/inode.c linux-new/fs/nfs/inode.c
--- linux-old/fs/nfs/inode.c	2002-10-23 20:57:54.000000000 -0400
+++ linux-new/fs/nfs/inode.c	2002-10-23 21:59:11.000000000 -0400
@@ -251,6 +251,71 @@
 }
 
 /*
+ * Set up the NFS superblock private area using probed values
+ */
+static int
+nfs_setup_superblock(struct super_block *sb, struct nfs_fh *rootfh)
+{
+	struct nfs_server *server = &sb->u.nfs_sb.s_server;
+	struct nfs_fattr fattr;
+	struct nfs_fsinfo fsinfo = { &fattr, };
+	struct nfs_pathconf pathinfo = { &fattr, };
+	int maxlen, res;
+
+	res = server->rpc_ops->fsinfo(server, rootfh, &fsinfo);
+	if (res < 0)
+		return res;
+
+	/* Work out a lot of parameters */
+	if (!server->rsize)
+		server->rsize = nfs_block_size(fsinfo.rtpref, NULL);
+	if (!server->wsize)
+		server->wsize = nfs_block_size(fsinfo.wtpref, NULL);
+
+	/* NFSv3: we don't have bsize, but rather rtmult and wtmult... */
+	if (!fsinfo.wtmult)
+		fsinfo.wtmult = 512;
+	sb->s_blocksize = nfs_block_bits(fsinfo.wtmult, &sb->s_blocksize_bits);
+
+	if (server->rsize > fsinfo.rtmax)
+		server->rsize = fsinfo.rtmax;
+	if (server->wsize > fsinfo.wtmax)
+		server->wsize = fsinfo.wtmax;
+
+	server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+	if (server->rpages > NFS_READ_MAXIOV) {
+		server->rpages = NFS_READ_MAXIOV;
+		server->rsize = server->rpages << PAGE_CACHE_SHIFT;
+	}
+
+	server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+        if (server->wpages > NFS_WRITE_MAXIOV) {
+		server->wpages = NFS_WRITE_MAXIOV;
+                server->wsize = server->wpages << PAGE_CACHE_SHIFT;
+	}
+
+	server->dtsize = nfs_block_size(fsinfo.dtpref, NULL);
+	if (server->dtsize > PAGE_CACHE_SIZE)
+		server->dtsize = PAGE_CACHE_SIZE;
+	if (server->dtsize > server->rsize)
+		server->dtsize = server->rsize;
+
+        maxlen = (server->rpc_ops->version == 2) ? NFS2_MAXNAMLEN : NFS3_MAXNAMLEN;
+	if (!server->namelen) {
+		res = server->rpc_ops->pathconf(server, rootfh, &pathinfo);
+		if (!res)
+			server->namelen = pathinfo.name_max;
+	}
+        if (!server->namelen || server->namelen > maxlen)
+		server->namelen = maxlen;
+
+	sb->s_maxbytes = fsinfo.maxfilesize;
+	if (sb->s_maxbytes > MAX_LFS_FILESIZE) 
+		sb->s_maxbytes = MAX_LFS_FILESIZE; 
+	return 0;
+}
+
+/*
  * The way this works is that the mount process passes a structure
  * in the data argument which contains the server's IP address
  * and the root file handle obtained from the server's mount
@@ -268,8 +333,7 @@
 	unsigned int		authflavor;
 	struct sockaddr_in	srvaddr;
 	struct rpc_timeout	timeparms;
-	struct nfs_fsinfo	fsinfo;
-	int			tcp, version, maxlen;
+	int			tcp, version;
 
 	memset(&sb->u.nfs_sb, 0, sizeof(sb->u.nfs_sb));
 	if (!data)
@@ -298,11 +362,11 @@
 
 	sb->s_magic      = NFS_SUPER_MAGIC;
 	sb->s_op         = &nfs_sops;
-	sb->s_blocksize_bits = 0;
-	sb->s_blocksize  = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
 	server           = &sb->u.nfs_sb.s_server;
-	server->rsize    = nfs_block_size(data->rsize, NULL);
-	server->wsize    = nfs_block_size(data->wsize, NULL);
+	if (data->rsize)
+		server->rsize = nfs_block_size(data->rsize, NULL);
+	if (data->wsize)
+		server->wsize = nfs_block_size(data->wsize, NULL);
 	server->flags    = data->flags & NFS_MOUNT_FLAGMASK;
 
 	if (data->flags & NFS_MOUNT_NOAC) {
@@ -409,63 +473,11 @@
 	sb->s_root->d_op = &nfs_dentry_operations;
 
 	/* Get some general file system info */
-        if (server->rpc_ops->statfs(server, root, &fsinfo) >= 0) {
-		if (server->namelen == 0)
-			server->namelen = fsinfo.namelen;
-	} else {
+	if (nfs_setup_superblock(sb, root) < 0) {
 		printk(KERN_NOTICE "NFS: cannot retrieve file system info.\n");
 		goto out_no_root;
         }
 
-	/* Work out a lot of parameters */
-	if (data->rsize == 0)
-		server->rsize = nfs_block_size(fsinfo.rtpref, NULL);
-	if (data->wsize == 0)
-		server->wsize = nfs_block_size(fsinfo.wtpref, NULL);
-	/* NFSv3: we don't have bsize, but rather rtmult and wtmult... */
-	if (!fsinfo.bsize)
-		fsinfo.bsize = (fsinfo.rtmult>fsinfo.wtmult) ? fsinfo.rtmult : fsinfo.wtmult;
-	/* Also make sure we don't go below rsize/wsize since
-	 * RPC calls are expensive */
-	if (fsinfo.bsize < server->rsize)
-		fsinfo.bsize = server->rsize;
-	if (fsinfo.bsize < server->wsize)
-		fsinfo.bsize = server->wsize;
-
-	if (data->bsize == 0)
-		sb->s_blocksize = nfs_block_bits(fsinfo.bsize, &sb->s_blocksize_bits);
-	if (server->rsize > fsinfo.rtmax)
-		server->rsize = fsinfo.rtmax;
-	if (server->wsize > fsinfo.wtmax)
-		server->wsize = fsinfo.wtmax;
-
-	server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-	if (server->rpages > NFS_READ_MAXIOV) {
-		server->rpages = NFS_READ_MAXIOV;
-		server->rsize = server->rpages << PAGE_CACHE_SHIFT;
-	}
-
-	server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-        if (server->wpages > NFS_WRITE_MAXIOV) {
-		server->wpages = NFS_WRITE_MAXIOV;
-                server->wsize = server->wpages << PAGE_CACHE_SHIFT;
-	}
-
-	server->dtsize = nfs_block_size(fsinfo.dtpref, NULL);
-	if (server->dtsize > PAGE_CACHE_SIZE)
-		server->dtsize = PAGE_CACHE_SIZE;
-	if (server->dtsize > server->rsize)
-		server->dtsize = server->rsize;
-
-        maxlen = (version == 2) ? NFS2_MAXNAMLEN : NFS3_MAXNAMLEN;
-
-        if (server->namelen == 0 || server->namelen > maxlen)
-                server->namelen = maxlen;
-
-	sb->s_maxbytes = fsinfo.maxfilesize;
-	if (sb->s_maxbytes > MAX_LFS_FILESIZE) 
-		sb->s_maxbytes = MAX_LFS_FILESIZE; 
-
 	/* Fire up the writeback cache */
 	if (nfs_reqlist_alloc(server) < 0) {
 		printk(KERN_NOTICE "NFS: cannot initialize writeback cache.\n");
@@ -526,7 +538,8 @@
 	struct nfs_server *server = &sb->u.nfs_sb.s_server;
 	unsigned char blockbits;
 	unsigned long blockres;
-	struct nfs_fsinfo res;
+	struct nfs_fattr attr;
+	struct nfs_fsstat res = { &attr, };
 	int error;
 
 	error = server->rpc_ops->statfs(server, NFS_FH(sb->s_root->d_inode), &res);
@@ -534,18 +547,15 @@
 	if (error < 0)
 		goto out_err;
 
-	if (res.bsize == 0)
-		res.bsize = sb->s_blocksize;
-	buf->f_bsize = nfs_block_bits(res.bsize, &blockbits);
+	buf->f_bsize = sb->s_blocksize;
+	blockbits = sb->s_blocksize_bits;
 	blockres = (1 << blockbits) - 1;
 	buf->f_blocks = (res.tbytes + blockres) >> blockbits;
 	buf->f_bfree = (res.fbytes + blockres) >> blockbits;
 	buf->f_bavail = (res.abytes + blockres) >> blockbits;
 	buf->f_files = res.tfiles;
 	buf->f_ffree = res.afiles;
-	if (res.namelen == 0 || res.namelen > server->namelen)
-		res.namelen = server->namelen;
-	buf->f_namelen = res.namelen;
+	buf->f_namelen = server->namelen;
 	return 0;
  out_err:
 	printk("nfs_statfs: statfs error = %d\n", -error);
@@ -1060,7 +1070,8 @@
 	inode->i_atime = new_atime;
 
 	if (NFS_CACHE_MTIME(inode) != new_mtime) {
-		NFS_MTIME_UPDATE(inode) = jiffies;
+		if (invalid)
+			NFS_MTIME_UPDATE(inode) = jiffies;
 		NFS_CACHE_MTIME(inode) = new_mtime;
 		inode->i_mtime = nfs_time_to_secs(new_mtime);
 	}
diff -Nru linux-old/fs/nfs/nfs2xdr.c linux-new/fs/nfs/nfs2xdr.c
--- linux-old/fs/nfs/nfs2xdr.c	2002-10-23 20:57:54.000000000 -0400
+++ linux-new/fs/nfs/nfs2xdr.c	2002-10-23 21:59:11.000000000 -0400
@@ -572,36 +572,18 @@
  * Decode STATFS reply
  */
 static int
-nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
+nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs2_statfs *res)
 {
 	int	status;
-	u32	xfer_size;
 
 	if ((status = ntohl(*p++)))
 		return -nfs_stat_to_errno(status);
 
-	/* For NFSv2, we more or less have to guess the preferred
-	 * read/write/readdir sizes from the single 'transfer size'
-	 * value.
-	 */
-	xfer_size = ntohl(*p++);	/* tsize */
-	res->rtmax  = 8 * 1024;
-	res->rtpref = xfer_size;
-	res->rtmult = xfer_size;
-	res->wtmax  = 8 * 1024;
-	res->wtpref = xfer_size;
-	res->wtmult = xfer_size;
-	res->dtpref = PAGE_CACHE_SIZE;
-	res->maxfilesize = 0x7FFFFFFF;	/* just a guess */
+	res->tsize  = ntohl(*p++);
 	res->bsize  = ntohl(*p++);
-
-	res->tbytes = ntohl(*p++) * res->bsize;
-	res->fbytes = ntohl(*p++) * res->bsize;
-	res->abytes = ntohl(*p++) * res->bsize;
-	res->tfiles = 0;
-	res->ffiles = 0;
-	res->afiles = 0;
-	res->namelen = 0;
+	res->blocks = ntohl(*p++);
+	res->bfree  = ntohl(*p++);
+	res->bavail = ntohl(*p++);
 
 	return 0;
 }
diff -Nru linux-old/fs/nfs/nfs3proc.c linux-new/fs/nfs/nfs3proc.c
--- linux-old/fs/nfs/nfs3proc.c	2002-10-23 20:57:54.000000000 -0400
+++ linux-new/fs/nfs/nfs3proc.c	2002-10-23 21:59:11.000000000 -0400
@@ -483,24 +483,42 @@
 	return status;
 }
 
-/*
- * This is a combo call of fsstat and fsinfo
- */
 static int
 nfs3_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
-		 struct nfs_fsinfo *info)
+		 struct nfs_fsstat *stat)
 {
 	int	status;
 
-	dprintk("NFS call  fsstat\n");
-	memset((char *)info, 0, sizeof(*info));
-	status = rpc_call(server->client, NFS3PROC_FSSTAT, fhandle, info, 0);
-	if (status < 0)
-		goto error;
+	stat->fattr->valid = 0;
+	dprintk("NFS call statfs\n");
+	status = rpc_call(server->client, NFS3PROC_FSSTAT, fhandle, stat, 0);
+	dprintk("NFS reply statfs: %d\n", status);
+	return status;
+}
+
+static int
+nfs3_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
+		 struct nfs_fsinfo *info)
+{
+	int status;
+
+	info->fattr->valid = 0;
+	dprintk("NFS call fsinfo\n");
 	status = rpc_call(server->client, NFS3PROC_FSINFO, fhandle, info, 0);
+	dprintk("NFS reply fsinfo: %d\n", status);
+	return status;
+}
 
-error:
-	dprintk("NFS reply statfs: %d\n", status);
+static int
+nfs3_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
+		   struct nfs_pathconf *info)
+{
+	int status;
+
+	info->fattr->valid = 0;
+	dprintk("NFS call pathconf\n");
+	status = rpc_call(server->client, NFS3PROC_PATHCONF, fhandle, info, 0);
+	dprintk("NFS reply pathconf: %d\n", status);
 	return status;
 }
 
@@ -529,5 +547,7 @@
 	nfs3_proc_readdir,
 	nfs3_proc_mknod,
 	nfs3_proc_statfs,
+	nfs3_proc_fsinfo,
+	nfs3_proc_pathconf,
 	nfs3_decode_dirent,
 };
diff -Nru linux-old/fs/nfs/nfs3xdr.c linux-new/fs/nfs/nfs3xdr.c
--- linux-old/fs/nfs/nfs3xdr.c	2002-10-23 20:57:54.000000000 -0400
+++ linux-new/fs/nfs/nfs3xdr.c	2002-10-23 21:59:11.000000000 -0400
@@ -895,14 +895,13 @@
  * Decode FSSTAT reply
  */
 static int
-nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
+nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsstat *res)
 {
-	struct nfs_fattr dummy;
 	int		status;
 
 	status = ntohl(*p++);
 
-	p = xdr_decode_post_op_attr(p, &dummy);
+	p = xdr_decode_post_op_attr(p, res->fattr);
 	if (status != 0)
 		return -nfs_stat_to_errno(status);
 
@@ -912,8 +911,7 @@
 	p = xdr_decode_hyper(p, &res->tfiles);
 	p = xdr_decode_hyper(p, &res->ffiles);
 	p = xdr_decode_hyper(p, &res->afiles);
-
-	/* ignore invarsec */
+	res->invarsec = ntohl(*p++);
 	return 0;
 }
 
@@ -923,12 +921,11 @@
 static int
 nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
 {
-	struct nfs_fattr dummy;
 	int		status;
 
 	status = ntohl(*p++);
 
-	p = xdr_decode_post_op_attr(p, &dummy);
+	p = xdr_decode_post_op_attr(p, res->fattr);
 	if (status != 0)
 		return -nfs_stat_to_errno(status);
 
@@ -940,8 +937,8 @@
 	res->wtmult = ntohl(*p++);
 	res->dtpref = ntohl(*p++);
 	p = xdr_decode_hyper(p, &res->maxfilesize);
-
-	/* ignore time_delta and properties */
+	p = xdr_decode_time3(p, &res->time_delta);
+	res->properties = ntohl(*p++);
 	return 0;
 }
 
@@ -949,20 +946,21 @@
  * Decode PATHCONF reply
  */
 static int
-nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
+nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_pathconf *res)
 {
-	struct nfs_fattr dummy;
 	int		status;
 
 	status = ntohl(*p++);
 
-	p = xdr_decode_post_op_attr(p, &dummy);
+	p = xdr_decode_post_op_attr(p, res->fattr);
 	if (status != 0)
 		return -nfs_stat_to_errno(status);
 	res->linkmax = ntohl(*p++);
-	res->namelen = ntohl(*p++);
-
-	/* ignore remaining fields */
+	res->name_max = ntohl(*p++);
+	res->no_trunc = ntohl(*p++) != 0;
+	res->chown_restricted = ntohl(*p++) != 0;
+	res->case_insensitive = ntohl(*p++) != 0;
+	res->case_preserving = ntohl(*p++) != 0;
 	return 0;
 }
 
diff -Nru linux-old/fs/nfs/proc.c linux-new/fs/nfs/proc.c
--- linux-old/fs/nfs/proc.c	2002-10-23 20:57:54.000000000 -0400
+++ linux-new/fs/nfs/proc.c	2002-10-23 21:59:11.000000000 -0400
@@ -351,17 +351,62 @@
 
 static int
 nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
-			struct nfs_fsinfo *info)
+			struct nfs_fsstat *stat)
 {
 	int	status;
+	struct	nfs2_statfs fsinfo;
 
-	dprintk("NFS call  statfs\n");
-	memset((char *)info, 0, sizeof(*info));
-	status = rpc_call(server->client, NFSPROC_STATFS, fhandle, info, 0);
+	stat->fattr->valid = 0;
+	dprintk("NFS call statfs\n");
+	status = rpc_call(server->client, NFSPROC_STATFS, fhandle, &fsinfo, 0);
 	dprintk("NFS reply statfs: %d\n", status);
+	if (status)
+		goto out;
+	stat->tbytes = (u64)fsinfo.blocks * fsinfo.bsize;
+	stat->fbytes = (u64)fsinfo.bfree  * fsinfo.bsize;
+	stat->abytes = (u64)fsinfo.bavail * fsinfo.bsize;
+	stat->tfiles = 0;
+	stat->ffiles = 0;
+	stat->afiles = 0;
+	stat->invarsec = 0;
+ out:
 	return status;
 }
 
+static int
+nfs_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
+			struct nfs_fsinfo *info)
+{
+	int	status;
+	struct	nfs2_statfs fsinfo;
+
+	info->fattr->valid = 0;
+	dprintk("NFS call fsinfo\n");
+	status = rpc_call(server->client, NFSPROC_STATFS, fhandle, &fsinfo, 0);
+	dprintk("NFS reply fsinfo: %d\n", status);
+	if (status)
+		goto out;
+	info->rtmax  = NFS_MAXDATA;
+	info->rtpref = fsinfo.tsize;
+	info->rtmult = fsinfo.bsize;
+	info->wtmax  = NFS_MAXDATA;
+	info->wtpref = fsinfo.tsize;
+	info->wtmult = fsinfo.bsize;
+	info->dtpref = fsinfo.tsize;
+	info->maxfilesize = 0x7FFFFFFF;
+	info->time_delta = 0;
+	info->properties = 0x1b;
+ out:
+	return status;
+}
+
+static int
+nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
+			struct nfs_pathconf *info)
+{
+	return -ENOTSUPP;
+}
+
 extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int);
 
 struct nfs_rpc_ops     nfs_v2_clientops = {
@@ -387,5 +432,7 @@
        nfs_proc_readdir,
        nfs_proc_mknod,
        nfs_proc_statfs,
+       nfs_proc_fsinfo,
+       nfs_proc_pathconf,
        nfs_decode_dirent,
 };
diff -Nru linux-old/include/linux/nfs_xdr.h linux-new/include/linux/nfs_xdr.h
--- linux-old/include/linux/nfs_xdr.h	2002-10-23 20:58:12.000000000 -0400
+++ linux-new/include/linux/nfs_xdr.h	2002-10-23 21:59:11.000000000 -0400
@@ -37,6 +37,7 @@
  * Info on the file system
  */
 struct nfs_fsinfo {
+	struct nfs_fattr	*fattr;
 	__u32			rtmax;	/* max.  read transfer size */
 	__u32			rtpref;	/* pref. read transfer size */
 	__u32			rtmult;	/* reads should be multiple of this */
@@ -45,15 +46,37 @@
 	__u32			wtmult;	/* writes should be multiple of this */
 	__u32			dtpref;	/* pref. readdir transfer size */
 	__u64			maxfilesize;
-	__u64			bsize;	/* block size */
+	__u64			time_delta;
+	__u32			properties;
+};
+
+struct nfs_fsstat {
+	struct nfs_fattr	*fattr;
 	__u64			tbytes;	/* total size in bytes */
 	__u64			fbytes;	/* # of free bytes */
 	__u64			abytes;	/* # of bytes available to user */
 	__u64			tfiles;	/* # of files */
 	__u64			ffiles;	/* # of free files */
 	__u64			afiles;	/* # of files available to user */
+	__u32			invarsec;
+};
+
+struct nfs_pathconf {
+	struct nfs_fattr	*fattr; /* Post-op attributes */
 	__u32			linkmax;/* max # of hard links */
-	__u32			namelen;/* max name length */
+	__u32			name_max;/* max name length */
+	int			no_trunc : 1,
+				chown_restricted : 1,
+				case_insensitive : 1,
+				case_preserving : 1;
+};
+
+struct nfs2_statfs {
+	__u32			tsize;	/* Server transfer size */
+	__u32			bsize;	/* Filesystem block size */
+	__u32			blocks;	/* No. of "bsize" blocks on filesystem */
+	__u32			bfree;	/* No. of free "bsize" blocks */
+	__u32			bavail;	/* No. of available "bsize" blocks */
 };
 
 /* Arguments to the read call.
@@ -332,7 +355,11 @@
 	int	(*mknod)   (struct inode *, struct qstr *, struct iattr *,
 			    dev_t, struct nfs_fh *, struct nfs_fattr *);
 	int	(*statfs)  (struct nfs_server *, struct nfs_fh *,
+			    struct nfs_fsstat *);
+	int	(*fsinfo)  (struct nfs_server *, struct nfs_fh *,
 			    struct nfs_fsinfo *);
+	int	(*pathconf) (struct nfs_server *, struct nfs_fh *,
+			    struct nfs_pathconf *);
 	u32 *	(*decode_dirent)(u32 *, struct nfs_entry *, int plus);
 };
 
