hc
2024-09-20 cf4ce59b3b70238352c7f1729f0f7223214828ad
kernel/fs/nfs/nfs4namespace.c
....@@ -8,6 +8,7 @@
88 * NFSv4 namespace
99 */
1010
11
+#include <linux/module.h>
1112 #include <linux/dcache.h>
1213 #include <linux/mount.h>
1314 #include <linux/namei.h>
....@@ -21,37 +22,64 @@
2122 #include <linux/inet.h>
2223 #include "internal.h"
2324 #include "nfs4_fs.h"
25
+#include "nfs.h"
2426 #include "dns_resolve.h"
2527
2628 #define NFSDBG_FACILITY NFSDBG_VFS
2729
2830 /*
29
- * Convert the NFSv4 pathname components into a standard posix path.
30
- *
31
- * Note that the resulting string will be placed at the end of the buffer
31
+ * Work out the length that an NFSv4 path would render to as a standard posix
32
+ * path, with a leading slash but no terminating slash.
3233 */
33
-static inline char *nfs4_pathname_string(const struct nfs4_pathname *pathname,
34
- char *buffer, ssize_t buflen)
34
+static ssize_t nfs4_pathname_len(const struct nfs4_pathname *pathname)
3535 {
36
- char *end = buffer + buflen;
37
- int n;
36
+ ssize_t len = 0;
37
+ int i;
3838
39
- *--end = '\0';
40
- buflen--;
39
+ for (i = 0; i < pathname->ncomponents; i++) {
40
+ const struct nfs4_string *component = &pathname->components[i];
4141
42
- n = pathname->ncomponents;
43
- while (--n >= 0) {
44
- const struct nfs4_string *component = &pathname->components[n];
45
- buflen -= component->len + 1;
46
- if (buflen < 0)
47
- goto Elong;
48
- end -= component->len;
49
- memcpy(end, component->data, component->len);
50
- *--end = '/';
42
+ if (component->len > NAME_MAX)
43
+ goto too_long;
44
+ len += 1 + component->len; /* Adding "/foo" */
45
+ if (len > PATH_MAX)
46
+ goto too_long;
5147 }
52
- return end;
53
-Elong:
54
- return ERR_PTR(-ENAMETOOLONG);
48
+ return len;
49
+
50
+too_long:
51
+ return -ENAMETOOLONG;
52
+}
53
+
54
+/*
55
+ * Convert the NFSv4 pathname components into a standard posix path.
56
+ */
57
+static char *nfs4_pathname_string(const struct nfs4_pathname *pathname,
58
+ unsigned short *_len)
59
+{
60
+ ssize_t len;
61
+ char *buf, *p;
62
+ int i;
63
+
64
+ len = nfs4_pathname_len(pathname);
65
+ if (len < 0)
66
+ return ERR_PTR(len);
67
+ *_len = len;
68
+
69
+ p = buf = kmalloc(len + 1, GFP_KERNEL);
70
+ if (!buf)
71
+ return ERR_PTR(-ENOMEM);
72
+
73
+ for (i = 0; i < pathname->ncomponents; i++) {
74
+ const struct nfs4_string *component = &pathname->components[i];
75
+
76
+ *p++ = '/';
77
+ memcpy(p, component->data, component->len);
78
+ p += component->len;
79
+ }
80
+
81
+ *p = 0;
82
+ return buf;
5583 }
5684
5785 /*
....@@ -100,21 +128,36 @@
100128 */
101129 static int nfs4_validate_fspath(struct dentry *dentry,
102130 const struct nfs4_fs_locations *locations,
103
- char *page, char *page2)
131
+ struct nfs_fs_context *ctx)
104132 {
105
- const char *path, *fs_path;
133
+ const char *path;
134
+ char *fs_path;
135
+ unsigned short len;
136
+ char *buf;
137
+ int n;
106138
107
- path = nfs4_path(dentry, page, PAGE_SIZE);
108
- if (IS_ERR(path))
139
+ buf = kmalloc(4096, GFP_KERNEL);
140
+ if (!buf)
141
+ return -ENOMEM;
142
+
143
+ path = nfs4_path(dentry, buf, 4096);
144
+ if (IS_ERR(path)) {
145
+ kfree(buf);
109146 return PTR_ERR(path);
147
+ }
110148
111
- fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE);
112
- if (IS_ERR(fs_path))
149
+ fs_path = nfs4_pathname_string(&locations->fs_path, &len);
150
+ if (IS_ERR(fs_path)) {
151
+ kfree(buf);
113152 return PTR_ERR(fs_path);
153
+ }
114154
115
- if (strncmp(path, fs_path, strlen(fs_path)) != 0) {
155
+ n = strncmp(path, fs_path, len);
156
+ kfree(buf);
157
+ kfree(fs_path);
158
+ if (n != 0) {
116159 dprintk("%s: path %s does not begin with fsroot %s\n",
117
- __func__, path, fs_path);
160
+ __func__, path, ctx->nfs_server.export_path);
118161 return -ENOENT;
119162 }
120163
....@@ -122,21 +165,27 @@
122165 }
123166
124167 size_t nfs_parse_server_name(char *string, size_t len, struct sockaddr *sa,
125
- size_t salen, struct net *net)
168
+ size_t salen, struct net *net, int port)
126169 {
127170 ssize_t ret;
128171
129172 ret = rpc_pton(net, string, len, sa, salen);
130173 if (ret == 0) {
131
- ret = nfs_dns_resolve_name(net, string, len, sa, salen);
132
- if (ret < 0)
133
- ret = 0;
174
+ ret = rpc_uaddr2sockaddr(net, string, len, sa, salen);
175
+ if (ret == 0) {
176
+ ret = nfs_dns_resolve_name(net, string, len, sa, salen);
177
+ if (ret < 0)
178
+ ret = 0;
179
+ }
180
+ } else if (port) {
181
+ rpc_set_port(sa, port);
134182 }
135183 return ret;
136184 }
137185
138186 /**
139187 * nfs_find_best_sec - Find a security mechanism supported locally
188
+ * @clnt: pointer to rpc_clnt
140189 * @server: NFS server struct
141190 * @flavors: List of security tuples returned by SECINFO procedure
142191 *
....@@ -235,95 +284,103 @@
235284 return new;
236285 }
237286
238
-static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
239
- char *page, char *page2,
240
- const struct nfs4_fs_location *location)
287
+static int try_location(struct fs_context *fc,
288
+ const struct nfs4_fs_location *location)
241289 {
242
- const size_t addr_bufsize = sizeof(struct sockaddr_storage);
243
- struct net *net = rpc_net_ns(NFS_SB(mountdata->sb)->client);
244
- struct vfsmount *mnt = ERR_PTR(-ENOENT);
245
- char *mnt_path;
246
- unsigned int maxbuflen;
247
- unsigned int s;
290
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
291
+ unsigned int len, s;
292
+ char *export_path, *source, *p;
293
+ int ret = -ENOENT;
248294
249
- mnt_path = nfs4_pathname_string(&location->rootpath, page2, PAGE_SIZE);
250
- if (IS_ERR(mnt_path))
251
- return ERR_CAST(mnt_path);
252
- mountdata->mnt_path = mnt_path;
253
- maxbuflen = mnt_path - 1 - page2;
254
-
255
- mountdata->addr = kmalloc(addr_bufsize, GFP_KERNEL);
256
- if (mountdata->addr == NULL)
257
- return ERR_PTR(-ENOMEM);
258
-
295
+ /* Allocate a buffer big enough to hold any of the hostnames plus a
296
+ * terminating char and also a buffer big enough to hold the hostname
297
+ * plus a colon plus the path.
298
+ */
299
+ len = 0;
259300 for (s = 0; s < location->nservers; s++) {
260301 const struct nfs4_string *buf = &location->servers[s];
302
+ if (buf->len > len)
303
+ len = buf->len;
304
+ }
261305
262
- if (buf->len <= 0 || buf->len >= maxbuflen)
263
- continue;
306
+ kfree(ctx->nfs_server.hostname);
307
+ ctx->nfs_server.hostname = kmalloc(len + 1, GFP_KERNEL);
308
+ if (!ctx->nfs_server.hostname)
309
+ return -ENOMEM;
310
+
311
+ export_path = nfs4_pathname_string(&location->rootpath,
312
+ &ctx->nfs_server.export_path_len);
313
+ if (IS_ERR(export_path))
314
+ return PTR_ERR(export_path);
315
+
316
+ kfree(ctx->nfs_server.export_path);
317
+ ctx->nfs_server.export_path = export_path;
318
+
319
+ source = kmalloc(len + 1 + ctx->nfs_server.export_path_len + 1,
320
+ GFP_KERNEL);
321
+ if (!source)
322
+ return -ENOMEM;
323
+
324
+ kfree(fc->source);
325
+ fc->source = source;
326
+ for (s = 0; s < location->nservers; s++) {
327
+ const struct nfs4_string *buf = &location->servers[s];
264328
265329 if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len))
266330 continue;
267331
268
- mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len,
269
- mountdata->addr, addr_bufsize, net);
270
- if (mountdata->addrlen == 0)
332
+ ctx->nfs_server.addrlen =
333
+ nfs_parse_server_name(buf->data, buf->len,
334
+ &ctx->nfs_server.address,
335
+ sizeof(ctx->nfs_server._address),
336
+ fc->net_ns, 0);
337
+ if (ctx->nfs_server.addrlen == 0)
271338 continue;
272339
273
- memcpy(page2, buf->data, buf->len);
274
- page2[buf->len] = '\0';
275
- mountdata->hostname = page2;
340
+ rpc_set_port(&ctx->nfs_server.address, NFS_PORT);
276341
277
- snprintf(page, PAGE_SIZE, "%s:%s",
278
- mountdata->hostname,
279
- mountdata->mnt_path);
342
+ memcpy(ctx->nfs_server.hostname, buf->data, buf->len);
343
+ ctx->nfs_server.hostname[buf->len] = '\0';
280344
281
- mnt = vfs_submount(mountdata->dentry, &nfs4_referral_fs_type, page, mountdata);
282
- if (!IS_ERR(mnt))
283
- break;
345
+ p = source;
346
+ memcpy(p, buf->data, buf->len);
347
+ p += buf->len;
348
+ *p++ = ':';
349
+ memcpy(p, ctx->nfs_server.export_path, ctx->nfs_server.export_path_len);
350
+ p += ctx->nfs_server.export_path_len;
351
+ *p = 0;
352
+
353
+ ret = nfs4_get_referral_tree(fc);
354
+ if (ret == 0)
355
+ return 0;
284356 }
285
- kfree(mountdata->addr);
286
- return mnt;
357
+
358
+ return ret;
287359 }
288360
289361 /**
290362 * nfs_follow_referral - set up mountpoint when hitting a referral on moved error
291
- * @dentry - parent directory
292
- * @locations - array of NFSv4 server location information
363
+ * @fc: pointer to struct nfs_fs_context
364
+ * @locations: array of NFSv4 server location information
293365 *
294366 */
295
-static struct vfsmount *nfs_follow_referral(struct dentry *dentry,
296
- const struct nfs4_fs_locations *locations)
367
+static int nfs_follow_referral(struct fs_context *fc,
368
+ const struct nfs4_fs_locations *locations)
297369 {
298
- struct vfsmount *mnt = ERR_PTR(-ENOENT);
299
- struct nfs_clone_mount mountdata = {
300
- .sb = dentry->d_sb,
301
- .dentry = dentry,
302
- .authflavor = NFS_SB(dentry->d_sb)->client->cl_auth->au_flavor,
303
- };
304
- char *page = NULL, *page2 = NULL;
370
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
305371 int loc, error;
306372
307373 if (locations == NULL || locations->nlocations <= 0)
308
- goto out;
374
+ return -ENOENT;
309375
310
- dprintk("%s: referral at %pd2\n", __func__, dentry);
311
-
312
- page = (char *) __get_free_page(GFP_USER);
313
- if (!page)
314
- goto out;
315
-
316
- page2 = (char *) __get_free_page(GFP_USER);
317
- if (!page2)
318
- goto out;
376
+ dprintk("%s: referral at %pd2\n", __func__, ctx->clone_data.dentry);
319377
320378 /* Ensure fs path is a prefix of current dentry path */
321
- error = nfs4_validate_fspath(dentry, locations, page, page2);
322
- if (error < 0) {
323
- mnt = ERR_PTR(error);
324
- goto out;
325
- }
379
+ error = nfs4_validate_fspath(ctx->clone_data.dentry, locations, ctx);
380
+ if (error < 0)
381
+ return error;
326382
383
+ error = -ENOENT;
327384 for (loc = 0; loc < locations->nlocations; loc++) {
328385 const struct nfs4_fs_location *location = &locations->locations[loc];
329386
....@@ -331,15 +388,12 @@
331388 location->rootpath.ncomponents == 0)
332389 continue;
333390
334
- mnt = try_location(&mountdata, page, page2, location);
335
- if (!IS_ERR(mnt))
336
- break;
391
+ error = try_location(fc, location);
392
+ if (error == 0)
393
+ return 0;
337394 }
338395
339
-out:
340
- free_page((unsigned long) page);
341
- free_page((unsigned long) page2);
342
- return mnt;
396
+ return error;
343397 }
344398
345399 /*
....@@ -347,71 +401,72 @@
347401 * @dentry - dentry of referral
348402 *
349403 */
350
-static struct vfsmount *nfs_do_refmount(struct rpc_clnt *client, struct dentry *dentry)
404
+static int nfs_do_refmount(struct fs_context *fc, struct rpc_clnt *client)
351405 {
352
- struct vfsmount *mnt = ERR_PTR(-ENOMEM);
353
- struct dentry *parent;
406
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
407
+ struct dentry *dentry, *parent;
354408 struct nfs4_fs_locations *fs_locations = NULL;
355409 struct page *page;
356
- int err;
410
+ int err = -ENOMEM;
357411
358412 /* BUG_ON(IS_ROOT(dentry)); */
359413 page = alloc_page(GFP_KERNEL);
360
- if (page == NULL)
361
- return mnt;
414
+ if (!page)
415
+ return -ENOMEM;
362416
363417 fs_locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL);
364
- if (fs_locations == NULL)
418
+ if (!fs_locations)
365419 goto out_free;
366420
367421 /* Get locations */
368
- mnt = ERR_PTR(-ENOENT);
369
-
422
+ dentry = ctx->clone_data.dentry;
370423 parent = dget_parent(dentry);
371424 dprintk("%s: getting locations for %pd2\n",
372425 __func__, dentry);
373426
374427 err = nfs4_proc_fs_locations(client, d_inode(parent), &dentry->d_name, fs_locations, page);
375428 dput(parent);
376
- if (err != 0 ||
377
- fs_locations->nlocations <= 0 ||
378
- fs_locations->fs_path.ncomponents <= 0)
379
- goto out_free;
429
+ if (err != 0)
430
+ goto out_free_2;
380431
381
- mnt = nfs_follow_referral(dentry, fs_locations);
432
+ err = -ENOENT;
433
+ if (fs_locations->nlocations <= 0 ||
434
+ fs_locations->fs_path.ncomponents <= 0)
435
+ goto out_free_2;
436
+
437
+ err = nfs_follow_referral(fc, fs_locations);
438
+out_free_2:
439
+ kfree(fs_locations);
382440 out_free:
383441 __free_page(page);
384
- kfree(fs_locations);
385
- return mnt;
442
+ return err;
386443 }
387444
388
-struct vfsmount *nfs4_submount(struct nfs_server *server, struct dentry *dentry,
389
- struct nfs_fh *fh, struct nfs_fattr *fattr)
445
+int nfs4_submount(struct fs_context *fc, struct nfs_server *server)
390446 {
391
- rpc_authflavor_t flavor = server->client->cl_auth->au_flavor;
447
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
448
+ struct dentry *dentry = ctx->clone_data.dentry;
392449 struct dentry *parent = dget_parent(dentry);
393450 struct inode *dir = d_inode(parent);
394
- const struct qstr *name = &dentry->d_name;
395451 struct rpc_clnt *client;
396
- struct vfsmount *mnt;
452
+ int ret;
397453
398454 /* Look it up again to get its attributes and sec flavor */
399
- client = nfs4_proc_lookup_mountpoint(dir, name, fh, fattr);
455
+ client = nfs4_proc_lookup_mountpoint(dir, dentry, ctx->mntfh,
456
+ ctx->clone_data.fattr);
400457 dput(parent);
401458 if (IS_ERR(client))
402
- return ERR_CAST(client);
459
+ return PTR_ERR(client);
403460
404
- if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) {
405
- mnt = nfs_do_refmount(client, dentry);
406
- goto out;
461
+ ctx->selected_flavor = client->cl_auth->au_flavor;
462
+ if (ctx->clone_data.fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) {
463
+ ret = nfs_do_refmount(fc, client);
464
+ } else {
465
+ ret = nfs_do_submount(fc);
407466 }
408467
409
- if (client->cl_auth->au_flavor != flavor)
410
- flavor = client->cl_auth->au_flavor;
411
- mnt = nfs_do_submount(dentry, fh, fattr, flavor);
412
-out:
413468 rpc_shutdown_client(client);
414
- return mnt;
469
+ return ret;
415470 }
416471
417472 /*
....@@ -446,13 +501,13 @@
446501 continue;
447502
448503 salen = nfs_parse_server_name(buf->data, buf->len,
449
- sap, addr_bufsize, net);
504
+ sap, addr_bufsize, net, 0);
450505 if (salen == 0)
451506 continue;
452507 rpc_set_port(sap, NFS_PORT);
453508
454509 error = -ENOMEM;
455
- hostname = kstrndup(buf->data, buf->len, GFP_KERNEL);
510
+ hostname = kmemdup_nul(buf->data, buf->len, GFP_KERNEL);
456511 if (hostname == NULL)
457512 break;
458513