Blame view
fs/nfs/nfs4namespace.c
13.5 KB
b24413180 License cleanup: ... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
f7b422b17 NFS: Split fs/nfs... |
2 3 4 5 |
/* * linux/fs/nfs/nfs4namespace.c * * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com> |
54ceac451 NFS: Share NFS su... |
6 |
* - Modified by David Howells <dhowells@redhat.com> |
f7b422b17 NFS: Split fs/nfs... |
7 8 9 |
* * NFSv4 namespace */ |
f2aedb713 NFS: Add fs_conte... |
10 |
#include <linux/module.h> |
f7b422b17 NFS: Split fs/nfs... |
11 12 13 14 |
#include <linux/dcache.h> #include <linux/mount.h> #include <linux/namei.h> #include <linux/nfs_fs.h> |
47040da3c NFSv4: Allow secu... |
15 |
#include <linux/nfs_mount.h> |
5a0e3ad6a include cleanup: ... |
16 |
#include <linux/slab.h> |
f7b422b17 NFS: Split fs/nfs... |
17 18 |
#include <linux/string.h> #include <linux/sunrpc/clnt.h> |
5976687a2 sunrpc: move addr... |
19 |
#include <linux/sunrpc/addr.h> |
f7b422b17 NFS: Split fs/nfs... |
20 21 22 |
#include <linux/vfs.h> #include <linux/inet.h> #include "internal.h" |
c228fd3ae NFSv4: Cleanups f... |
23 |
#include "nfs4_fs.h" |
f2aedb713 NFS: Add fs_conte... |
24 |
#include "nfs.h" |
7d7ea8828 NFS: Use the DNS ... |
25 |
#include "dns_resolve.h" |
f7b422b17 NFS: Split fs/nfs... |
26 27 28 29 |
#define NFSDBG_FACILITY NFSDBG_VFS /* |
f2aedb713 NFS: Add fs_conte... |
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
* Work out the length that an NFSv4 path would render to as a standard posix * path, with a leading slash but no terminating slash. */ static ssize_t nfs4_pathname_len(const struct nfs4_pathname *pathname) { ssize_t len = 0; int i; for (i = 0; i < pathname->ncomponents; i++) { const struct nfs4_string *component = &pathname->components[i]; if (component->len > NAME_MAX) goto too_long; len += 1 + component->len; /* Adding "/foo" */ if (len > PATH_MAX) goto too_long; } return len; too_long: return -ENAMETOOLONG; } /* |
ef95d31e6 NFS: Fix misparsi... |
54 |
* Convert the NFSv4 pathname components into a standard posix path. |
f7b422b17 NFS: Split fs/nfs... |
55 |
*/ |
f2aedb713 NFS: Add fs_conte... |
56 57 |
static char *nfs4_pathname_string(const struct nfs4_pathname *pathname, unsigned short *_len) |
f7b422b17 NFS: Split fs/nfs... |
58 |
{ |
f2aedb713 NFS: Add fs_conte... |
59 60 61 62 63 64 65 66 67 68 69 70 |
ssize_t len; char *buf, *p; int i; len = nfs4_pathname_len(pathname); if (len < 0) return ERR_PTR(len); *_len = len; p = buf = kmalloc(len + 1, GFP_KERNEL); if (!buf) return ERR_PTR(-ENOMEM); |
f7b422b17 NFS: Split fs/nfs... |
71 |
|
f2aedb713 NFS: Add fs_conte... |
72 73 74 75 76 77 |
for (i = 0; i < pathname->ncomponents; i++) { const struct nfs4_string *component = &pathname->components[i]; *p++ = '/'; memcpy(p, component->data, component->len); p += component->len; |
f7b422b17 NFS: Split fs/nfs... |
78 |
} |
f2aedb713 NFS: Add fs_conte... |
79 80 81 |
*p = 0; return buf; |
f7b422b17 NFS: Split fs/nfs... |
82 |
} |
54ceac451 NFS: Share NFS su... |
83 |
/* |
1aba15676 nfs4: fix referra... |
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
* return the path component of "<server>:<path>" * nfspath - the "<server>:<path>" string * end - one past the last char that could contain "<server>:" * returns NULL on failure */ static char *nfs_path_component(const char *nfspath, const char *end) { char *p; if (*nfspath == '[') { /* parse [] escaped IPv6 addrs */ p = strchr(nfspath, ']'); if (p != NULL && ++p < end && *p == ':') return p + 1; } else { /* otherwise split on first colon */ p = strchr(nfspath, ':'); if (p != NULL && p < end) return p + 1; } return NULL; } /* |
54ceac451 NFS: Share NFS su... |
108 109 |
* Determine the mount path as a string */ |
b514f872f nfs: make nfs_pat... |
110 |
static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen) |
54ceac451 NFS: Share NFS su... |
111 |
{ |
b514f872f nfs: make nfs_pat... |
112 |
char *limit; |
97a548682 nfs: Show origina... |
113 114 |
char *path = nfs_path(&limit, dentry, buffer, buflen, NFS_PATH_CANONICAL); |
b514f872f nfs: make nfs_pat... |
115 |
if (!IS_ERR(path)) { |
1aba15676 nfs4: fix referra... |
116 117 118 |
char *path_component = nfs_path_component(path, limit); if (path_component) return path_component; |
b514f872f nfs: make nfs_pat... |
119 120 |
} return path; |
54ceac451 NFS: Share NFS su... |
121 122 123 124 125 126 |
} /* * Check that fs_locations::fs_root [RFC3530 6.3] is a prefix for what we * believe to be the server path to this dentry */ |
b514f872f nfs: make nfs_pat... |
127 |
static int nfs4_validate_fspath(struct dentry *dentry, |
54ceac451 NFS: Share NFS su... |
128 |
const struct nfs4_fs_locations *locations, |
f2aedb713 NFS: Add fs_conte... |
129 |
struct nfs_fs_context *ctx) |
54ceac451 NFS: Share NFS su... |
130 |
{ |
62a55d088 NFS: Additional r... |
131 132 |
const char *path; char *fs_path; |
f2aedb713 NFS: Add fs_conte... |
133 |
unsigned short len; |
62a55d088 NFS: Additional r... |
134 |
char *buf; |
f2aedb713 NFS: Add fs_conte... |
135 |
int n; |
54ceac451 NFS: Share NFS su... |
136 |
|
f2aedb713 NFS: Add fs_conte... |
137 |
buf = kmalloc(4096, GFP_KERNEL); |
e0b27d98b NFS: Add missing ... |
138 139 |
if (!buf) return -ENOMEM; |
f2aedb713 NFS: Add fs_conte... |
140 141 142 |
path = nfs4_path(dentry, buf, 4096); if (IS_ERR(path)) { kfree(buf); |
54ceac451 NFS: Share NFS su... |
143 |
return PTR_ERR(path); |
f2aedb713 NFS: Add fs_conte... |
144 |
} |
54ceac451 NFS: Share NFS su... |
145 |
|
f2aedb713 NFS: Add fs_conte... |
146 147 148 |
fs_path = nfs4_pathname_string(&locations->fs_path, &len); if (IS_ERR(fs_path)) { kfree(buf); |
54ceac451 NFS: Share NFS su... |
149 |
return PTR_ERR(fs_path); |
f2aedb713 NFS: Add fs_conte... |
150 |
} |
54ceac451 NFS: Share NFS su... |
151 |
|
f2aedb713 NFS: Add fs_conte... |
152 153 154 155 |
n = strncmp(path, fs_path, len); kfree(buf); kfree(fs_path); if (n != 0) { |
54ceac451 NFS: Share NFS su... |
156 157 |
dprintk("%s: path %s does not begin with fsroot %s ", |
f2aedb713 NFS: Add fs_conte... |
158 |
__func__, path, ctx->nfs_server.export_path); |
54ceac451 NFS: Share NFS su... |
159 160 161 162 163 |
return -ENOENT; } return 0; } |
7d7ea8828 NFS: Use the DNS ... |
164 |
static size_t nfs_parse_server_name(char *string, size_t len, |
292f503ca NFSv4: Use the co... |
165 |
struct sockaddr *sa, size_t salen, struct net *net) |
7d7ea8828 NFS: Use the DNS ... |
166 167 |
{ ssize_t ret; |
33faaa380 NFS: pass transpo... |
168 |
ret = rpc_pton(net, string, len, sa, salen); |
7d7ea8828 NFS: Use the DNS ... |
169 |
if (ret == 0) { |
33faaa380 NFS: pass transpo... |
170 |
ret = nfs_dns_resolve_name(net, string, len, sa, salen); |
7d7ea8828 NFS: Use the DNS ... |
171 172 173 174 175 |
if (ret < 0) ret = 0; } return ret; } |
9568c5e9a SUNRPC: Introduce... |
176 177 |
/** * nfs_find_best_sec - Find a security mechanism supported locally |
302fad7bd NFS: Fix up docum... |
178 |
* @clnt: pointer to rpc_clnt |
4d4b69dd8 NFS: add support ... |
179 |
* @server: NFS server struct |
9568c5e9a SUNRPC: Introduce... |
180 181 |
* @flavors: List of security tuples returned by SECINFO procedure * |
66b068604 NFSv4: test SECIN... |
182 183 |
* Return an rpc client that uses the first security mechanism in * "flavors" that is locally supported. The "flavors" array |
9568c5e9a SUNRPC: Introduce... |
184 |
* is searched in the order returned from the server, per RFC 3530 |
66b068604 NFSv4: test SECIN... |
185 186 |
* recommendation and each flavor is checked for membership in the * sec= mount option list if it exists. |
8445cd352 NFS Return -EPERM... |
187 188 |
* * Return -EPERM if no matching flavor is found in the array. |
66b068604 NFSv4: test SECIN... |
189 190 191 |
* * Please call rpc_shutdown_client() when you are done with this rpc client. * |
9568c5e9a SUNRPC: Introduce... |
192 |
*/ |
66b068604 NFSv4: test SECIN... |
193 194 |
static struct rpc_clnt *nfs_find_best_sec(struct rpc_clnt *clnt, struct nfs_server *server, |
4d4b69dd8 NFS: add support ... |
195 |
struct nfs4_secinfo_flavors *flavors) |
2671bfc3b NFS: Remove secin... |
196 |
{ |
66b068604 NFSv4: test SECIN... |
197 |
rpc_authflavor_t pflavor; |
9568c5e9a SUNRPC: Introduce... |
198 |
struct nfs4_secinfo4 *secinfo; |
fb15b26f8 SUNRPC: Define rp... |
199 |
unsigned int i; |
2671bfc3b NFS: Remove secin... |
200 201 |
for (i = 0; i < flavors->num_flavors; i++) { |
9568c5e9a SUNRPC: Introduce... |
202 203 204 205 206 207 |
secinfo = &flavors->flavors[i]; switch (secinfo->flavor) { case RPC_AUTH_NULL: case RPC_AUTH_UNIX: case RPC_AUTH_GSS: |
66b068604 NFSv4: test SECIN... |
208 |
pflavor = rpcauth_get_pseudoflavor(secinfo->flavor, |
9568c5e9a SUNRPC: Introduce... |
209 |
&secinfo->flavor_info); |
66b068604 NFSv4: test SECIN... |
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
/* does the pseudoflavor match a sec= mount opt? */ if (pflavor != RPC_AUTH_MAXFLAVOR && nfs_auth_info_match(&server->auth_info, pflavor)) { struct rpc_clnt *new; struct rpc_cred *cred; /* Cloning creates an rpc_auth for the flavor */ new = rpc_clone_client_set_auth(clnt, pflavor); if (IS_ERR(new)) continue; /** * Check that the user actually can use the * flavor. This is mostly for RPC_AUTH_GSS * where cr_init obtains a gss context */ cred = rpcauth_lookupcred(new->cl_auth, 0); if (IS_ERR(cred)) { rpc_shutdown_client(new); continue; } put_rpccred(cred); return new; } |
2671bfc3b NFS: Remove secin... |
233 234 |
} } |
66b068604 NFSv4: test SECIN... |
235 |
return ERR_PTR(-EPERM); |
2671bfc3b NFS: Remove secin... |
236 |
} |
66b068604 NFSv4: test SECIN... |
237 238 239 240 241 242 243 244 245 246 247 248 249 |
/** * nfs4_negotiate_security - in response to an NFS4ERR_WRONGSEC on lookup, * return an rpc_clnt that uses the best available security flavor with * respect to the secinfo flavor list and the sec= mount options. * * @clnt: RPC client to clone * @inode: directory inode * @name: lookup name * * Please call rpc_shutdown_client() when you are done with this rpc client. */ struct rpc_clnt * nfs4_negotiate_security(struct rpc_clnt *clnt, struct inode *inode, |
beffb8feb qstr: constify in... |
250 |
const struct qstr *name) |
72de53ec4 NFS: Do secinfo a... |
251 252 253 |
{ struct page *page; struct nfs4_secinfo_flavors *flavors; |
66b068604 NFSv4: test SECIN... |
254 |
struct rpc_clnt *new; |
72de53ec4 NFS: Do secinfo a... |
255 256 257 258 |
int err; page = alloc_page(GFP_KERNEL); if (!page) |
66b068604 NFSv4: test SECIN... |
259 |
return ERR_PTR(-ENOMEM); |
72de53ec4 NFS: Do secinfo a... |
260 261 262 263 |
flavors = page_address(page); err = nfs4_proc_secinfo(inode, name, flavors); if (err < 0) { |
66b068604 NFSv4: test SECIN... |
264 |
new = ERR_PTR(err); |
72de53ec4 NFS: Do secinfo a... |
265 266 |
goto out; } |
66b068604 NFSv4: test SECIN... |
267 |
new = nfs_find_best_sec(clnt, NFS_SERVER(inode), flavors); |
72de53ec4 NFS: Do secinfo a... |
268 269 270 |
out: put_page(page); |
66b068604 NFSv4: test SECIN... |
271 |
return new; |
72de53ec4 NFS: Do secinfo a... |
272 |
} |
f2aedb713 NFS: Add fs_conte... |
273 274 |
static int try_location(struct fs_context *fc, const struct nfs4_fs_location *location) |
4ada29d5c nfs: break up nfs... |
275 |
{ |
f2aedb713 NFS: Add fs_conte... |
276 277 278 279 280 281 282 283 284 285 |
struct nfs_fs_context *ctx = nfs_fc2context(fc); unsigned int len, s; char *export_path, *source, *p; int ret = -ENOENT; /* Allocate a buffer big enough to hold any of the hostnames plus a * terminating char and also a buffer big enough to hold the hostname * plus a colon plus the path. */ len = 0; |
460cdbc83 nfs: replace whil... |
286 |
for (s = 0; s < location->nservers; s++) { |
ea31a4437 nfs: Fix misparsi... |
287 |
const struct nfs4_string *buf = &location->servers[s]; |
f2aedb713 NFS: Add fs_conte... |
288 289 290 |
if (buf->len > len) len = buf->len; } |
4ada29d5c nfs: break up nfs... |
291 |
|
f2aedb713 NFS: Add fs_conte... |
292 293 294 295 296 297 298 299 300 |
kfree(ctx->nfs_server.hostname); ctx->nfs_server.hostname = kmalloc(len + 1, GFP_KERNEL); if (!ctx->nfs_server.hostname) return -ENOMEM; export_path = nfs4_pathname_string(&location->rootpath, &ctx->nfs_server.export_path_len); if (IS_ERR(export_path)) return PTR_ERR(export_path); |
4659ed7cc nfs: Fix memory l... |
301 |
kfree(ctx->nfs_server.export_path); |
f2aedb713 NFS: Add fs_conte... |
302 303 304 305 306 307 308 309 310 |
ctx->nfs_server.export_path = export_path; source = kmalloc(len + 1 + ctx->nfs_server.export_path_len + 1, GFP_KERNEL); if (!source) return -ENOMEM; kfree(fc->source); fc->source = source; |
f2aedb713 NFS: Add fs_conte... |
311 312 |
for (s = 0; s < location->nservers; s++) { const struct nfs4_string *buf = &location->servers[s]; |
4ada29d5c nfs: break up nfs... |
313 |
|
ea31a4437 nfs: Fix misparsi... |
314 315 |
if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len)) continue; |
517be09de NFSv4: Fix the re... |
316 |
|
62a55d088 NFS: Additional r... |
317 |
ctx->nfs_server.addrlen = |
f2aedb713 NFS: Add fs_conte... |
318 |
nfs_parse_server_name(buf->data, buf->len, |
62a55d088 NFS: Additional r... |
319 320 |
&ctx->nfs_server.address, sizeof(ctx->nfs_server._address), |
f2aedb713 NFS: Add fs_conte... |
321 |
fc->net_ns); |
62a55d088 NFS: Additional r... |
322 |
if (ctx->nfs_server.addrlen == 0) |
ea31a4437 nfs: Fix misparsi... |
323 |
continue; |
517be09de NFSv4: Fix the re... |
324 |
|
62a55d088 NFS: Additional r... |
325 |
rpc_set_port(&ctx->nfs_server.address, NFS_PORT); |
f2aedb713 NFS: Add fs_conte... |
326 327 328 |
memcpy(ctx->nfs_server.hostname, buf->data, buf->len); ctx->nfs_server.hostname[buf->len] = '\0'; |
4ada29d5c nfs: break up nfs... |
329 |
|
f2aedb713 NFS: Add fs_conte... |
330 331 332 333 334 335 336 |
p = source; memcpy(p, buf->data, buf->len); p += buf->len; *p++ = ':'; memcpy(p, ctx->nfs_server.export_path, ctx->nfs_server.export_path_len); p += ctx->nfs_server.export_path_len; *p = 0; |
4ada29d5c nfs: break up nfs... |
337 |
|
f2aedb713 NFS: Add fs_conte... |
338 339 340 |
ret = nfs4_get_referral_tree(fc); if (ret == 0) return 0; |
4ada29d5c nfs: break up nfs... |
341 |
} |
f2aedb713 NFS: Add fs_conte... |
342 343 |
return ret; |
4ada29d5c nfs: break up nfs... |
344 |
} |
f7b422b17 NFS: Split fs/nfs... |
345 346 |
/** * nfs_follow_referral - set up mountpoint when hitting a referral on moved error |
3cab1854b nfs: Fix up docum... |
347 |
* @fc: pointer to struct nfs_fs_context |
302fad7bd NFS: Fix up docum... |
348 |
* @locations: array of NFSv4 server location information |
f7b422b17 NFS: Split fs/nfs... |
349 350 |
* */ |
f2aedb713 NFS: Add fs_conte... |
351 352 |
static int nfs_follow_referral(struct fs_context *fc, const struct nfs4_fs_locations *locations) |
f7b422b17 NFS: Split fs/nfs... |
353 |
{ |
f2aedb713 NFS: Add fs_conte... |
354 |
struct nfs_fs_context *ctx = nfs_fc2context(fc); |
3f43c6667 NFS: Address a co... |
355 |
int loc, error; |
f7b422b17 NFS: Split fs/nfs... |
356 357 |
if (locations == NULL || locations->nlocations <= 0) |
f2aedb713 NFS: Add fs_conte... |
358 |
return -ENOENT; |
54ceac451 NFS: Share NFS su... |
359 |
|
f2aedb713 NFS: Add fs_conte... |
360 361 |
dprintk("%s: referral at %pd2 ", __func__, ctx->clone_data.dentry); |
f7b422b17 NFS: Split fs/nfs... |
362 |
|
54ceac451 NFS: Share NFS su... |
363 |
/* Ensure fs path is a prefix of current dentry path */ |
f2aedb713 NFS: Add fs_conte... |
364 365 366 |
error = nfs4_validate_fspath(ctx->clone_data.dentry, locations, ctx); if (error < 0) return error; |
f7b422b17 NFS: Split fs/nfs... |
367 |
|
f2aedb713 NFS: Add fs_conte... |
368 |
error = -ENOENT; |
460cdbc83 nfs: replace whil... |
369 |
for (loc = 0; loc < locations->nlocations; loc++) { |
509de8111 NFS: Add extra co... |
370 |
const struct nfs4_fs_location *location = &locations->locations[loc]; |
f7b422b17 NFS: Split fs/nfs... |
371 372 |
if (location == NULL || location->nservers <= 0 || |
460cdbc83 nfs: replace whil... |
373 |
location->rootpath.ncomponents == 0) |
f7b422b17 NFS: Split fs/nfs... |
374 |
continue; |
f7b422b17 NFS: Split fs/nfs... |
375 |
|
f2aedb713 NFS: Add fs_conte... |
376 377 378 |
error = try_location(fc, location); if (error == 0) return 0; |
f7b422b17 NFS: Split fs/nfs... |
379 |
} |
f2aedb713 NFS: Add fs_conte... |
380 |
return error; |
f7b422b17 NFS: Split fs/nfs... |
381 382 383 384 385 |
} /* * nfs_do_refmount - handle crossing a referral on server * @dentry - dentry of referral |
f7b422b17 NFS: Split fs/nfs... |
386 387 |
* */ |
f2aedb713 NFS: Add fs_conte... |
388 |
static int nfs_do_refmount(struct fs_context *fc, struct rpc_clnt *client) |
f7b422b17 NFS: Split fs/nfs... |
389 |
{ |
f2aedb713 NFS: Add fs_conte... |
390 391 |
struct nfs_fs_context *ctx = nfs_fc2context(fc); struct dentry *dentry, *parent; |
f7b422b17 NFS: Split fs/nfs... |
392 393 |
struct nfs4_fs_locations *fs_locations = NULL; struct page *page; |
f2aedb713 NFS: Add fs_conte... |
394 |
int err = -ENOMEM; |
f7b422b17 NFS: Split fs/nfs... |
395 396 |
/* BUG_ON(IS_ROOT(dentry)); */ |
f7b422b17 NFS: Split fs/nfs... |
397 |
page = alloc_page(GFP_KERNEL); |
f2aedb713 NFS: Add fs_conte... |
398 399 |
if (!page) return -ENOMEM; |
f7b422b17 NFS: Split fs/nfs... |
400 401 |
fs_locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL); |
f2aedb713 NFS: Add fs_conte... |
402 |
if (!fs_locations) |
f7b422b17 NFS: Split fs/nfs... |
403 404 405 |
goto out_free; /* Get locations */ |
f2aedb713 NFS: Add fs_conte... |
406 |
dentry = ctx->clone_data.dentry; |
f7b422b17 NFS: Split fs/nfs... |
407 |
parent = dget_parent(dentry); |
6de1472f1 nfs: use %p[dD] i... |
408 409 410 |
dprintk("%s: getting locations for %pd2 ", __func__, dentry); |
54ceac451 NFS: Share NFS su... |
411 |
|
2b0143b5c VFS: normal files... |
412 |
err = nfs4_proc_fs_locations(client, d_inode(parent), &dentry->d_name, fs_locations, page); |
f7b422b17 NFS: Split fs/nfs... |
413 |
dput(parent); |
f2aedb713 NFS: Add fs_conte... |
414 415 416 417 418 |
if (err != 0) goto out_free_2; err = -ENOENT; if (fs_locations->nlocations <= 0 || |
f7b422b17 NFS: Split fs/nfs... |
419 |
fs_locations->fs_path.ncomponents <= 0) |
f2aedb713 NFS: Add fs_conte... |
420 |
goto out_free_2; |
f7b422b17 NFS: Split fs/nfs... |
421 |
|
f2aedb713 NFS: Add fs_conte... |
422 423 424 |
err = nfs_follow_referral(fc, fs_locations); out_free_2: kfree(fs_locations); |
f7b422b17 NFS: Split fs/nfs... |
425 426 |
out_free: __free_page(page); |
f2aedb713 NFS: Add fs_conte... |
427 |
return err; |
f7b422b17 NFS: Split fs/nfs... |
428 |
} |
281cad46b NFS: Create a sub... |
429 |
|
f2aedb713 NFS: Add fs_conte... |
430 |
int nfs4_submount(struct fs_context *fc, struct nfs_server *server) |
281cad46b NFS: Create a sub... |
431 |
{ |
f2aedb713 NFS: Add fs_conte... |
432 433 |
struct nfs_fs_context *ctx = nfs_fc2context(fc); struct dentry *dentry = ctx->clone_data.dentry; |
281cad46b NFS: Create a sub... |
434 |
struct dentry *parent = dget_parent(dentry); |
2b0143b5c VFS: normal files... |
435 |
struct inode *dir = d_inode(parent); |
281cad46b NFS: Create a sub... |
436 |
struct rpc_clnt *client; |
f2aedb713 NFS: Add fs_conte... |
437 |
int ret; |
281cad46b NFS: Create a sub... |
438 439 |
/* Look it up again to get its attributes and sec flavor */ |
f7b37b8b1 NFS: Add softreva... |
440 |
client = nfs4_proc_lookup_mountpoint(dir, dentry, ctx->mntfh, |
f2aedb713 NFS: Add fs_conte... |
441 |
ctx->clone_data.fattr); |
281cad46b NFS: Create a sub... |
442 443 |
dput(parent); if (IS_ERR(client)) |
f2aedb713 NFS: Add fs_conte... |
444 |
return PTR_ERR(client); |
281cad46b NFS: Create a sub... |
445 |
|
f2aedb713 NFS: Add fs_conte... |
446 447 448 449 450 |
ctx->selected_flavor = client->cl_auth->au_flavor; if (ctx->clone_data.fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) { ret = nfs_do_refmount(fc, client); } else { ret = nfs_do_submount(fc); |
47040da3c NFSv4: Allow secu... |
451 |
} |
281cad46b NFS: Create a sub... |
452 453 |
rpc_shutdown_client(client); |
f2aedb713 NFS: Add fs_conte... |
454 |
return ret; |
281cad46b NFS: Create a sub... |
455 |
} |
800c06a5b NFS: Add function... |
456 457 458 459 460 461 462 463 464 465 466 |
/* * Try one location from the fs_locations array. * * Returns zero on success, or a negative errno value. */ static int nfs4_try_replacing_one_location(struct nfs_server *server, char *page, char *page2, const struct nfs4_fs_location *location) { const size_t addr_bufsize = sizeof(struct sockaddr_storage); |
292f503ca NFSv4: Use the co... |
467 |
struct net *net = rpc_net_ns(server->client); |
800c06a5b NFS: Add function... |
468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 |
struct sockaddr *sap; unsigned int s; size_t salen; int error; sap = kmalloc(addr_bufsize, GFP_KERNEL); if (sap == NULL) return -ENOMEM; error = -ENOENT; for (s = 0; s < location->nservers; s++) { const struct nfs4_string *buf = &location->servers[s]; char *hostname; if (buf->len <= 0 || buf->len > PAGE_SIZE) continue; if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len) != NULL) continue; salen = nfs_parse_server_name(buf->data, buf->len, |
292f503ca NFSv4: Use the co... |
489 |
sap, addr_bufsize, net); |
800c06a5b NFS: Add function... |
490 491 492 493 494 |
if (salen == 0) continue; rpc_set_port(sap, NFS_PORT); error = -ENOMEM; |
a8bd9ddf3 NFS: Replace vari... |
495 |
hostname = kmemdup_nul(buf->data, buf->len, GFP_KERNEL); |
800c06a5b NFS: Add function... |
496 497 |
if (hostname == NULL) break; |
292f503ca NFSv4: Use the co... |
498 |
error = nfs4_update_server(server, hostname, sap, salen, net); |
800c06a5b NFS: Add function... |
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 |
kfree(hostname); if (error == 0) break; } kfree(sap); return error; } /** * nfs4_replace_transport - set up transport to destination server * * @server: export being migrated * @locations: fs_locations array * * Returns zero on success, or a negative errno value. * * The client tries all the entries in the "locations" array, in the * order returned by the server, until one works or the end of the * array is reached. */ int nfs4_replace_transport(struct nfs_server *server, const struct nfs4_fs_locations *locations) { char *page = NULL, *page2 = NULL; int loc, error; error = -ENOENT; if (locations == NULL || locations->nlocations <= 0) goto out; error = -ENOMEM; page = (char *) __get_free_page(GFP_USER); if (!page) goto out; page2 = (char *) __get_free_page(GFP_USER); if (!page2) goto out; for (loc = 0; loc < locations->nlocations; loc++) { const struct nfs4_fs_location *location = &locations->locations[loc]; if (location == NULL || location->nservers <= 0 || location->rootpath.ncomponents == 0) continue; error = nfs4_try_replacing_one_location(server, page, page2, location); if (error == 0) break; } out: free_page((unsigned long)page); free_page((unsigned long)page2); return error; } |