Blame view

fs/nfs/getroot.c 4.43 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
54ceac451   David Howells   NFS: Share NFS su...
2
3
4
5
  /* getroot.c: get the root dentry for an NFS mount
   *
   * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells (dhowells@redhat.com)
54ceac451   David Howells   NFS: Share NFS su...
6
   */
54ceac451   David Howells   NFS: Share NFS su...
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  #include <linux/module.h>
  #include <linux/init.h>
  
  #include <linux/time.h>
  #include <linux/kernel.h>
  #include <linux/mm.h>
  #include <linux/string.h>
  #include <linux/stat.h>
  #include <linux/errno.h>
  #include <linux/unistd.h>
  #include <linux/sunrpc/clnt.h>
  #include <linux/sunrpc/stats.h>
  #include <linux/nfs_fs.h>
  #include <linux/nfs_mount.h>
54ceac451   David Howells   NFS: Share NFS su...
21
  #include <linux/lockd/bind.h>
54ceac451   David Howells   NFS: Share NFS su...
22
23
  #include <linux/seq_file.h>
  #include <linux/mount.h>
54ceac451   David Howells   NFS: Share NFS su...
24
25
  #include <linux/vfs.h>
  #include <linux/namei.h>
738a35195   David Howells   NFS: Secure the r...
26
  #include <linux/security.h>
54ceac451   David Howells   NFS: Share NFS su...
27

7c0f6ba68   Linus Torvalds   Replace <asm/uacc...
28
  #include <linux/uaccess.h>
54ceac451   David Howells   NFS: Share NFS su...
29

4e437e95a   Stanislav Kinsbursky   nfs: include inte...
30
  #include "internal.h"
54ceac451   David Howells   NFS: Share NFS su...
31
  #define NFSDBG_FACILITY		NFSDBG_CLIENT
54ceac451   David Howells   NFS: Share NFS su...
32
33
  
  /*
b09b9417d   Trond Myklebust   NFS: Fix the usta...
34
35
36
37
38
39
40
   * 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) {
48fde701a   Al Viro   switch open-coded...
41
42
  		sb->s_root = d_make_root(inode);
  		if (sb->s_root == NULL)
b09b9417d   Trond Myklebust   NFS: Fix the usta...
43
  			return -ENOMEM;
7de9c6ee3   Al Viro   new helper: ihold()
44
  		ihold(inode);
a10db50a4   Trond Myklebust   NFS: Fix an Oops ...
45
46
47
  		/*
  		 * Ensure that this dentry is invisible to d_find_alias().
  		 * Otherwise, it may be spliced into the tree by
41d28bca2   Al Viro   switch d_material...
48
  		 * d_splice_alias if a parent directory from the same
a10db50a4   Trond Myklebust   NFS: Fix an Oops ...
49
50
51
52
  		 * filesystem gets mounted at a later time.
  		 * This again causes shrink_dcache_for_umount_subtree() to
  		 * Oops, since the test for IS_ROOT() will fail.
  		 */
2b0143b5c   David Howells   VFS: normal files...
53
  		spin_lock(&d_inode(sb->s_root)->i_lock);
b23fb0a60   Nick Piggin   fs: scale inode a...
54
  		spin_lock(&sb->s_root->d_lock);
946e51f2b   Al Viro   move d_rcu from o...
55
  		hlist_del_init(&sb->s_root->d_u.d_alias);
b23fb0a60   Nick Piggin   fs: scale inode a...
56
  		spin_unlock(&sb->s_root->d_lock);
2b0143b5c   David Howells   VFS: normal files...
57
  		spin_unlock(&d_inode(sb->s_root)->i_lock);
b09b9417d   Trond Myklebust   NFS: Fix the usta...
58
59
60
61
62
  	}
  	return 0;
  }
  
  /*
54ceac451   David Howells   NFS: Share NFS su...
63
64
   * get an NFS2/NFS3 root dentry from the root filehandle
   */
62a55d088   Scott Mayhew   NFS: Additional r...
65
  int nfs_get_root(struct super_block *s, struct fs_context *fc)
54ceac451   David Howells   NFS: Share NFS su...
66
  {
62a55d088   Scott Mayhew   NFS: Additional r...
67
68
  	struct nfs_fs_context *ctx = nfs_fc2context(fc);
  	struct nfs_server *server = NFS_SB(s);
54ceac451   David Howells   NFS: Share NFS su...
69
  	struct nfs_fsinfo fsinfo;
62a55d088   Scott Mayhew   NFS: Additional r...
70
  	struct dentry *root;
54ceac451   David Howells   NFS: Share NFS su...
71
  	struct inode *inode;
62a55d088   Scott Mayhew   NFS: Additional r...
72
73
  	char *name;
  	int error = -ENOMEM;
779df6a54   Scott Mayhew   NFS: Ensure secur...
74
  	unsigned long kflags = 0, kflags_out = 0;
54ceac451   David Howells   NFS: Share NFS su...
75

62a55d088   Scott Mayhew   NFS: Additional r...
76
  	name = kstrdup(fc->source, GFP_KERNEL);
b1942c5f8   Al Viro   nfs: store devnam...
77
  	if (!name)
62a55d088   Scott Mayhew   NFS: Additional r...
78
  		goto out;
b1942c5f8   Al Viro   nfs: store devnam...
79

54ceac451   David Howells   NFS: Share NFS su...
80
  	/* get the actual root for this mount */
8bac9db9c   Trond Myklebust   NFSv4: Reduce sta...
81
  	fsinfo.fattr = nfs_alloc_fattr();
62a55d088   Scott Mayhew   NFS: Additional r...
82
83
  	if (fsinfo.fattr == NULL)
  		goto out_name;
54ceac451   David Howells   NFS: Share NFS su...
84

779df6a54   Scott Mayhew   NFS: Ensure secur...
85
86
87
  	fsinfo.fattr->label = nfs4_label_alloc(server, GFP_KERNEL);
  	if (IS_ERR(fsinfo.fattr->label))
  		goto out_fattr;
62a55d088   Scott Mayhew   NFS: Additional r...
88
  	error = server->nfs_client->rpc_ops->getroot(server, ctx->mntfh, &fsinfo);
54ceac451   David Howells   NFS: Share NFS su...
89
90
91
  	if (error < 0) {
  		dprintk("nfs_get_root: getattr error = %d
  ", -error);
ce8866f09   Scott Mayhew   NFS: Attach suppl...
92
  		nfs_errorf(fc, "NFS: Couldn't getattr on root");
779df6a54   Scott Mayhew   NFS: Ensure secur...
93
  		goto out_label;
54ceac451   David Howells   NFS: Share NFS su...
94
  	}
62a55d088   Scott Mayhew   NFS: Additional r...
95
  	inode = nfs_fhget(s, ctx->mntfh, fsinfo.fattr, NULL);
54ceac451   David Howells   NFS: Share NFS su...
96
97
98
  	if (IS_ERR(inode)) {
  		dprintk("nfs_get_root: get root inode failed
  ");
62a55d088   Scott Mayhew   NFS: Additional r...
99
  		error = PTR_ERR(inode);
ce8866f09   Scott Mayhew   NFS: Attach suppl...
100
  		nfs_errorf(fc, "NFS: Couldn't get root inode");
779df6a54   Scott Mayhew   NFS: Ensure secur...
101
  		goto out_label;
54ceac451   David Howells   NFS: Share NFS su...
102
  	}
62a55d088   Scott Mayhew   NFS: Additional r...
103
104
  	error = nfs_superblock_set_dummy_root(s, inode);
  	if (error != 0)
779df6a54   Scott Mayhew   NFS: Ensure secur...
105
  		goto out_label;
b09b9417d   Trond Myklebust   NFS: Fix the usta...
106

54ceac451   David Howells   NFS: Share NFS su...
107
108
109
110
  	/* 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
  	 */
62a55d088   Scott Mayhew   NFS: Additional r...
111
112
  	root = d_obtain_root(inode);
  	if (IS_ERR(root)) {
54ceac451   David Howells   NFS: Share NFS su...
113
114
  		dprintk("nfs_get_root: get root dentry failed
  ");
62a55d088   Scott Mayhew   NFS: Additional r...
115
  		error = PTR_ERR(root);
ce8866f09   Scott Mayhew   NFS: Attach suppl...
116
  		nfs_errorf(fc, "NFS: Couldn't get root dentry");
779df6a54   Scott Mayhew   NFS: Ensure secur...
117
  		goto out_label;
54ceac451   David Howells   NFS: Share NFS su...
118
  	}
62a55d088   Scott Mayhew   NFS: Additional r...
119
120
121
122
123
  	security_d_instantiate(root, inode);
  	spin_lock(&root->d_lock);
  	if (IS_ROOT(root) && !root->d_fsdata &&
  	    !(root->d_flags & DCACHE_NFSFS_RENAMED)) {
  		root->d_fsdata = name;
b1942c5f8   Al Viro   nfs: store devnam...
124
125
  		name = NULL;
  	}
62a55d088   Scott Mayhew   NFS: Additional r...
126
127
  	spin_unlock(&root->d_lock);
  	fc->root = root;
779df6a54   Scott Mayhew   NFS: Ensure secur...
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
  	if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL)
  		kflags |= SECURITY_LSM_NATIVE_LABELS;
  	if (ctx->clone_data.sb) {
  		if (d_inode(fc->root)->i_fop != &nfs_dir_operations) {
  			error = -ESTALE;
  			goto error_splat_root;
  		}
  		/* clone lsm security options from the parent to the new sb */
  		error = security_sb_clone_mnt_opts(ctx->clone_data.sb,
  						   s, kflags, &kflags_out);
  	} else {
  		error = security_sb_set_mnt_opts(s, fc->security,
  							kflags, &kflags_out);
  	}
  	if (error)
  		goto error_splat_root;
  	if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL &&
  		!(kflags_out & SECURITY_LSM_NATIVE_LABELS))
  		NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL;
  
  	nfs_setsecurity(inode, fsinfo.fattr, fsinfo.fattr->label);
62a55d088   Scott Mayhew   NFS: Additional r...
149
  	error = 0;
779df6a54   Scott Mayhew   NFS: Ensure secur...
150
151
  out_label:
  	nfs4_label_free(fsinfo.fattr->label);
62a55d088   Scott Mayhew   NFS: Additional r...
152
  out_fattr:
8bac9db9c   Trond Myklebust   NFSv4: Reduce sta...
153
  	nfs_free_fattr(fsinfo.fattr);
62a55d088   Scott Mayhew   NFS: Additional r...
154
155
156
157
  out_name:
  	kfree(name);
  out:
  	return error;
779df6a54   Scott Mayhew   NFS: Ensure secur...
158
159
160
161
  error_splat_root:
  	dput(fc->root);
  	fc->root = NULL;
  	goto out_label;
54ceac451   David Howells   NFS: Share NFS su...
162
  }