From: Trond Myklebust 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 *); _