| 1 | |
| 2 | |
| 3 | *
|
| 4 | * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
|
| 5 | * Written by David Howells ([email protected])
|
| 6 |
|
| 7 |
|
| 8 | #include <linux/module.h>
|
| 9 | #include <linux/init.h>
|
| 10 |
|
| 11 | #include <linux/time.h>
|
| 12 | #include <linux/kernel.h>
|
| 13 | #include <linux/mm.h>
|
| 14 | #include <linux/string.h>
|
| 15 | #include <linux/stat.h>
|
| 16 | #include <linux/errno.h>
|
| 17 | #include <linux/unistd.h>
|
| 18 | #include <linux/sunrpc/clnt.h>
|
| 19 | #include <linux/sunrpc/stats.h>
|
| 20 | #include <linux/nfs_fs.h>
|
| 21 | #include <linux/nfs_mount.h>
|
| 22 | #include <linux/lockd/bind.h>
|
| 23 | #include <linux/seq_file.h>
|
| 24 | #include <linux/mount.h>
|
| 25 | #include <linux/vfs.h>
|
| 26 | #include <linux/namei.h>
|
| 27 | #include <linux/security.h>
|
| 28 |
|
| 29 | #include <linux/uaccess.h>
|
| 30 |
|
| 31 | #include "internal.h"
|
| 32 |
|
| 33 | #define NFSDBG_FACILITY NFSDBG_CLIENT
|
| 34 |
|
| 35 | |
| 36 | * get a root dentry from the root filehandle
|
| 37 |
|
| 38 | int nfs_get_root(struct super_block *s, struct fs_context *fc)
|
| 39 | {
|
| 40 | struct nfs_fs_context *ctx = nfs_fc2context(fc);
|
| 41 | struct nfs_server *server = NFS_SB(s), *clone_server;
|
| 42 | struct nfs_fsinfo fsinfo;
|
| 43 | struct dentry *root;
|
| 44 | struct inode *inode;
|
| 45 | char *name;
|
| 46 | int error = -ENOMEM;
|
| 47 | unsigned long kflags = 0, kflags_out = 0;
|
| 48 |
|
| 49 | name = kstrdup(fc->source, GFP_KERNEL);
|
| 50 | if (!name)
|
| 51 | goto out;
|
| 52 |
|
| 53 |
|
| 54 | fsinfo.fattr = nfs_alloc_fattr_with_label(server);
|
| 55 | if (fsinfo.fattr == NULL)
|
| 56 | goto out_name;
|
| 57 |
|
| 58 | error = server->nfs_client->rpc_ops->getroot(server, ctx->mntfh, &fsinfo);
|
| 59 | if (error < 0) {
|
| 60 | dprintk("nfs_get_root: getattr error = %d\n", -error);
|
| 61 | nfs_errorf(fc, "NFS: Couldn't getattr on root");
|
| 62 | goto out_fattr;
|
| 63 | }
|
| 64 |
|
| 65 | inode = nfs_fhget(s, ctx->mntfh, fsinfo.fattr);
|
| 66 | if (IS_ERR(inode)) {
|
| 67 | dprintk("nfs_get_root: get root inode failed\n");
|
| 68 | error = PTR_ERR(inode);
|
| 69 | nfs_errorf(fc, "NFS: Couldn't get root inode");
|
| 70 | goto out_fattr;
|
| 71 | }
|
| 72 |
|
| 73 | |
| 74 | * if the dentry tree reaches them; however if the dentry already
|
| 75 | * exists, we'll pick it up at this point and use it as the root
|
| 76 |
|
| 77 | root = d_obtain_root(inode);
|
| 78 | if (IS_ERR(root)) {
|
| 79 | dprintk("nfs_get_root: get root dentry failed\n");
|
| 80 | error = PTR_ERR(root);
|
| 81 | nfs_errorf(fc, "NFS: Couldn't get root dentry");
|
| 82 | goto out_fattr;
|
| 83 | }
|
| 84 |
|
| 85 | security_d_instantiate(root, inode);
|
| 86 | spin_lock(&root->d_lock);
|
| 87 | if (IS_ROOT(root) && !root->d_fsdata &&
|
| 88 | !(root->d_flags & DCACHE_NFSFS_RENAMED)) {
|
| 89 | root->d_fsdata = name;
|
| 90 | name = NULL;
|
| 91 | }
|
| 92 | spin_unlock(&root->d_lock);
|
| 93 | if (!s->s_root)
|
| 94 | s->s_root = dget(root);
|
| 95 | fc->root = root;
|
| 96 | if (server->caps & NFS_CAP_SECURITY_LABEL)
|
| 97 | kflags |= SECURITY_LSM_NATIVE_LABELS;
|
| 98 | if (ctx->clone_data.sb) {
|
| 99 | if (d_inode(fc->root)->i_fop != &nfs_dir_operations) {
|
| 100 | error = -ESTALE;
|
| 101 | goto error_splat_root;
|
| 102 | }
|
| 103 |
|
| 104 | error = security_sb_clone_mnt_opts(ctx->clone_data.sb,
|
| 105 | s, kflags, &kflags_out);
|
| 106 | if (error)
|
| 107 | goto error_splat_root;
|
| 108 | clone_server = NFS_SB(ctx->clone_data.sb);
|
| 109 | server->has_sec_mnt_opts = clone_server->has_sec_mnt_opts;
|
| 110 | } else {
|
| 111 | error = security_sb_set_mnt_opts(s, fc->security,
|
| 112 | kflags, &kflags_out);
|
| 113 | }
|
| 114 | if (error)
|
| 115 | goto error_splat_root;
|
| 116 | if (server->caps & NFS_CAP_SECURITY_LABEL &&
|
| 117 | !(kflags_out & SECURITY_LSM_NATIVE_LABELS))
|
| 118 | server->caps &= ~NFS_CAP_SECURITY_LABEL;
|
| 119 |
|
| 120 | nfs_setsecurity(inode, fsinfo.fattr);
|
| 121 | error = 0;
|
| 122 |
|
| 123 | out_fattr:
|
| 124 | nfs_free_fattr(fsinfo.fattr);
|
| 125 | out_name:
|
| 126 | kfree(name);
|
| 127 | out:
|
| 128 | return error;
|
| 129 | error_splat_root:
|
| 130 | dput(fc->root);
|
| 131 | fc->root = NULL;
|
| 132 | goto out_fattr;
|
| 133 | }
|