Blame view
fs/nfs/nfs4namespace.c
12.8 KB
f7b422b17 NFS: Split fs/nfs... |
1 2 3 4 |
/* * linux/fs/nfs/nfs4namespace.c * * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com> |
54ceac451 NFS: Share NFS su... |
5 |
* - Modified by David Howells <dhowells@redhat.com> |
f7b422b17 NFS: Split fs/nfs... |
6 7 8 |
* * NFSv4 namespace */ |
f7b422b17 NFS: Split fs/nfs... |
9 10 11 12 |
#include <linux/dcache.h> #include <linux/mount.h> #include <linux/namei.h> #include <linux/nfs_fs.h> |
47040da3c NFSv4: Allow secu... |
13 |
#include <linux/nfs_mount.h> |
5a0e3ad6a include cleanup: ... |
14 |
#include <linux/slab.h> |
f7b422b17 NFS: Split fs/nfs... |
15 16 |
#include <linux/string.h> #include <linux/sunrpc/clnt.h> |
5976687a2 sunrpc: move addr... |
17 |
#include <linux/sunrpc/addr.h> |
f7b422b17 NFS: Split fs/nfs... |
18 19 20 |
#include <linux/vfs.h> #include <linux/inet.h> #include "internal.h" |
c228fd3ae NFSv4: Cleanups f... |
21 |
#include "nfs4_fs.h" |
7d7ea8828 NFS: Use the DNS ... |
22 |
#include "dns_resolve.h" |
f7b422b17 NFS: Split fs/nfs... |
23 24 25 26 |
#define NFSDBG_FACILITY NFSDBG_VFS /* |
ef95d31e6 NFS: Fix misparsi... |
27 28 29 |
* Convert the NFSv4 pathname components into a standard posix path. * * Note that the resulting string will be placed at the end of the buffer |
f7b422b17 NFS: Split fs/nfs... |
30 |
*/ |
509de8111 NFS: Add extra co... |
31 |
static inline char *nfs4_pathname_string(const struct nfs4_pathname *pathname, |
f7b422b17 NFS: Split fs/nfs... |
32 33 34 35 36 37 38 39 40 41 |
char *buffer, ssize_t buflen) { char *end = buffer + buflen; int n; *--end = '\0'; buflen--; n = pathname->ncomponents; while (--n >= 0) { |
509de8111 NFS: Add extra co... |
42 |
const struct nfs4_string *component = &pathname->components[n]; |
f7b422b17 NFS: Split fs/nfs... |
43 44 45 46 47 48 49 50 51 52 53 |
buflen -= component->len + 1; if (buflen < 0) goto Elong; end -= component->len; memcpy(end, component->data, component->len); *--end = '/'; } return end; Elong: return ERR_PTR(-ENAMETOOLONG); } |
54ceac451 NFS: Share NFS su... |
54 |
/* |
1aba15676 nfs4: fix referra... |
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
* 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... |
79 80 |
* Determine the mount path as a string */ |
b514f872f nfs: make nfs_pat... |
81 |
static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen) |
54ceac451 NFS: Share NFS su... |
82 |
{ |
b514f872f nfs: make nfs_pat... |
83 |
char *limit; |
97a548682 nfs: Show origina... |
84 85 |
char *path = nfs_path(&limit, dentry, buffer, buflen, NFS_PATH_CANONICAL); |
b514f872f nfs: make nfs_pat... |
86 |
if (!IS_ERR(path)) { |
1aba15676 nfs4: fix referra... |
87 88 89 |
char *path_component = nfs_path_component(path, limit); if (path_component) return path_component; |
b514f872f nfs: make nfs_pat... |
90 91 |
} return path; |
54ceac451 NFS: Share NFS su... |
92 93 94 95 96 97 |
} /* * 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... |
98 |
static int nfs4_validate_fspath(struct dentry *dentry, |
54ceac451 NFS: Share NFS su... |
99 100 101 102 |
const struct nfs4_fs_locations *locations, char *page, char *page2) { const char *path, *fs_path; |
b514f872f nfs: make nfs_pat... |
103 |
path = nfs4_path(dentry, page, PAGE_SIZE); |
54ceac451 NFS: Share NFS su... |
104 105 106 107 108 109 110 111 112 113 |
if (IS_ERR(path)) return PTR_ERR(path); fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE); if (IS_ERR(fs_path)) return PTR_ERR(fs_path); if (strncmp(path, fs_path, strlen(fs_path)) != 0) { dprintk("%s: path %s does not begin with fsroot %s ", |
3110ff804 nfs: replace rema... |
114 |
__func__, path, fs_path); |
54ceac451 NFS: Share NFS su... |
115 116 117 118 119 |
return -ENOENT; } return 0; } |
7d7ea8828 NFS: Use the DNS ... |
120 |
static size_t nfs_parse_server_name(char *string, size_t len, |
292f503ca NFSv4: Use the co... |
121 |
struct sockaddr *sa, size_t salen, struct net *net) |
7d7ea8828 NFS: Use the DNS ... |
122 123 |
{ ssize_t ret; |
33faaa380 NFS: pass transpo... |
124 |
ret = rpc_pton(net, string, len, sa, salen); |
7d7ea8828 NFS: Use the DNS ... |
125 |
if (ret == 0) { |
33faaa380 NFS: pass transpo... |
126 |
ret = nfs_dns_resolve_name(net, string, len, sa, salen); |
7d7ea8828 NFS: Use the DNS ... |
127 128 129 130 131 |
if (ret < 0) ret = 0; } return ret; } |
9568c5e9a SUNRPC: Introduce... |
132 133 |
/** * nfs_find_best_sec - Find a security mechanism supported locally |
4d4b69dd8 NFS: add support ... |
134 |
* @server: NFS server struct |
9568c5e9a SUNRPC: Introduce... |
135 136 |
* @flavors: List of security tuples returned by SECINFO procedure * |
66b068604 NFSv4: test SECIN... |
137 138 |
* Return an rpc client that uses the first security mechanism in * "flavors" that is locally supported. The "flavors" array |
9568c5e9a SUNRPC: Introduce... |
139 |
* is searched in the order returned from the server, per RFC 3530 |
66b068604 NFSv4: test SECIN... |
140 141 |
* recommendation and each flavor is checked for membership in the * sec= mount option list if it exists. |
8445cd352 NFS Return -EPERM... |
142 143 |
* * Return -EPERM if no matching flavor is found in the array. |
66b068604 NFSv4: test SECIN... |
144 145 146 |
* * Please call rpc_shutdown_client() when you are done with this rpc client. * |
9568c5e9a SUNRPC: Introduce... |
147 |
*/ |
66b068604 NFSv4: test SECIN... |
148 149 |
static struct rpc_clnt *nfs_find_best_sec(struct rpc_clnt *clnt, struct nfs_server *server, |
4d4b69dd8 NFS: add support ... |
150 |
struct nfs4_secinfo_flavors *flavors) |
2671bfc3b NFS: Remove secin... |
151 |
{ |
66b068604 NFSv4: test SECIN... |
152 |
rpc_authflavor_t pflavor; |
9568c5e9a SUNRPC: Introduce... |
153 |
struct nfs4_secinfo4 *secinfo; |
fb15b26f8 SUNRPC: Define rp... |
154 |
unsigned int i; |
2671bfc3b NFS: Remove secin... |
155 156 |
for (i = 0; i < flavors->num_flavors; i++) { |
9568c5e9a SUNRPC: Introduce... |
157 158 159 160 161 162 |
secinfo = &flavors->flavors[i]; switch (secinfo->flavor) { case RPC_AUTH_NULL: case RPC_AUTH_UNIX: case RPC_AUTH_GSS: |
66b068604 NFSv4: test SECIN... |
163 |
pflavor = rpcauth_get_pseudoflavor(secinfo->flavor, |
9568c5e9a SUNRPC: Introduce... |
164 |
&secinfo->flavor_info); |
66b068604 NFSv4: test SECIN... |
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
/* 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... |
188 189 |
} } |
66b068604 NFSv4: test SECIN... |
190 |
return ERR_PTR(-EPERM); |
2671bfc3b NFS: Remove secin... |
191 |
} |
66b068604 NFSv4: test SECIN... |
192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
/** * 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, struct qstr *name) |
72de53ec4 NFS: Do secinfo a... |
206 207 208 |
{ struct page *page; struct nfs4_secinfo_flavors *flavors; |
66b068604 NFSv4: test SECIN... |
209 |
struct rpc_clnt *new; |
72de53ec4 NFS: Do secinfo a... |
210 211 212 213 |
int err; page = alloc_page(GFP_KERNEL); if (!page) |
66b068604 NFSv4: test SECIN... |
214 |
return ERR_PTR(-ENOMEM); |
72de53ec4 NFS: Do secinfo a... |
215 216 217 218 |
flavors = page_address(page); err = nfs4_proc_secinfo(inode, name, flavors); if (err < 0) { |
66b068604 NFSv4: test SECIN... |
219 |
new = ERR_PTR(err); |
72de53ec4 NFS: Do secinfo a... |
220 221 |
goto out; } |
66b068604 NFSv4: test SECIN... |
222 |
new = nfs_find_best_sec(clnt, NFS_SERVER(inode), flavors); |
72de53ec4 NFS: Do secinfo a... |
223 224 225 |
out: put_page(page); |
66b068604 NFSv4: test SECIN... |
226 |
return new; |
72de53ec4 NFS: Do secinfo a... |
227 |
} |
4ada29d5c nfs: break up nfs... |
228 229 230 231 |
static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, char *page, char *page2, const struct nfs4_fs_location *location) { |
364d015e5 NFSv4: Reduce the... |
232 |
const size_t addr_bufsize = sizeof(struct sockaddr_storage); |
292f503ca NFSv4: Use the co... |
233 |
struct net *net = rpc_net_ns(NFS_SB(mountdata->sb)->client); |
4ada29d5c nfs: break up nfs... |
234 235 |
struct vfsmount *mnt = ERR_PTR(-ENOENT); char *mnt_path; |
ef95d31e6 NFS: Fix misparsi... |
236 |
unsigned int maxbuflen; |
460cdbc83 nfs: replace whil... |
237 |
unsigned int s; |
4ada29d5c nfs: break up nfs... |
238 239 240 |
mnt_path = nfs4_pathname_string(&location->rootpath, page2, PAGE_SIZE); if (IS_ERR(mnt_path)) |
517be09de NFSv4: Fix the re... |
241 |
return ERR_CAST(mnt_path); |
4ada29d5c nfs: break up nfs... |
242 |
mountdata->mnt_path = mnt_path; |
ef95d31e6 NFS: Fix misparsi... |
243 |
maxbuflen = mnt_path - 1 - page2; |
4ada29d5c nfs: break up nfs... |
244 |
|
364d015e5 NFSv4: Reduce the... |
245 246 247 |
mountdata->addr = kmalloc(addr_bufsize, GFP_KERNEL); if (mountdata->addr == NULL) return ERR_PTR(-ENOMEM); |
460cdbc83 nfs: replace whil... |
248 |
for (s = 0; s < location->nservers; s++) { |
ea31a4437 nfs: Fix misparsi... |
249 |
const struct nfs4_string *buf = &location->servers[s]; |
4ada29d5c nfs: break up nfs... |
250 |
|
ef95d31e6 NFS: Fix misparsi... |
251 |
if (buf->len <= 0 || buf->len >= maxbuflen) |
4ada29d5c nfs: break up nfs... |
252 |
continue; |
4ada29d5c nfs: break up nfs... |
253 |
|
ea31a4437 nfs: Fix misparsi... |
254 255 |
if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len)) continue; |
517be09de NFSv4: Fix the re... |
256 257 |
mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len, |
292f503ca NFSv4: Use the co... |
258 |
mountdata->addr, addr_bufsize, net); |
53a0b9c4c NFS: Replace nfs_... |
259 |
if (mountdata->addrlen == 0) |
ea31a4437 nfs: Fix misparsi... |
260 |
continue; |
517be09de NFSv4: Fix the re... |
261 |
|
ec6ee6125 NFS: Replace nfs_... |
262 |
rpc_set_port(mountdata->addr, NFS_PORT); |
ea31a4437 nfs: Fix misparsi... |
263 |
|
ef95d31e6 NFS: Fix misparsi... |
264 265 |
memcpy(page2, buf->data, buf->len); page2[buf->len] = '\0'; |
ea31a4437 nfs: Fix misparsi... |
266 |
mountdata->hostname = page2; |
4ada29d5c nfs: break up nfs... |
267 268 269 270 271 272 273 274 |
snprintf(page, PAGE_SIZE, "%s:%s", mountdata->hostname, mountdata->mnt_path); mnt = vfs_kern_mount(&nfs4_referral_fs_type, 0, page, mountdata); if (!IS_ERR(mnt)) break; |
4ada29d5c nfs: break up nfs... |
275 |
} |
364d015e5 NFSv4: Reduce the... |
276 |
kfree(mountdata->addr); |
4ada29d5c nfs: break up nfs... |
277 278 |
return mnt; } |
f7b422b17 NFS: Split fs/nfs... |
279 280 |
/** * nfs_follow_referral - set up mountpoint when hitting a referral on moved error |
f7b422b17 NFS: Split fs/nfs... |
281 |
* @dentry - parent directory |
3f43c6667 NFS: Address a co... |
282 |
* @locations - array of NFSv4 server location information |
f7b422b17 NFS: Split fs/nfs... |
283 284 |
* */ |
f8ad9c4ba nfs: nfs_do_{ref,... |
285 |
static struct vfsmount *nfs_follow_referral(struct dentry *dentry, |
509de8111 NFS: Add extra co... |
286 |
const struct nfs4_fs_locations *locations) |
f7b422b17 NFS: Split fs/nfs... |
287 288 289 |
{ struct vfsmount *mnt = ERR_PTR(-ENOENT); struct nfs_clone_mount mountdata = { |
f8ad9c4ba nfs: nfs_do_{ref,... |
290 |
.sb = dentry->d_sb, |
f7b422b17 NFS: Split fs/nfs... |
291 |
.dentry = dentry, |
f8ad9c4ba nfs: nfs_do_{ref,... |
292 |
.authflavor = NFS_SB(dentry->d_sb)->client->cl_auth->au_flavor, |
f7b422b17 NFS: Split fs/nfs... |
293 |
}; |
54ceac451 NFS: Share NFS su... |
294 |
char *page = NULL, *page2 = NULL; |
3f43c6667 NFS: Address a co... |
295 |
int loc, error; |
f7b422b17 NFS: Split fs/nfs... |
296 297 298 |
if (locations == NULL || locations->nlocations <= 0) goto out; |
6de1472f1 nfs: use %p[dD] i... |
299 300 |
dprintk("%s: referral at %pd2 ", __func__, dentry); |
f7b422b17 NFS: Split fs/nfs... |
301 |
|
f7b422b17 NFS: Split fs/nfs... |
302 |
page = (char *) __get_free_page(GFP_USER); |
54ceac451 NFS: Share NFS su... |
303 |
if (!page) |
f7b422b17 NFS: Split fs/nfs... |
304 |
goto out; |
54ceac451 NFS: Share NFS su... |
305 |
|
f7b422b17 NFS: Split fs/nfs... |
306 |
page2 = (char *) __get_free_page(GFP_USER); |
54ceac451 NFS: Share NFS su... |
307 |
if (!page2) |
f7b422b17 NFS: Split fs/nfs... |
308 |
goto out; |
54ceac451 NFS: Share NFS su... |
309 |
/* Ensure fs path is a prefix of current dentry path */ |
b514f872f nfs: make nfs_pat... |
310 |
error = nfs4_validate_fspath(dentry, locations, page, page2); |
54ceac451 NFS: Share NFS su... |
311 312 313 |
if (error < 0) { mnt = ERR_PTR(error); goto out; |
f7b422b17 NFS: Split fs/nfs... |
314 |
} |
460cdbc83 nfs: replace whil... |
315 |
for (loc = 0; loc < locations->nlocations; loc++) { |
509de8111 NFS: Add extra co... |
316 |
const struct nfs4_fs_location *location = &locations->locations[loc]; |
f7b422b17 NFS: Split fs/nfs... |
317 318 |
if (location == NULL || location->nservers <= 0 || |
460cdbc83 nfs: replace whil... |
319 |
location->rootpath.ncomponents == 0) |
f7b422b17 NFS: Split fs/nfs... |
320 |
continue; |
f7b422b17 NFS: Split fs/nfs... |
321 |
|
4ada29d5c nfs: break up nfs... |
322 323 324 |
mnt = try_location(&mountdata, page, page2, location); if (!IS_ERR(mnt)) break; |
f7b422b17 NFS: Split fs/nfs... |
325 |
} |
f7b422b17 NFS: Split fs/nfs... |
326 |
out: |
54ceac451 NFS: Share NFS su... |
327 328 |
free_page((unsigned long) page); free_page((unsigned long) page2); |
3110ff804 nfs: replace rema... |
329 330 |
dprintk("%s: done ", __func__); |
f7b422b17 NFS: Split fs/nfs... |
331 332 333 334 335 336 |
return mnt; } /* * nfs_do_refmount - handle crossing a referral on server * @dentry - dentry of referral |
f7b422b17 NFS: Split fs/nfs... |
337 338 |
* */ |
281cad46b NFS: Create a sub... |
339 |
static struct vfsmount *nfs_do_refmount(struct rpc_clnt *client, struct dentry *dentry) |
f7b422b17 NFS: Split fs/nfs... |
340 |
{ |
54ceac451 NFS: Share NFS su... |
341 |
struct vfsmount *mnt = ERR_PTR(-ENOMEM); |
f7b422b17 NFS: Split fs/nfs... |
342 343 344 345 346 347 |
struct dentry *parent; struct nfs4_fs_locations *fs_locations = NULL; struct page *page; int err; /* BUG_ON(IS_ROOT(dentry)); */ |
3110ff804 nfs: replace rema... |
348 349 |
dprintk("%s: enter ", __func__); |
f7b422b17 NFS: Split fs/nfs... |
350 351 352 353 354 355 356 357 358 359 |
page = alloc_page(GFP_KERNEL); if (page == NULL) goto out; fs_locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL); if (fs_locations == NULL) goto out_free; /* Get locations */ |
54ceac451 NFS: Share NFS su... |
360 |
mnt = ERR_PTR(-ENOENT); |
f7b422b17 NFS: Split fs/nfs... |
361 |
parent = dget_parent(dentry); |
6de1472f1 nfs: use %p[dD] i... |
362 363 364 |
dprintk("%s: getting locations for %pd2 ", __func__, dentry); |
54ceac451 NFS: Share NFS su... |
365 |
|
2b0143b5c VFS: normal files... |
366 |
err = nfs4_proc_fs_locations(client, d_inode(parent), &dentry->d_name, fs_locations, page); |
f7b422b17 NFS: Split fs/nfs... |
367 |
dput(parent); |
54ceac451 NFS: Share NFS su... |
368 369 |
if (err != 0 || fs_locations->nlocations <= 0 || |
f7b422b17 NFS: Split fs/nfs... |
370 371 |
fs_locations->fs_path.ncomponents <= 0) goto out_free; |
f8ad9c4ba nfs: nfs_do_{ref,... |
372 |
mnt = nfs_follow_referral(dentry, fs_locations); |
f7b422b17 NFS: Split fs/nfs... |
373 374 375 376 |
out_free: __free_page(page); kfree(fs_locations); out: |
3110ff804 nfs: replace rema... |
377 378 |
dprintk("%s: done ", __func__); |
f7b422b17 NFS: Split fs/nfs... |
379 380 |
return mnt; } |
281cad46b NFS: Create a sub... |
381 382 383 384 |
struct vfsmount *nfs4_submount(struct nfs_server *server, struct dentry *dentry, struct nfs_fh *fh, struct nfs_fattr *fattr) { |
47040da3c NFSv4: Allow secu... |
385 |
rpc_authflavor_t flavor = server->client->cl_auth->au_flavor; |
281cad46b NFS: Create a sub... |
386 |
struct dentry *parent = dget_parent(dentry); |
2b0143b5c VFS: normal files... |
387 |
struct inode *dir = d_inode(parent); |
47040da3c NFSv4: Allow secu... |
388 |
struct qstr *name = &dentry->d_name; |
281cad46b NFS: Create a sub... |
389 390 391 392 |
struct rpc_clnt *client; struct vfsmount *mnt; /* Look it up again to get its attributes and sec flavor */ |
47040da3c NFSv4: Allow secu... |
393 |
client = nfs4_proc_lookup_mountpoint(dir, name, fh, fattr); |
281cad46b NFS: Create a sub... |
394 395 396 |
dput(parent); if (IS_ERR(client)) return ERR_CAST(client); |
47040da3c NFSv4: Allow secu... |
397 |
if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) { |
281cad46b NFS: Create a sub... |
398 |
mnt = nfs_do_refmount(client, dentry); |
47040da3c NFSv4: Allow secu... |
399 400 |
goto out; } |
281cad46b NFS: Create a sub... |
401 |
|
47040da3c NFSv4: Allow secu... |
402 403 |
if (client->cl_auth->au_flavor != flavor) flavor = client->cl_auth->au_flavor; |
47040da3c NFSv4: Allow secu... |
404 405 |
mnt = nfs_do_submount(dentry, fh, fattr, flavor); out: |
281cad46b NFS: Create a sub... |
406 407 408 |
rpc_shutdown_client(client); return mnt; } |
800c06a5b NFS: Add function... |
409 410 411 412 413 414 415 416 417 418 419 |
/* * 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... |
420 |
struct net *net = rpc_net_ns(server->client); |
800c06a5b NFS: Add function... |
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 |
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... |
442 |
sap, addr_bufsize, net); |
800c06a5b NFS: Add function... |
443 444 445 446 447 448 449 450 |
if (salen == 0) continue; rpc_set_port(sap, NFS_PORT); error = -ENOMEM; hostname = kstrndup(buf->data, buf->len, GFP_KERNEL); if (hostname == NULL) break; |
292f503ca NFSv4: Use the co... |
451 |
error = nfs4_update_server(server, hostname, sap, salen, net); |
800c06a5b NFS: Add function... |
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 |
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; } |