X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=fs%2Fnfs%2Fgetroot.c;h=0ee43843f4ec40c79f1516fb869a5eb720cb355c;hb=c2319540cd7330fa9066e5b9b84d357a2c8631a2;hp=8391bd7a83ce46b81b9480f6710e7cbe37512ae3;hpb=e7b3ca08549caccf5d6e1cf066780bf4f0ae77a7;p=linux-2.6 diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index 8391bd7a83..0ee43843f4 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -42,7 +41,25 @@ #include "internal.h" #define NFSDBG_FACILITY NFSDBG_CLIENT -#define NFS_PARANOIA 1 + +/* + * Set the superblock root dentry. + * Note that this function frees the inode in case of error. + */ +static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *inode) +{ + /* The mntroot acts as the dummy root dentry for this superblock */ + if (sb->s_root == NULL) { + sb->s_root = d_alloc_root(inode); + if (sb->s_root == NULL) { + iput(inode); + return -ENOMEM; + } + /* Circumvent igrab(): we know the inode is not being freed */ + atomic_inc(&inode->i_count); + } + return 0; +} /* * get an NFS2/NFS3 root dentry from the root filehandle @@ -56,33 +73,6 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) struct inode *inode; int error; - /* create a dummy root dentry with dummy inode for this superblock */ - if (!sb->s_root) { - struct nfs_fh dummyfh; - struct dentry *root; - struct inode *iroot; - - memset(&dummyfh, 0, sizeof(dummyfh)); - memset(&fattr, 0, sizeof(fattr)); - nfs_fattr_init(&fattr); - fattr.valid = NFS_ATTR_FATTR; - fattr.type = NFDIR; - fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR; - fattr.nlink = 2; - - iroot = nfs_fhget(sb, &dummyfh, &fattr); - if (IS_ERR(iroot)) - return ERR_PTR(PTR_ERR(iroot)); - - root = d_alloc_root(iroot); - if (!root) { - iput(iroot); - return ERR_PTR(-ENOMEM); - } - - sb->s_root = root; - } - /* get the actual root for this mount */ fsinfo.fattr = &fattr; @@ -98,6 +88,10 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) return ERR_PTR(PTR_ERR(inode)); } + error = nfs_superblock_set_dummy_root(sb, inode); + if (error != 0) + return ERR_PTR(error); + /* root dentries normally start off anonymous and get spliced in later * if the dentry tree reaches them; however if the dentry already * exists, we'll pick it up at this point and use it as the root @@ -135,17 +129,15 @@ int nfs4_path_walk(struct nfs_server *server, struct nfs_fh lastfh; struct qstr name; int ret; - //int referral_count = 0; dprintk("--> nfs4_path_walk(,,%s)\n", path); fsinfo.fattr = &fattr; nfs_fattr_init(&fattr); - if (*path++ != '/') { - dprintk("nfs4_get_root: Path does not begin with a slash\n"); - return -EINVAL; - } + /* Eat leading slashes */ + while (*path == '/') + path++; /* Start by getting the root filehandle from the server */ ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); @@ -160,6 +152,7 @@ int nfs4_path_walk(struct nfs_server *server, return -ENOTDIR; } + /* FIXME: It is quite valid for the server to return a referral here */ if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) { printk(KERN_ERR "nfs4_get_root:" " getroot obtained referral\n"); @@ -178,6 +171,9 @@ next_component: path++; name.len = path - (const char *) name.name; + if (name.len > NFS4_MAXNAMLEN) + return -ENAMETOOLONG; + eat_dot_dir: while (*path == '/') path++; @@ -187,6 +183,7 @@ eat_dot_dir: goto eat_dot_dir; } + /* FIXME: Why shouldn't the user be able to use ".." in the path? */ if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || !path[2]) ) { printk(KERN_ERR "nfs4_get_root:" @@ -212,6 +209,7 @@ eat_dot_dir: return -ENOTDIR; } + /* FIXME: Referrals are quite valid here too */ if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) { printk(KERN_ERR "nfs4_get_root:" " lookupfh obtained referral\n"); @@ -239,33 +237,6 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) dprintk("--> nfs4_get_root()\n"); - /* create a dummy root dentry with dummy inode for this superblock */ - if (!sb->s_root) { - struct nfs_fh dummyfh; - struct dentry *root; - struct inode *iroot; - - memset(&dummyfh, 0, sizeof(dummyfh)); - memset(&fattr, 0, sizeof(fattr)); - nfs_fattr_init(&fattr); - fattr.valid = NFS_ATTR_FATTR; - fattr.type = NFDIR; - fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR; - fattr.nlink = 2; - - iroot = nfs_fhget(sb, &dummyfh, &fattr); - if (IS_ERR(iroot)) - return ERR_PTR(PTR_ERR(iroot)); - - root = d_alloc_root(iroot); - if (!root) { - iput(iroot); - return ERR_PTR(-ENOMEM); - } - - sb->s_root = root; - } - /* get the info about the server and filesystem */ error = nfs4_server_capabilities(server, mntfh); if (error < 0) { @@ -287,6 +258,10 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) return ERR_PTR(PTR_ERR(inode)); } + error = nfs_superblock_set_dummy_root(sb, inode); + if (error != 0) + return ERR_PTR(error); + /* root dentries normally start off anonymous and get spliced in later * if the dentry tree reaches them; however if the dentry already * exists, we'll pick it up at this point and use it as the root