Merge branch 'for-2.6.35' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
[safe/jmp/linux-2.6] / fs / nfs / getroot.c
index b7c9b2d..7428f7d 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/nfs_idmap.h>
 #include <linux/vfs.h>
 #include <linux/namei.h>
-#include <linux/mnt_namespace.h>
 #include <linux/security.h>
 
 #include <asm/system.h>
@@ -79,159 +78,94 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh)
 {
        struct nfs_server *server = NFS_SB(sb);
        struct nfs_fsinfo fsinfo;
-       struct nfs_fattr fattr;
-       struct dentry *mntroot;
+       struct dentry *ret;
        struct inode *inode;
        int error;
 
        /* get the actual root for this mount */
-       fsinfo.fattr = &fattr;
+       fsinfo.fattr = nfs_alloc_fattr();
+       if (fsinfo.fattr == NULL)
+               return ERR_PTR(-ENOMEM);
 
        error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo);
        if (error < 0) {
                dprintk("nfs_get_root: getattr error = %d\n", -error);
-               return ERR_PTR(error);
+               ret = ERR_PTR(error);
+               goto out;
        }
 
        inode = nfs_fhget(sb, mntfh, fsinfo.fattr);
        if (IS_ERR(inode)) {
                dprintk("nfs_get_root: get root inode failed\n");
-               return ERR_CAST(inode);
+               ret = ERR_CAST(inode);
+               goto out;
        }
 
        error = nfs_superblock_set_dummy_root(sb, inode);
-       if (error != 0)
-               return ERR_PTR(error);
+       if (error != 0) {
+               ret = ERR_PTR(error);
+               goto out;
+       }
 
        /* 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
         */
-       mntroot = d_obtain_alias(inode);
-       if (IS_ERR(mntroot)) {
+       ret = d_obtain_alias(inode);
+       if (IS_ERR(ret)) {
                dprintk("nfs_get_root: get root dentry failed\n");
-               return mntroot;
+               goto out;
        }
 
-       security_d_instantiate(mntroot, inode);
-
-       if (!mntroot->d_op)
-               mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops;
+       security_d_instantiate(ret, inode);
 
-       return mntroot;
+       if (ret->d_op == NULL)
+               ret->d_op = server->nfs_client->rpc_ops->dentry_ops;
+out:
+       nfs_free_fattr(fsinfo.fattr);
+       return ret;
 }
 
 #ifdef CONFIG_NFS_V4
 
-/*
- * Do a simple pathwalk from the root FH of the server to the nominated target
- * of the mountpoint
- * - give error on symlinks
- * - give error on ".." occurring in the path
- * - follow traversals
- */
-int nfs4_path_walk(struct nfs_server *server,
-                  struct nfs_fh *mntfh,
-                  const char *path)
+int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh)
 {
        struct nfs_fsinfo fsinfo;
-       struct nfs_fattr fattr;
-       struct nfs_fh lastfh;
-       struct qstr name;
-       int ret;
+       int ret = -ENOMEM;
 
-       dprintk("--> nfs4_path_walk(,,%s)\n", path);
+       dprintk("--> nfs4_get_rootfh()\n");
 
-       fsinfo.fattr = &fattr;
-       nfs_fattr_init(&fattr);
-
-       /* Eat leading slashes */
-       while (*path == '/')
-               path++;
+       fsinfo.fattr = nfs_alloc_fattr();
+       if (fsinfo.fattr == NULL)
+               goto out;
 
        /* Start by getting the root filehandle from the server */
        ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo);
        if (ret < 0) {
-               dprintk("nfs4_get_root: getroot error = %d\n", -ret);
-               return ret;
+               dprintk("nfs4_get_rootfh: getroot error = %d\n", -ret);
+               goto out;
        }
 
-       if (fattr.type != NFDIR) {
-               printk(KERN_ERR "nfs4_get_root:"
+       if (!(fsinfo.fattr->valid & NFS_ATTR_FATTR_MODE)
+                       || !S_ISDIR(fsinfo.fattr->mode)) {
+               printk(KERN_ERR "nfs4_get_rootfh:"
                       " getroot encountered non-directory\n");
-               return -ENOTDIR;
+               ret = -ENOTDIR;
+               goto out;
        }
 
-       /* 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:"
+       if (fsinfo.fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) {
+               printk(KERN_ERR "nfs4_get_rootfh:"
                       " getroot obtained referral\n");
-               return -EREMOTE;
-       }
-
-next_component:
-       dprintk("Next: %s\n", path);
-
-       /* extract the next bit of the path */
-       if (!*path)
-               goto path_walk_complete;
-
-       name.name = path;
-       while (*path && *path != '/')
-               path++;
-       name.len = path - (const char *) name.name;
-
-       if (name.len > NFS4_MAXNAMLEN)
-               return -ENAMETOOLONG;
-
-eat_dot_dir:
-       while (*path == '/')
-               path++;
-
-       if (path[0] == '.' && (path[1] == '/' || !path[1])) {
-               path += 2;
-               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:"
-                      " Mount path contains reference to \"..\"\n");
-               return -EINVAL;
+               ret = -EREMOTE;
+               goto out;
        }
 
-       /* lookup the next FH in the sequence */
-       memcpy(&lastfh, mntfh, sizeof(lastfh));
-
-       dprintk("LookupFH: %*.*s [%s]\n", name.len, name.len, name.name, path);
-
-       ret = server->nfs_client->rpc_ops->lookupfh(server, &lastfh, &name,
-                                                   mntfh, &fattr);
-       if (ret < 0) {
-               dprintk("nfs4_get_root: getroot error = %d\n", -ret);
-               return ret;
-       }
-
-       if (fattr.type != NFDIR) {
-               printk(KERN_ERR "nfs4_get_root:"
-                      " lookupfh encountered non-directory\n");
-               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");
-               return -EREMOTE;
-       }
-
-       goto next_component;
-
-path_walk_complete:
-       memcpy(&server->fsid, &fattr.fsid, sizeof(server->fsid));
-       dprintk("<-- nfs4_path_walk() = 0\n");
-       return 0;
+       memcpy(&server->fsid, &fsinfo.fattr->fsid, sizeof(server->fsid));
+out:
+       nfs_free_fattr(fsinfo.fattr);
+       dprintk("<-- nfs4_get_rootfh() = %d\n", ret);
+       return ret;
 }
 
 /*
@@ -240,8 +174,8 @@ path_walk_complete:
 struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh)
 {
        struct nfs_server *server = NFS_SB(sb);
-       struct nfs_fattr fattr;
-       struct dentry *mntroot;
+       struct nfs_fattr *fattr = NULL;
+       struct dentry *ret;
        struct inode *inode;
        int error;
 
@@ -255,40 +189,50 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh)
                return ERR_PTR(error);
        }
 
+       fattr = nfs_alloc_fattr();
+       if (fattr == NULL)
+               return ERR_PTR(-ENOMEM);;
+
        /* get the actual root for this mount */
-       error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr);
+       error = server->nfs_client->rpc_ops->getattr(server, mntfh, fattr);
        if (error < 0) {
                dprintk("nfs_get_root: getattr error = %d\n", -error);
-               return ERR_PTR(error);
+               ret = ERR_PTR(error);
+               goto out;
        }
 
-       inode = nfs_fhget(sb, mntfh, &fattr);
+       inode = nfs_fhget(sb, mntfh, fattr);
        if (IS_ERR(inode)) {
                dprintk("nfs_get_root: get root inode failed\n");
-               return ERR_CAST(inode);
+               ret = ERR_CAST(inode);
+               goto out;
        }
 
        error = nfs_superblock_set_dummy_root(sb, inode);
-       if (error != 0)
-               return ERR_PTR(error);
+       if (error != 0) {
+               ret = ERR_PTR(error);
+               goto out;
+       }
 
        /* 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
         */
-       mntroot = d_obtain_alias(inode);
-       if (IS_ERR(mntroot)) {
+       ret = d_obtain_alias(inode);
+       if (IS_ERR(ret)) {
                dprintk("nfs_get_root: get root dentry failed\n");
-               return mntroot;
+               goto out;
        }
 
-       security_d_instantiate(mntroot, inode);
+       security_d_instantiate(ret, inode);
 
-       if (!mntroot->d_op)
-               mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops;
+       if (ret->d_op == NULL)
+               ret->d_op = server->nfs_client->rpc_ops->dentry_ops;
 
+out:
+       nfs_free_fattr(fattr);
        dprintk("<-- nfs4_get_root()\n");
-       return mntroot;
+       return ret;
 }
 
 #endif /* CONFIG_NFS_V4 */