Commit 738a35195941ecf604d3070e2a053e1df3de350b
Committed by
Trond Myklebust
1 parent
27ba851244
Exists in
master
and in
7 other branches
NFS: Secure the roots of the NFS subtrees in a shared superblock
Invoke security_d_instantiate() on root dentries after allocating them with dentry_alloc_anon(). Normally dentry_alloc_root() would do that, but we don't call that as we don't want to assign a name to the root dentry at this point (we may discover the real name later). Signed-Off-By: David Howells <dhowells@redhat.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Showing 1 changed file with 5 additions and 0 deletions Inline Diff
fs/nfs/getroot.c
1 | /* getroot.c: get the root dentry for an NFS mount | 1 | /* getroot.c: get the root dentry for an NFS mount |
2 | * | 2 | * |
3 | * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public License | 7 | * modify it under the terms of the GNU General Public License |
8 | * as published by the Free Software Foundation; either version | 8 | * as published by the Free Software Foundation; either version |
9 | * 2 of the License, or (at your option) any later version. | 9 | * 2 of the License, or (at your option) any later version. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/config.h> | 12 | #include <linux/config.h> |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | 15 | ||
16 | #include <linux/time.h> | 16 | #include <linux/time.h> |
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | #include <linux/mm.h> | 18 | #include <linux/mm.h> |
19 | #include <linux/string.h> | 19 | #include <linux/string.h> |
20 | #include <linux/stat.h> | 20 | #include <linux/stat.h> |
21 | #include <linux/errno.h> | 21 | #include <linux/errno.h> |
22 | #include <linux/unistd.h> | 22 | #include <linux/unistd.h> |
23 | #include <linux/sunrpc/clnt.h> | 23 | #include <linux/sunrpc/clnt.h> |
24 | #include <linux/sunrpc/stats.h> | 24 | #include <linux/sunrpc/stats.h> |
25 | #include <linux/nfs_fs.h> | 25 | #include <linux/nfs_fs.h> |
26 | #include <linux/nfs_mount.h> | 26 | #include <linux/nfs_mount.h> |
27 | #include <linux/nfs4_mount.h> | 27 | #include <linux/nfs4_mount.h> |
28 | #include <linux/lockd/bind.h> | 28 | #include <linux/lockd/bind.h> |
29 | #include <linux/smp_lock.h> | 29 | #include <linux/smp_lock.h> |
30 | #include <linux/seq_file.h> | 30 | #include <linux/seq_file.h> |
31 | #include <linux/mount.h> | 31 | #include <linux/mount.h> |
32 | #include <linux/nfs_idmap.h> | 32 | #include <linux/nfs_idmap.h> |
33 | #include <linux/vfs.h> | 33 | #include <linux/vfs.h> |
34 | #include <linux/namei.h> | 34 | #include <linux/namei.h> |
35 | #include <linux/namespace.h> | 35 | #include <linux/namespace.h> |
36 | #include <linux/security.h> | ||
36 | 37 | ||
37 | #include <asm/system.h> | 38 | #include <asm/system.h> |
38 | #include <asm/uaccess.h> | 39 | #include <asm/uaccess.h> |
39 | 40 | ||
40 | #include "nfs4_fs.h" | 41 | #include "nfs4_fs.h" |
41 | #include "delegation.h" | 42 | #include "delegation.h" |
42 | #include "internal.h" | 43 | #include "internal.h" |
43 | 44 | ||
44 | #define NFSDBG_FACILITY NFSDBG_CLIENT | 45 | #define NFSDBG_FACILITY NFSDBG_CLIENT |
45 | #define NFS_PARANOIA 1 | 46 | #define NFS_PARANOIA 1 |
46 | 47 | ||
47 | /* | 48 | /* |
48 | * get an NFS2/NFS3 root dentry from the root filehandle | 49 | * get an NFS2/NFS3 root dentry from the root filehandle |
49 | */ | 50 | */ |
50 | struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) | 51 | struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) |
51 | { | 52 | { |
52 | struct nfs_server *server = NFS_SB(sb); | 53 | struct nfs_server *server = NFS_SB(sb); |
53 | struct nfs_fsinfo fsinfo; | 54 | struct nfs_fsinfo fsinfo; |
54 | struct nfs_fattr fattr; | 55 | struct nfs_fattr fattr; |
55 | struct dentry *mntroot; | 56 | struct dentry *mntroot; |
56 | struct inode *inode; | 57 | struct inode *inode; |
57 | int error; | 58 | int error; |
58 | 59 | ||
59 | /* create a dummy root dentry with dummy inode for this superblock */ | 60 | /* create a dummy root dentry with dummy inode for this superblock */ |
60 | if (!sb->s_root) { | 61 | if (!sb->s_root) { |
61 | struct nfs_fh dummyfh; | 62 | struct nfs_fh dummyfh; |
62 | struct dentry *root; | 63 | struct dentry *root; |
63 | struct inode *iroot; | 64 | struct inode *iroot; |
64 | 65 | ||
65 | memset(&dummyfh, 0, sizeof(dummyfh)); | 66 | memset(&dummyfh, 0, sizeof(dummyfh)); |
66 | memset(&fattr, 0, sizeof(fattr)); | 67 | memset(&fattr, 0, sizeof(fattr)); |
67 | nfs_fattr_init(&fattr); | 68 | nfs_fattr_init(&fattr); |
68 | fattr.valid = NFS_ATTR_FATTR; | 69 | fattr.valid = NFS_ATTR_FATTR; |
69 | fattr.type = NFDIR; | 70 | fattr.type = NFDIR; |
70 | fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR; | 71 | fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR; |
71 | fattr.nlink = 2; | 72 | fattr.nlink = 2; |
72 | 73 | ||
73 | iroot = nfs_fhget(sb, &dummyfh, &fattr); | 74 | iroot = nfs_fhget(sb, &dummyfh, &fattr); |
74 | if (IS_ERR(iroot)) | 75 | if (IS_ERR(iroot)) |
75 | return ERR_PTR(PTR_ERR(iroot)); | 76 | return ERR_PTR(PTR_ERR(iroot)); |
76 | 77 | ||
77 | root = d_alloc_root(iroot); | 78 | root = d_alloc_root(iroot); |
78 | if (!root) { | 79 | if (!root) { |
79 | iput(iroot); | 80 | iput(iroot); |
80 | return ERR_PTR(-ENOMEM); | 81 | return ERR_PTR(-ENOMEM); |
81 | } | 82 | } |
82 | 83 | ||
83 | sb->s_root = root; | 84 | sb->s_root = root; |
84 | } | 85 | } |
85 | 86 | ||
86 | /* get the actual root for this mount */ | 87 | /* get the actual root for this mount */ |
87 | fsinfo.fattr = &fattr; | 88 | fsinfo.fattr = &fattr; |
88 | 89 | ||
89 | error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); | 90 | error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); |
90 | if (error < 0) { | 91 | if (error < 0) { |
91 | dprintk("nfs_get_root: getattr error = %d\n", -error); | 92 | dprintk("nfs_get_root: getattr error = %d\n", -error); |
92 | return ERR_PTR(error); | 93 | return ERR_PTR(error); |
93 | } | 94 | } |
94 | 95 | ||
95 | inode = nfs_fhget(sb, mntfh, fsinfo.fattr); | 96 | inode = nfs_fhget(sb, mntfh, fsinfo.fattr); |
96 | if (IS_ERR(inode)) { | 97 | if (IS_ERR(inode)) { |
97 | dprintk("nfs_get_root: get root inode failed\n"); | 98 | dprintk("nfs_get_root: get root inode failed\n"); |
98 | return ERR_PTR(PTR_ERR(inode)); | 99 | return ERR_PTR(PTR_ERR(inode)); |
99 | } | 100 | } |
100 | 101 | ||
101 | /* root dentries normally start off anonymous and get spliced in later | 102 | /* root dentries normally start off anonymous and get spliced in later |
102 | * if the dentry tree reaches them; however if the dentry already | 103 | * if the dentry tree reaches them; however if the dentry already |
103 | * exists, we'll pick it up at this point and use it as the root | 104 | * exists, we'll pick it up at this point and use it as the root |
104 | */ | 105 | */ |
105 | mntroot = d_alloc_anon(inode); | 106 | mntroot = d_alloc_anon(inode); |
106 | if (!mntroot) { | 107 | if (!mntroot) { |
107 | iput(inode); | 108 | iput(inode); |
108 | dprintk("nfs_get_root: get root dentry failed\n"); | 109 | dprintk("nfs_get_root: get root dentry failed\n"); |
109 | return ERR_PTR(-ENOMEM); | 110 | return ERR_PTR(-ENOMEM); |
110 | } | 111 | } |
111 | 112 | ||
113 | security_d_instantiate(mntroot, inode); | ||
114 | |||
112 | if (!mntroot->d_op) | 115 | if (!mntroot->d_op) |
113 | mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops; | 116 | mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops; |
114 | 117 | ||
115 | return mntroot; | 118 | return mntroot; |
116 | } | 119 | } |
117 | 120 | ||
118 | #ifdef CONFIG_NFS_V4 | 121 | #ifdef CONFIG_NFS_V4 |
119 | 122 | ||
120 | /* | 123 | /* |
121 | * Do a simple pathwalk from the root FH of the server to the nominated target | 124 | * Do a simple pathwalk from the root FH of the server to the nominated target |
122 | * of the mountpoint | 125 | * of the mountpoint |
123 | * - give error on symlinks | 126 | * - give error on symlinks |
124 | * - give error on ".." occurring in the path | 127 | * - give error on ".." occurring in the path |
125 | * - follow traversals | 128 | * - follow traversals |
126 | */ | 129 | */ |
127 | int nfs4_path_walk(struct nfs_server *server, | 130 | int nfs4_path_walk(struct nfs_server *server, |
128 | struct nfs_fh *mntfh, | 131 | struct nfs_fh *mntfh, |
129 | const char *path) | 132 | const char *path) |
130 | { | 133 | { |
131 | struct nfs_fsinfo fsinfo; | 134 | struct nfs_fsinfo fsinfo; |
132 | struct nfs_fattr fattr; | 135 | struct nfs_fattr fattr; |
133 | struct nfs_fh lastfh; | 136 | struct nfs_fh lastfh; |
134 | struct qstr name; | 137 | struct qstr name; |
135 | int ret; | 138 | int ret; |
136 | //int referral_count = 0; | 139 | //int referral_count = 0; |
137 | 140 | ||
138 | dprintk("--> nfs4_path_walk(,,%s)\n", path); | 141 | dprintk("--> nfs4_path_walk(,,%s)\n", path); |
139 | 142 | ||
140 | fsinfo.fattr = &fattr; | 143 | fsinfo.fattr = &fattr; |
141 | nfs_fattr_init(&fattr); | 144 | nfs_fattr_init(&fattr); |
142 | 145 | ||
143 | if (*path++ != '/') { | 146 | if (*path++ != '/') { |
144 | dprintk("nfs4_get_root: Path does not begin with a slash\n"); | 147 | dprintk("nfs4_get_root: Path does not begin with a slash\n"); |
145 | return -EINVAL; | 148 | return -EINVAL; |
146 | } | 149 | } |
147 | 150 | ||
148 | /* Start by getting the root filehandle from the server */ | 151 | /* Start by getting the root filehandle from the server */ |
149 | ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); | 152 | ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); |
150 | if (ret < 0) { | 153 | if (ret < 0) { |
151 | dprintk("nfs4_get_root: getroot error = %d\n", -ret); | 154 | dprintk("nfs4_get_root: getroot error = %d\n", -ret); |
152 | return ret; | 155 | return ret; |
153 | } | 156 | } |
154 | 157 | ||
155 | if (fattr.type != NFDIR) { | 158 | if (fattr.type != NFDIR) { |
156 | printk(KERN_ERR "nfs4_get_root:" | 159 | printk(KERN_ERR "nfs4_get_root:" |
157 | " getroot encountered non-directory\n"); | 160 | " getroot encountered non-directory\n"); |
158 | return -ENOTDIR; | 161 | return -ENOTDIR; |
159 | } | 162 | } |
160 | 163 | ||
161 | if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) { | 164 | if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) { |
162 | printk(KERN_ERR "nfs4_get_root:" | 165 | printk(KERN_ERR "nfs4_get_root:" |
163 | " getroot obtained referral\n"); | 166 | " getroot obtained referral\n"); |
164 | return -EREMOTE; | 167 | return -EREMOTE; |
165 | } | 168 | } |
166 | 169 | ||
167 | next_component: | 170 | next_component: |
168 | dprintk("Next: %s\n", path); | 171 | dprintk("Next: %s\n", path); |
169 | 172 | ||
170 | /* extract the next bit of the path */ | 173 | /* extract the next bit of the path */ |
171 | if (!*path) | 174 | if (!*path) |
172 | goto path_walk_complete; | 175 | goto path_walk_complete; |
173 | 176 | ||
174 | name.name = path; | 177 | name.name = path; |
175 | while (*path && *path != '/') | 178 | while (*path && *path != '/') |
176 | path++; | 179 | path++; |
177 | name.len = path - (const char *) name.name; | 180 | name.len = path - (const char *) name.name; |
178 | 181 | ||
179 | eat_dot_dir: | 182 | eat_dot_dir: |
180 | while (*path == '/') | 183 | while (*path == '/') |
181 | path++; | 184 | path++; |
182 | 185 | ||
183 | if (path[0] == '.' && (path[1] == '/' || !path[1])) { | 186 | if (path[0] == '.' && (path[1] == '/' || !path[1])) { |
184 | path += 2; | 187 | path += 2; |
185 | goto eat_dot_dir; | 188 | goto eat_dot_dir; |
186 | } | 189 | } |
187 | 190 | ||
188 | if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || !path[2]) | 191 | if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || !path[2]) |
189 | ) { | 192 | ) { |
190 | printk(KERN_ERR "nfs4_get_root:" | 193 | printk(KERN_ERR "nfs4_get_root:" |
191 | " Mount path contains reference to \"..\"\n"); | 194 | " Mount path contains reference to \"..\"\n"); |
192 | return -EINVAL; | 195 | return -EINVAL; |
193 | } | 196 | } |
194 | 197 | ||
195 | /* lookup the next FH in the sequence */ | 198 | /* lookup the next FH in the sequence */ |
196 | memcpy(&lastfh, mntfh, sizeof(lastfh)); | 199 | memcpy(&lastfh, mntfh, sizeof(lastfh)); |
197 | 200 | ||
198 | dprintk("LookupFH: %*.*s [%s]\n", name.len, name.len, name.name, path); | 201 | dprintk("LookupFH: %*.*s [%s]\n", name.len, name.len, name.name, path); |
199 | 202 | ||
200 | ret = server->nfs_client->rpc_ops->lookupfh(server, &lastfh, &name, | 203 | ret = server->nfs_client->rpc_ops->lookupfh(server, &lastfh, &name, |
201 | mntfh, &fattr); | 204 | mntfh, &fattr); |
202 | if (ret < 0) { | 205 | if (ret < 0) { |
203 | dprintk("nfs4_get_root: getroot error = %d\n", -ret); | 206 | dprintk("nfs4_get_root: getroot error = %d\n", -ret); |
204 | return ret; | 207 | return ret; |
205 | } | 208 | } |
206 | 209 | ||
207 | if (fattr.type != NFDIR) { | 210 | if (fattr.type != NFDIR) { |
208 | printk(KERN_ERR "nfs4_get_root:" | 211 | printk(KERN_ERR "nfs4_get_root:" |
209 | " lookupfh encountered non-directory\n"); | 212 | " lookupfh encountered non-directory\n"); |
210 | return -ENOTDIR; | 213 | return -ENOTDIR; |
211 | } | 214 | } |
212 | 215 | ||
213 | if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) { | 216 | if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) { |
214 | printk(KERN_ERR "nfs4_get_root:" | 217 | printk(KERN_ERR "nfs4_get_root:" |
215 | " lookupfh obtained referral\n"); | 218 | " lookupfh obtained referral\n"); |
216 | return -EREMOTE; | 219 | return -EREMOTE; |
217 | } | 220 | } |
218 | 221 | ||
219 | goto next_component; | 222 | goto next_component; |
220 | 223 | ||
221 | path_walk_complete: | 224 | path_walk_complete: |
222 | memcpy(&server->fsid, &fattr.fsid, sizeof(server->fsid)); | 225 | memcpy(&server->fsid, &fattr.fsid, sizeof(server->fsid)); |
223 | dprintk("<-- nfs4_path_walk() = 0\n"); | 226 | dprintk("<-- nfs4_path_walk() = 0\n"); |
224 | return 0; | 227 | return 0; |
225 | } | 228 | } |
226 | 229 | ||
227 | /* | 230 | /* |
228 | * get an NFS4 root dentry from the root filehandle | 231 | * get an NFS4 root dentry from the root filehandle |
229 | */ | 232 | */ |
230 | struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) | 233 | struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) |
231 | { | 234 | { |
232 | struct nfs_server *server = NFS_SB(sb); | 235 | struct nfs_server *server = NFS_SB(sb); |
233 | struct nfs_fattr fattr; | 236 | struct nfs_fattr fattr; |
234 | struct dentry *mntroot; | 237 | struct dentry *mntroot; |
235 | struct inode *inode; | 238 | struct inode *inode; |
236 | int error; | 239 | int error; |
237 | 240 | ||
238 | dprintk("--> nfs4_get_root()\n"); | 241 | dprintk("--> nfs4_get_root()\n"); |
239 | 242 | ||
240 | /* create a dummy root dentry with dummy inode for this superblock */ | 243 | /* create a dummy root dentry with dummy inode for this superblock */ |
241 | if (!sb->s_root) { | 244 | if (!sb->s_root) { |
242 | struct nfs_fh dummyfh; | 245 | struct nfs_fh dummyfh; |
243 | struct dentry *root; | 246 | struct dentry *root; |
244 | struct inode *iroot; | 247 | struct inode *iroot; |
245 | 248 | ||
246 | memset(&dummyfh, 0, sizeof(dummyfh)); | 249 | memset(&dummyfh, 0, sizeof(dummyfh)); |
247 | memset(&fattr, 0, sizeof(fattr)); | 250 | memset(&fattr, 0, sizeof(fattr)); |
248 | nfs_fattr_init(&fattr); | 251 | nfs_fattr_init(&fattr); |
249 | fattr.valid = NFS_ATTR_FATTR; | 252 | fattr.valid = NFS_ATTR_FATTR; |
250 | fattr.type = NFDIR; | 253 | fattr.type = NFDIR; |
251 | fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR; | 254 | fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR; |
252 | fattr.nlink = 2; | 255 | fattr.nlink = 2; |
253 | 256 | ||
254 | iroot = nfs_fhget(sb, &dummyfh, &fattr); | 257 | iroot = nfs_fhget(sb, &dummyfh, &fattr); |
255 | if (IS_ERR(iroot)) | 258 | if (IS_ERR(iroot)) |
256 | return ERR_PTR(PTR_ERR(iroot)); | 259 | return ERR_PTR(PTR_ERR(iroot)); |
257 | 260 | ||
258 | root = d_alloc_root(iroot); | 261 | root = d_alloc_root(iroot); |
259 | if (!root) { | 262 | if (!root) { |
260 | iput(iroot); | 263 | iput(iroot); |
261 | return ERR_PTR(-ENOMEM); | 264 | return ERR_PTR(-ENOMEM); |
262 | } | 265 | } |
263 | 266 | ||
264 | sb->s_root = root; | 267 | sb->s_root = root; |
265 | } | 268 | } |
266 | 269 | ||
267 | /* get the info about the server and filesystem */ | 270 | /* get the info about the server and filesystem */ |
268 | error = nfs4_server_capabilities(server, mntfh); | 271 | error = nfs4_server_capabilities(server, mntfh); |
269 | if (error < 0) { | 272 | if (error < 0) { |
270 | dprintk("nfs_get_root: getcaps error = %d\n", | 273 | dprintk("nfs_get_root: getcaps error = %d\n", |
271 | -error); | 274 | -error); |
272 | return ERR_PTR(error); | 275 | return ERR_PTR(error); |
273 | } | 276 | } |
274 | 277 | ||
275 | /* get the actual root for this mount */ | 278 | /* get the actual root for this mount */ |
276 | error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr); | 279 | error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr); |
277 | if (error < 0) { | 280 | if (error < 0) { |
278 | dprintk("nfs_get_root: getattr error = %d\n", -error); | 281 | dprintk("nfs_get_root: getattr error = %d\n", -error); |
279 | return ERR_PTR(error); | 282 | return ERR_PTR(error); |
280 | } | 283 | } |
281 | 284 | ||
282 | inode = nfs_fhget(sb, mntfh, &fattr); | 285 | inode = nfs_fhget(sb, mntfh, &fattr); |
283 | if (IS_ERR(inode)) { | 286 | if (IS_ERR(inode)) { |
284 | dprintk("nfs_get_root: get root inode failed\n"); | 287 | dprintk("nfs_get_root: get root inode failed\n"); |
285 | return ERR_PTR(PTR_ERR(inode)); | 288 | return ERR_PTR(PTR_ERR(inode)); |
286 | } | 289 | } |
287 | 290 | ||
288 | /* root dentries normally start off anonymous and get spliced in later | 291 | /* root dentries normally start off anonymous and get spliced in later |
289 | * if the dentry tree reaches them; however if the dentry already | 292 | * if the dentry tree reaches them; however if the dentry already |
290 | * exists, we'll pick it up at this point and use it as the root | 293 | * exists, we'll pick it up at this point and use it as the root |
291 | */ | 294 | */ |
292 | mntroot = d_alloc_anon(inode); | 295 | mntroot = d_alloc_anon(inode); |
293 | if (!mntroot) { | 296 | if (!mntroot) { |
294 | iput(inode); | 297 | iput(inode); |
295 | dprintk("nfs_get_root: get root dentry failed\n"); | 298 | dprintk("nfs_get_root: get root dentry failed\n"); |
296 | return ERR_PTR(-ENOMEM); | 299 | return ERR_PTR(-ENOMEM); |
297 | } | 300 | } |
301 | |||
302 | security_d_instantiate(mntroot, inode); | ||
298 | 303 | ||
299 | if (!mntroot->d_op) | 304 | if (!mntroot->d_op) |
300 | mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops; | 305 | mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops; |
301 | 306 | ||
302 | dprintk("<-- nfs4_get_root()\n"); | 307 | dprintk("<-- nfs4_get_root()\n"); |
303 | return mntroot; | 308 | return mntroot; |
304 | } | 309 | } |
305 | 310 | ||
306 | #endif /* CONFIG_NFS_V4 */ | 311 | #endif /* CONFIG_NFS_V4 */ |
307 | 312 |