From: Trond Myklebust <trond.myklebust@fys.uio.no>

Please also back out nfs-mount-error-recovery.patch.

The appended patch fixes the same problem as well as removing the need
for the equally severely broken NFS_INO_FAKE_ROOT state. The latter is
causing all sorts of Oopses and crap whenever it gets invoked.


---

 fs/nfs/inode.c          |   71 ++++++++++--------------------------------------
 fs/nfs/nfs3proc.c       |   14 ++++++---
 fs/nfs/nfs4proc.c       |   11 ++++---
 fs/nfs/proc.c           |   30 ++++++++++++++++----
 include/linux/nfs_fs.h  |    2 -
 include/linux/nfs_xdr.h |    2 -
 6 files changed, 56 insertions(+), 74 deletions(-)

diff -puN fs/nfs/inode.c~nfs-mount-fix fs/nfs/inode.c
--- 25/fs/nfs/inode.c~nfs-mount-fix	2004-02-28 18:11:27.000000000 -0800
+++ 25-akpm/fs/nfs/inode.c	2004-02-28 18:11:27.000000000 -0800
@@ -231,50 +231,23 @@ nfs_block_size(unsigned long bsize, unsi
 /*
  * Obtain the root inode of the file system.
  */
-static int
-nfs_get_root(struct inode **rooti, rpc_authflavor_t authflavor, struct super_block *sb, struct nfs_fh *rootfh)
+static struct inode *
+nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *fsinfo)
 {
 	struct nfs_server	*server = NFS_SB(sb);
-	struct nfs_fattr	fattr = { };
+	struct inode *rooti;
 	int			error;
 
-	error = server->rpc_ops->getroot(server, rootfh, &fattr);
-	if (error == -EACCES && authflavor > RPC_AUTH_MAXFLAVOR) {
-		/*
-		 * Some authentication types (gss/krb5, most notably)
-		 * are such that root won't be able to present a
-		 * credential for GETATTR (ie, getroot()).
-		 *
-		 * We still want the mount to succeed.
-		 * 
-		 * So we fake the attr values and mark the inode as such.
-		 * On the first succesful traversal, we fix everything.
-		 * The auth type test isn't quite correct, but whatever.
-		 */
-		dfprintk(VFS, "NFS: faking root inode\n");
-
-		fattr.fileid = 1;
-		fattr.nlink = 2;	/* minimum for a dir */
-		fattr.type = NFDIR;
-		fattr.mode = S_IFDIR|S_IRUGO|S_IXUGO;
-		fattr.size = 4096;
-		fattr.du.nfs3.used = 1;
-		fattr.valid = NFS_ATTR_FATTR|NFS_ATTR_FATTR_V3;
-	} else if (error < 0) {
+	error = server->rpc_ops->getroot(server, rootfh, fsinfo);
+	if (error < 0) {
 		printk(KERN_NOTICE "nfs_get_root: getattr error = %d\n", -error);
-		*rooti = NULL;	/* superfluous ... but safe */
-		return error;
+		return ERR_PTR(error);
 	}
 
-	*rooti = nfs_fhget(sb, rootfh, &fattr);
-	if (error == -EACCES && authflavor > RPC_AUTH_MAXFLAVOR) {
-		if (*rooti) {
-			NFS_FLAGS(*rooti) |= NFS_INO_FAKE_ROOT;
-			NFS_CACHEINV((*rooti));
-			error = 0;
-		}
-	}
-	return error;
+	rooti = nfs_fhget(sb, rootfh, fsinfo->fattr);
+	if (!rooti)
+		return ERR_PTR(-ENOMEM);
+	return rooti;
 }
 
 /*
@@ -284,7 +257,7 @@ static int
 nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
 {
 	struct nfs_server	*server;
-	struct inode		*root_inode = NULL;
+	struct inode		*root_inode;
 	struct nfs_fattr	fattr;
 	struct nfs_fsinfo	fsinfo = {
 					.fattr = &fattr,
@@ -300,8 +273,9 @@ nfs_sb_init(struct super_block *sb, rpc_
 
 	sb->s_magic      = NFS_SUPER_MAGIC;
 
+	root_inode = nfs_get_root(sb, &server->fh, &fsinfo);
 	/* Did getting the root inode fail? */
-	if (nfs_get_root(&root_inode, authflavor, sb, &server->fh) < 0)
+	if (IS_ERR(root_inode))
 		goto out_no_root;
 	sb->s_root = d_alloc_root(root_inode);
 	if (!sb->s_root)
@@ -310,10 +284,6 @@ nfs_sb_init(struct super_block *sb, rpc_
 	sb->s_root->d_op = server->rpc_ops->dentry_ops;
 
 	/* Get some general file system info */
-        if (server->rpc_ops->fsinfo(server, &server->fh, &fsinfo) < 0) {
-		printk(KERN_NOTICE "NFS: cannot retrieve file system info.\n");
-		goto out_no_root;
-        }
 	if (server->namelen == 0 &&
 	    server->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0)
 		server->namelen = pathinfo.max_namelen;
@@ -369,13 +339,11 @@ nfs_sb_init(struct super_block *sb, rpc_
 	rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
 	return 0;
 	/* Yargs. It didn't work out. */
-out_free_all:
-	if (root_inode)
-		iput(root_inode);
-	return -EINVAL;
 out_no_root:
 	printk("nfs_read_super: get root inode failed\n");
-	goto out_free_all;
+	if (!IS_ERR(root_inode))
+		iput(root_inode);
+	return -EINVAL;
 }
 
 /*
@@ -1157,13 +1125,6 @@ static int nfs_update_inode(struct inode
 	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
 		return 0;
 
-	/* First successful call after mount, fill real data. */
-	if (NFS_FAKE_ROOT(inode)) {
-		dfprintk(VFS, "NFS: updating fake root\n");
-		nfsi->fileid = fattr->fileid;
-		NFS_FLAGS(inode) &= ~NFS_INO_FAKE_ROOT;
-	}
-
 	if (nfsi->fileid != fattr->fileid) {
 		printk(KERN_ERR "%s: inode number mismatch\n"
 		       "expected (%s/0x%Lx), got (%s/0x%Lx)\n",
diff -puN fs/nfs/nfs3proc.c~nfs-mount-fix fs/nfs/nfs3proc.c
--- 25/fs/nfs/nfs3proc.c~nfs-mount-fix	2004-02-28 18:11:27.000000000 -0800
+++ 25-akpm/fs/nfs/nfs3proc.c	2004-02-28 18:11:27.000000000 -0800
@@ -85,14 +85,18 @@ nfs_cred(struct inode *inode, struct fil
  */
 static int
 nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
-		   struct nfs_fattr *fattr)
+		   struct nfs_fsinfo *info)
 {
 	int	status;
 
-	dprintk("NFS call  getroot\n");
-	fattr->valid = 0;
-	status = rpc_call(server->client, NFS3PROC_GETATTR, fhandle, fattr, 0);
-	dprintk("NFS reply getroot\n");
+	dprintk("%s: call  fsinfo\n", __FUNCTION__);
+	info->fattr->valid = 0;
+	status = rpc_call(server->client_sys, NFS3PROC_FSINFO, fhandle, info, 0);
+	dprintk("%s: reply fsinfo %d\n", __FUNCTION__, status);
+	if (!(info->fattr->valid & NFS_ATTR_FATTR)) {
+		status = rpc_call(server->client_sys, NFS3PROC_GETATTR, fhandle, info->fattr, 0);
+		dprintk("%s: reply getattr %d\n", __FUNCTION__, status);
+	}
 	return status;
 }
 
diff -puN fs/nfs/nfs4proc.c~nfs-mount-fix fs/nfs/nfs4proc.c
--- 25/fs/nfs/nfs4proc.c~nfs-mount-fix	2004-02-28 18:11:27.000000000 -0800
+++ 25-akpm/fs/nfs/nfs4proc.c	2004-02-28 18:11:27.000000000 -0800
@@ -54,6 +54,7 @@
 #define GET_OP(cp,name)		&cp->ops[cp->req_nops].u.name
 #define OPNUM(cp)		cp->ops[cp->req_nops].opnum
 
+static int nfs4_proc_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
 static int nfs4_async_handle_error(struct rpc_task *, struct nfs_server *);
 extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);
 extern struct rpc_procinfo nfs4_procedures[];
@@ -822,10 +823,11 @@ nfs4_open_revalidate(struct inode *dir, 
 
 static int
 nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
-		   struct nfs_fattr *fattr)
+		   struct nfs_fsinfo *info)
 {
 	struct nfs4_compound	compound;
 	struct nfs4_op		ops[4];
+	struct nfs_fattr *	fattr = info->fattr;
 	unsigned char *		p;
 	struct qstr		q;
 	int			status;
@@ -869,7 +871,9 @@ nfs4_proc_get_root(struct nfs_server *se
 		break;
 	}
 out:
-	return status;
+	if (status)
+		return status;
+	return nfs4_proc_fsinfo(server, fhandle, info);
 }
 
 static int
@@ -1458,7 +1462,6 @@ nfs4_proc_statfs(struct nfs_server *serv
 	struct nfs4_compound compound;
 	struct nfs4_op ops[2];
 
-	memset(fsstat, 0, sizeof(*fsstat));
 	nfs4_setup_compound(&compound, ops, server, "statfs");
 	nfs4_setup_putfh(&compound, fhandle);
 	nfs4_setup_statfs(&compound, fsstat);
@@ -1475,7 +1478,6 @@ nfs4_proc_fsinfo(struct nfs_server *serv
 		.rpc_resp = fsinfo,
 	};
 
-	memset(fsinfo, 0, sizeof(*fsinfo));
 	return rpc_call_sync(server->client, &msg, 0);
 }
 
@@ -1486,7 +1488,6 @@ nfs4_proc_pathconf(struct nfs_server *se
 	struct nfs4_compound compound;
 	struct nfs4_op ops[2];
 
-	memset(pathconf, 0, sizeof(*pathconf));
 	nfs4_setup_compound(&compound, ops, server, "statfs");
 	nfs4_setup_putfh(&compound, fhandle);
 	nfs4_setup_pathconf(&compound, pathconf);
diff -puN fs/nfs/proc.c~nfs-mount-fix fs/nfs/proc.c
--- 25/fs/nfs/proc.c~nfs-mount-fix	2004-02-28 18:11:27.000000000 -0800
+++ 25-akpm/fs/nfs/proc.c	2004-02-28 18:11:27.000000000 -0800
@@ -66,15 +66,33 @@ nfs_cred(struct inode *inode, struct fil
  */
 static int
 nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
-		  struct nfs_fattr *fattr)
+		  struct nfs_fsinfo *info)
 {
-	int		status;
+	struct nfs_fattr *fattr = info->fattr;
+	struct nfs2_fsstat fsinfo;
+	int status;
 
-	dprintk("NFS call  getroot\n");
+	dprintk("%s: call getattr\n", __FUNCTION__);
 	fattr->valid = 0;
-	status = rpc_call(server->client, NFSPROC_GETATTR, fhandle, fattr, 0);
-	dprintk("NFS reply getroot\n");
-	return status;
+	status = rpc_call(server->client_sys, NFSPROC_GETATTR, fhandle, fattr, 0);
+	dprintk("%s: reply getattr %d\n", __FUNCTION__, status);
+	if (status)
+		return status;
+	dprintk("%s: call statfs\n", __FUNCTION__);
+	status = rpc_call(server->client_sys, NFSPROC_STATFS, fhandle, &fsinfo, 0);
+	dprintk("%s: reply statfs %d\n", __FUNCTION__, status);
+	if (status)
+		return status;
+	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->lease_time = 0;
+	return 0;
 }
 
 /*
diff -puN include/linux/nfs_fs.h~nfs-mount-fix include/linux/nfs_fs.h
--- 25/include/linux/nfs_fs.h~nfs-mount-fix	2004-02-28 18:11:27.000000000 -0800
+++ 25-akpm/include/linux/nfs_fs.h	2004-02-28 18:11:27.000000000 -0800
@@ -176,7 +176,6 @@ struct nfs_inode {
 #define NFS_INO_INVALID_ATTR	0x0008		/* cached attrs are invalid */
 #define NFS_INO_INVALID_DATA	0x0010		/* cached data is invalid */
 #define NFS_INO_INVALID_ATIME	0x0020		/* cached atime is invalid */
-#define NFS_INO_FAKE_ROOT	0x0080		/* root inode placeholder */
 
 static inline struct nfs_inode *NFS_I(struct inode *inode)
 {
@@ -204,7 +203,6 @@ static inline struct nfs_inode *NFS_I(st
 #define NFS_FLAGS(inode)		(NFS_I(inode)->flags)
 #define NFS_REVALIDATING(inode)		(NFS_FLAGS(inode) & NFS_INO_REVALIDATING)
 #define NFS_STALE(inode)		(NFS_FLAGS(inode) & NFS_INO_STALE)
-#define NFS_FAKE_ROOT(inode)		(NFS_FLAGS(inode) & NFS_INO_FAKE_ROOT)
 
 #define NFS_FILEID(inode)		(NFS_I(inode)->fileid)
 
diff -puN include/linux/nfs_xdr.h~nfs-mount-fix include/linux/nfs_xdr.h
--- 25/include/linux/nfs_xdr.h~nfs-mount-fix	2004-02-28 18:11:27.000000000 -0800
+++ 25-akpm/include/linux/nfs_xdr.h	2004-02-28 18:11:27.000000000 -0800
@@ -700,7 +700,7 @@ struct nfs_rpc_ops {
 	struct inode_operations *dir_inode_ops;
 
 	int	(*getroot) (struct nfs_server *, struct nfs_fh *,
-			    struct nfs_fattr *);
+			    struct nfs_fsinfo *);
 	int	(*getattr) (struct inode *, struct nfs_fattr *);
 	int	(*setattr) (struct dentry *, struct nfs_fattr *,
 			    struct iattr *);

_