diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /fs/nfs/super.c | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'fs/nfs/super.c')
-rw-r--r-- | fs/nfs/super.c | 1480 |
1 files changed, 906 insertions, 574 deletions
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 2e7e8c878e5..c4daf4eaad9 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/lockd/bind.h> | 41 | #include <linux/lockd/bind.h> |
42 | #include <linux/seq_file.h> | 42 | #include <linux/seq_file.h> |
43 | #include <linux/mount.h> | 43 | #include <linux/mount.h> |
44 | #include <linux/mnt_namespace.h> | ||
44 | #include <linux/namei.h> | 45 | #include <linux/namei.h> |
45 | #include <linux/nfs_idmap.h> | 46 | #include <linux/nfs_idmap.h> |
46 | #include <linux/vfs.h> | 47 | #include <linux/vfs.h> |
@@ -52,10 +53,8 @@ | |||
52 | #include <linux/nfs_xdr.h> | 53 | #include <linux/nfs_xdr.h> |
53 | #include <linux/magic.h> | 54 | #include <linux/magic.h> |
54 | #include <linux/parser.h> | 55 | #include <linux/parser.h> |
55 | #include <linux/nsproxy.h> | ||
56 | #include <linux/rcupdate.h> | ||
57 | #include <linux/kthread.h> | ||
58 | 56 | ||
57 | #include <asm/system.h> | ||
59 | #include <asm/uaccess.h> | 58 | #include <asm/uaccess.h> |
60 | 59 | ||
61 | #include "nfs4_fs.h" | 60 | #include "nfs4_fs.h" |
@@ -64,14 +63,11 @@ | |||
64 | #include "iostat.h" | 63 | #include "iostat.h" |
65 | #include "internal.h" | 64 | #include "internal.h" |
66 | #include "fscache.h" | 65 | #include "fscache.h" |
67 | #include "nfs4session.h" | ||
68 | #include "pnfs.h" | 66 | #include "pnfs.h" |
69 | #include "nfs.h" | ||
70 | 67 | ||
71 | #define NFSDBG_FACILITY NFSDBG_VFS | 68 | #define NFSDBG_FACILITY NFSDBG_VFS |
72 | #define NFS_TEXT_DATA 1 | ||
73 | 69 | ||
74 | #if IS_ENABLED(CONFIG_NFS_V3) | 70 | #ifdef CONFIG_NFS_V3 |
75 | #define NFS_DEFAULT_VERSION 3 | 71 | #define NFS_DEFAULT_VERSION 3 |
76 | #else | 72 | #else |
77 | #define NFS_DEFAULT_VERSION 2 | 73 | #define NFS_DEFAULT_VERSION 2 |
@@ -84,13 +80,13 @@ enum { | |||
84 | Opt_cto, Opt_nocto, | 80 | Opt_cto, Opt_nocto, |
85 | Opt_ac, Opt_noac, | 81 | Opt_ac, Opt_noac, |
86 | Opt_lock, Opt_nolock, | 82 | Opt_lock, Opt_nolock, |
83 | Opt_v2, Opt_v3, Opt_v4, | ||
87 | Opt_udp, Opt_tcp, Opt_rdma, | 84 | Opt_udp, Opt_tcp, Opt_rdma, |
88 | Opt_acl, Opt_noacl, | 85 | Opt_acl, Opt_noacl, |
89 | Opt_rdirplus, Opt_nordirplus, | 86 | Opt_rdirplus, Opt_nordirplus, |
90 | Opt_sharecache, Opt_nosharecache, | 87 | Opt_sharecache, Opt_nosharecache, |
91 | Opt_resvport, Opt_noresvport, | 88 | Opt_resvport, Opt_noresvport, |
92 | Opt_fscache, Opt_nofscache, | 89 | Opt_fscache, Opt_nofscache, |
93 | Opt_migration, Opt_nomigration, | ||
94 | 90 | ||
95 | /* Mount options that take integer arguments */ | 91 | /* Mount options that take integer arguments */ |
96 | Opt_port, | 92 | Opt_port, |
@@ -102,10 +98,10 @@ enum { | |||
102 | Opt_namelen, | 98 | Opt_namelen, |
103 | Opt_mountport, | 99 | Opt_mountport, |
104 | Opt_mountvers, | 100 | Opt_mountvers, |
101 | Opt_nfsvers, | ||
105 | Opt_minorversion, | 102 | Opt_minorversion, |
106 | 103 | ||
107 | /* Mount options that take string arguments */ | 104 | /* Mount options that take string arguments */ |
108 | Opt_nfsvers, | ||
109 | Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost, | 105 | Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost, |
110 | Opt_addr, Opt_mountaddr, Opt_clientaddr, | 106 | Opt_addr, Opt_mountaddr, Opt_clientaddr, |
111 | Opt_lookupcache, | 107 | Opt_lookupcache, |
@@ -137,6 +133,9 @@ static const match_table_t nfs_mount_option_tokens = { | |||
137 | { Opt_noac, "noac" }, | 133 | { Opt_noac, "noac" }, |
138 | { Opt_lock, "lock" }, | 134 | { Opt_lock, "lock" }, |
139 | { Opt_nolock, "nolock" }, | 135 | { Opt_nolock, "nolock" }, |
136 | { Opt_v2, "v2" }, | ||
137 | { Opt_v3, "v3" }, | ||
138 | { Opt_v4, "v4" }, | ||
140 | { Opt_udp, "udp" }, | 139 | { Opt_udp, "udp" }, |
141 | { Opt_tcp, "tcp" }, | 140 | { Opt_tcp, "tcp" }, |
142 | { Opt_rdma, "rdma" }, | 141 | { Opt_rdma, "rdma" }, |
@@ -150,8 +149,6 @@ static const match_table_t nfs_mount_option_tokens = { | |||
150 | { Opt_noresvport, "noresvport" }, | 149 | { Opt_noresvport, "noresvport" }, |
151 | { Opt_fscache, "fsc" }, | 150 | { Opt_fscache, "fsc" }, |
152 | { Opt_nofscache, "nofsc" }, | 151 | { Opt_nofscache, "nofsc" }, |
153 | { Opt_migration, "migration" }, | ||
154 | { Opt_nomigration, "nomigration" }, | ||
155 | 152 | ||
156 | { Opt_port, "port=%s" }, | 153 | { Opt_port, "port=%s" }, |
157 | { Opt_rsize, "rsize=%s" }, | 154 | { Opt_rsize, "rsize=%s" }, |
@@ -167,10 +164,9 @@ static const match_table_t nfs_mount_option_tokens = { | |||
167 | { Opt_namelen, "namlen=%s" }, | 164 | { Opt_namelen, "namlen=%s" }, |
168 | { Opt_mountport, "mountport=%s" }, | 165 | { Opt_mountport, "mountport=%s" }, |
169 | { Opt_mountvers, "mountvers=%s" }, | 166 | { Opt_mountvers, "mountvers=%s" }, |
170 | { Opt_minorversion, "minorversion=%s" }, | ||
171 | |||
172 | { Opt_nfsvers, "nfsvers=%s" }, | 167 | { Opt_nfsvers, "nfsvers=%s" }, |
173 | { Opt_nfsvers, "vers=%s" }, | 168 | { Opt_nfsvers, "vers=%s" }, |
169 | { Opt_minorversion, "minorversion=%s" }, | ||
174 | 170 | ||
175 | { Opt_sec, "sec=%s" }, | 171 | { Opt_sec, "sec=%s" }, |
176 | { Opt_proto, "proto=%s" }, | 172 | { Opt_proto, "proto=%s" }, |
@@ -184,9 +180,6 @@ static const match_table_t nfs_mount_option_tokens = { | |||
184 | { Opt_fscache_uniq, "fsc=%s" }, | 180 | { Opt_fscache_uniq, "fsc=%s" }, |
185 | { Opt_local_lock, "local_lock=%s" }, | 181 | { Opt_local_lock, "local_lock=%s" }, |
186 | 182 | ||
187 | /* The following needs to be listed after all other options */ | ||
188 | { Opt_nfsvers, "v%s" }, | ||
189 | |||
190 | { Opt_err, NULL } | 183 | { Opt_err, NULL } |
191 | }; | 184 | }; |
192 | 185 | ||
@@ -267,34 +260,28 @@ static match_table_t nfs_local_lock_tokens = { | |||
267 | { Opt_local_lock_err, NULL } | 260 | { Opt_local_lock_err, NULL } |
268 | }; | 261 | }; |
269 | 262 | ||
270 | enum { | ||
271 | Opt_vers_2, Opt_vers_3, Opt_vers_4, Opt_vers_4_0, | ||
272 | Opt_vers_4_1, | ||
273 | |||
274 | Opt_vers_err | ||
275 | }; | ||
276 | |||
277 | static match_table_t nfs_vers_tokens = { | ||
278 | { Opt_vers_2, "2" }, | ||
279 | { Opt_vers_3, "3" }, | ||
280 | { Opt_vers_4, "4" }, | ||
281 | { Opt_vers_4_0, "4.0" }, | ||
282 | { Opt_vers_4_1, "4.1" }, | ||
283 | |||
284 | { Opt_vers_err, NULL } | ||
285 | }; | ||
286 | 263 | ||
264 | static void nfs_umount_begin(struct super_block *); | ||
265 | static int nfs_statfs(struct dentry *, struct kstatfs *); | ||
266 | static int nfs_show_options(struct seq_file *, struct vfsmount *); | ||
267 | static int nfs_show_devname(struct seq_file *, struct vfsmount *); | ||
268 | static int nfs_show_path(struct seq_file *, struct vfsmount *); | ||
269 | static int nfs_show_stats(struct seq_file *, struct vfsmount *); | ||
270 | static struct dentry *nfs_fs_mount(struct file_system_type *, | ||
271 | int, const char *, void *); | ||
287 | static struct dentry *nfs_xdev_mount(struct file_system_type *fs_type, | 272 | static struct dentry *nfs_xdev_mount(struct file_system_type *fs_type, |
288 | int flags, const char *dev_name, void *raw_data); | 273 | int flags, const char *dev_name, void *raw_data); |
274 | static void nfs_put_super(struct super_block *); | ||
275 | static void nfs_kill_super(struct super_block *); | ||
276 | static int nfs_remount(struct super_block *sb, int *flags, char *raw_data); | ||
289 | 277 | ||
290 | struct file_system_type nfs_fs_type = { | 278 | static struct file_system_type nfs_fs_type = { |
291 | .owner = THIS_MODULE, | 279 | .owner = THIS_MODULE, |
292 | .name = "nfs", | 280 | .name = "nfs", |
293 | .mount = nfs_fs_mount, | 281 | .mount = nfs_fs_mount, |
294 | .kill_sb = nfs_kill_super, | 282 | .kill_sb = nfs_kill_super, |
295 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | 283 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, |
296 | }; | 284 | }; |
297 | EXPORT_SYMBOL_GPL(nfs_fs_type); | ||
298 | 285 | ||
299 | struct file_system_type nfs_xdev_fs_type = { | 286 | struct file_system_type nfs_xdev_fs_type = { |
300 | .owner = THIS_MODULE, | 287 | .owner = THIS_MODULE, |
@@ -304,11 +291,10 @@ struct file_system_type nfs_xdev_fs_type = { | |||
304 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | 291 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, |
305 | }; | 292 | }; |
306 | 293 | ||
307 | const struct super_operations nfs_sops = { | 294 | static const struct super_operations nfs_sops = { |
308 | .alloc_inode = nfs_alloc_inode, | 295 | .alloc_inode = nfs_alloc_inode, |
309 | .destroy_inode = nfs_destroy_inode, | 296 | .destroy_inode = nfs_destroy_inode, |
310 | .write_inode = nfs_write_inode, | 297 | .write_inode = nfs_write_inode, |
311 | .drop_inode = nfs_drop_inode, | ||
312 | .put_super = nfs_put_super, | 298 | .put_super = nfs_put_super, |
313 | .statfs = nfs_statfs, | 299 | .statfs = nfs_statfs, |
314 | .evict_inode = nfs_evict_inode, | 300 | .evict_inode = nfs_evict_inode, |
@@ -319,40 +305,78 @@ const struct super_operations nfs_sops = { | |||
319 | .show_stats = nfs_show_stats, | 305 | .show_stats = nfs_show_stats, |
320 | .remount_fs = nfs_remount, | 306 | .remount_fs = nfs_remount, |
321 | }; | 307 | }; |
322 | EXPORT_SYMBOL_GPL(nfs_sops); | ||
323 | 308 | ||
324 | #if IS_ENABLED(CONFIG_NFS_V4) | 309 | #ifdef CONFIG_NFS_V4 |
325 | static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *); | 310 | static int nfs4_validate_text_mount_data(void *options, |
326 | static int nfs4_validate_mount_data(void *options, | ||
327 | struct nfs_parsed_mount_data *args, const char *dev_name); | 311 | struct nfs_parsed_mount_data *args, const char *dev_name); |
312 | static struct dentry *nfs4_try_mount(int flags, const char *dev_name, | ||
313 | struct nfs_parsed_mount_data *data); | ||
314 | static struct dentry *nfs4_mount(struct file_system_type *fs_type, | ||
315 | int flags, const char *dev_name, void *raw_data); | ||
316 | static struct dentry *nfs4_remote_mount(struct file_system_type *fs_type, | ||
317 | int flags, const char *dev_name, void *raw_data); | ||
318 | static struct dentry *nfs4_xdev_mount(struct file_system_type *fs_type, | ||
319 | int flags, const char *dev_name, void *raw_data); | ||
320 | static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type, | ||
321 | int flags, const char *dev_name, void *raw_data); | ||
322 | static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type, | ||
323 | int flags, const char *dev_name, void *raw_data); | ||
324 | static void nfs4_kill_super(struct super_block *sb); | ||
325 | |||
326 | static struct file_system_type nfs4_fs_type = { | ||
327 | .owner = THIS_MODULE, | ||
328 | .name = "nfs4", | ||
329 | .mount = nfs4_mount, | ||
330 | .kill_sb = nfs4_kill_super, | ||
331 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
332 | }; | ||
328 | 333 | ||
329 | struct file_system_type nfs4_fs_type = { | 334 | static struct file_system_type nfs4_remote_fs_type = { |
330 | .owner = THIS_MODULE, | 335 | .owner = THIS_MODULE, |
331 | .name = "nfs4", | 336 | .name = "nfs4", |
332 | .mount = nfs_fs_mount, | 337 | .mount = nfs4_remote_mount, |
333 | .kill_sb = nfs_kill_super, | 338 | .kill_sb = nfs4_kill_super, |
334 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | 339 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, |
335 | }; | 340 | }; |
336 | EXPORT_SYMBOL_GPL(nfs4_fs_type); | ||
337 | 341 | ||
338 | static int __init register_nfs4_fs(void) | 342 | struct file_system_type nfs4_xdev_fs_type = { |
339 | { | 343 | .owner = THIS_MODULE, |
340 | return register_filesystem(&nfs4_fs_type); | 344 | .name = "nfs4", |
341 | } | 345 | .mount = nfs4_xdev_mount, |
346 | .kill_sb = nfs4_kill_super, | ||
347 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
348 | }; | ||
342 | 349 | ||
343 | static void unregister_nfs4_fs(void) | 350 | static struct file_system_type nfs4_remote_referral_fs_type = { |
344 | { | 351 | .owner = THIS_MODULE, |
345 | unregister_filesystem(&nfs4_fs_type); | 352 | .name = "nfs4", |
346 | } | 353 | .mount = nfs4_remote_referral_mount, |
347 | #else | 354 | .kill_sb = nfs4_kill_super, |
348 | static int __init register_nfs4_fs(void) | 355 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, |
349 | { | 356 | }; |
350 | return 0; | ||
351 | } | ||
352 | 357 | ||
353 | static void unregister_nfs4_fs(void) | 358 | struct file_system_type nfs4_referral_fs_type = { |
354 | { | 359 | .owner = THIS_MODULE, |
355 | } | 360 | .name = "nfs4", |
361 | .mount = nfs4_referral_mount, | ||
362 | .kill_sb = nfs4_kill_super, | ||
363 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
364 | }; | ||
365 | |||
366 | static const struct super_operations nfs4_sops = { | ||
367 | .alloc_inode = nfs_alloc_inode, | ||
368 | .destroy_inode = nfs_destroy_inode, | ||
369 | .write_inode = nfs_write_inode, | ||
370 | .put_super = nfs_put_super, | ||
371 | .statfs = nfs_statfs, | ||
372 | .evict_inode = nfs4_evict_inode, | ||
373 | .umount_begin = nfs_umount_begin, | ||
374 | .show_options = nfs_show_options, | ||
375 | .show_devname = nfs_show_devname, | ||
376 | .show_path = nfs_show_path, | ||
377 | .show_stats = nfs_show_stats, | ||
378 | .remount_fs = nfs_remount, | ||
379 | }; | ||
356 | #endif | 380 | #endif |
357 | 381 | ||
358 | static struct shrinker acl_shrinker = { | 382 | static struct shrinker acl_shrinker = { |
@@ -371,18 +395,21 @@ int __init register_nfs_fs(void) | |||
371 | if (ret < 0) | 395 | if (ret < 0) |
372 | goto error_0; | 396 | goto error_0; |
373 | 397 | ||
374 | ret = register_nfs4_fs(); | 398 | ret = nfs_register_sysctl(); |
375 | if (ret < 0) | 399 | if (ret < 0) |
376 | goto error_1; | 400 | goto error_1; |
377 | 401 | #ifdef CONFIG_NFS_V4 | |
378 | ret = nfs_register_sysctl(); | 402 | ret = register_filesystem(&nfs4_fs_type); |
379 | if (ret < 0) | 403 | if (ret < 0) |
380 | goto error_2; | 404 | goto error_2; |
405 | #endif | ||
381 | register_shrinker(&acl_shrinker); | 406 | register_shrinker(&acl_shrinker); |
382 | return 0; | 407 | return 0; |
383 | 408 | ||
409 | #ifdef CONFIG_NFS_V4 | ||
384 | error_2: | 410 | error_2: |
385 | unregister_nfs4_fs(); | 411 | nfs_unregister_sysctl(); |
412 | #endif | ||
386 | error_1: | 413 | error_1: |
387 | unregister_filesystem(&nfs_fs_type); | 414 | unregister_filesystem(&nfs_fs_type); |
388 | error_0: | 415 | error_0: |
@@ -395,8 +422,10 @@ error_0: | |||
395 | void __exit unregister_nfs_fs(void) | 422 | void __exit unregister_nfs_fs(void) |
396 | { | 423 | { |
397 | unregister_shrinker(&acl_shrinker); | 424 | unregister_shrinker(&acl_shrinker); |
425 | #ifdef CONFIG_NFS_V4 | ||
426 | unregister_filesystem(&nfs4_fs_type); | ||
427 | #endif | ||
398 | nfs_unregister_sysctl(); | 428 | nfs_unregister_sysctl(); |
399 | unregister_nfs4_fs(); | ||
400 | unregister_filesystem(&nfs_fs_type); | 429 | unregister_filesystem(&nfs_fs_type); |
401 | } | 430 | } |
402 | 431 | ||
@@ -407,7 +436,6 @@ void nfs_sb_active(struct super_block *sb) | |||
407 | if (atomic_inc_return(&server->active) == 1) | 436 | if (atomic_inc_return(&server->active) == 1) |
408 | atomic_inc(&sb->s_active); | 437 | atomic_inc(&sb->s_active); |
409 | } | 438 | } |
410 | EXPORT_SYMBOL_GPL(nfs_sb_active); | ||
411 | 439 | ||
412 | void nfs_sb_deactive(struct super_block *sb) | 440 | void nfs_sb_deactive(struct super_block *sb) |
413 | { | 441 | { |
@@ -416,60 +444,11 @@ void nfs_sb_deactive(struct super_block *sb) | |||
416 | if (atomic_dec_and_test(&server->active)) | 444 | if (atomic_dec_and_test(&server->active)) |
417 | deactivate_super(sb); | 445 | deactivate_super(sb); |
418 | } | 446 | } |
419 | EXPORT_SYMBOL_GPL(nfs_sb_deactive); | ||
420 | |||
421 | static int nfs_deactivate_super_async_work(void *ptr) | ||
422 | { | ||
423 | struct super_block *sb = ptr; | ||
424 | |||
425 | deactivate_super(sb); | ||
426 | module_put_and_exit(0); | ||
427 | return 0; | ||
428 | } | ||
429 | |||
430 | /* | ||
431 | * same effect as deactivate_super, but will do final unmount in kthread | ||
432 | * context | ||
433 | */ | ||
434 | static void nfs_deactivate_super_async(struct super_block *sb) | ||
435 | { | ||
436 | struct task_struct *task; | ||
437 | char buf[INET6_ADDRSTRLEN + 1]; | ||
438 | struct nfs_server *server = NFS_SB(sb); | ||
439 | struct nfs_client *clp = server->nfs_client; | ||
440 | |||
441 | if (!atomic_add_unless(&sb->s_active, -1, 1)) { | ||
442 | rcu_read_lock(); | ||
443 | snprintf(buf, sizeof(buf), | ||
444 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR)); | ||
445 | rcu_read_unlock(); | ||
446 | |||
447 | __module_get(THIS_MODULE); | ||
448 | task = kthread_run(nfs_deactivate_super_async_work, sb, | ||
449 | "%s-deactivate-super", buf); | ||
450 | if (IS_ERR(task)) { | ||
451 | pr_err("%s: kthread_run: %ld\n", | ||
452 | __func__, PTR_ERR(task)); | ||
453 | /* make synchronous call and hope for the best */ | ||
454 | deactivate_super(sb); | ||
455 | module_put(THIS_MODULE); | ||
456 | } | ||
457 | } | ||
458 | } | ||
459 | |||
460 | void nfs_sb_deactive_async(struct super_block *sb) | ||
461 | { | ||
462 | struct nfs_server *server = NFS_SB(sb); | ||
463 | |||
464 | if (atomic_dec_and_test(&server->active)) | ||
465 | nfs_deactivate_super_async(sb); | ||
466 | } | ||
467 | EXPORT_SYMBOL_GPL(nfs_sb_deactive_async); | ||
468 | 447 | ||
469 | /* | 448 | /* |
470 | * Deliver file system statistics to userspace | 449 | * Deliver file system statistics to userspace |
471 | */ | 450 | */ |
472 | int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) | 451 | static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) |
473 | { | 452 | { |
474 | struct nfs_server *server = NFS_SB(dentry->d_sb); | 453 | struct nfs_server *server = NFS_SB(dentry->d_sb); |
475 | unsigned char blockbits; | 454 | unsigned char blockbits; |
@@ -530,7 +509,6 @@ int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
530 | dprintk("%s: statfs error = %d\n", __func__, -error); | 509 | dprintk("%s: statfs error = %d\n", __func__, -error); |
531 | return error; | 510 | return error; |
532 | } | 511 | } |
533 | EXPORT_SYMBOL_GPL(nfs_statfs); | ||
534 | 512 | ||
535 | /* | 513 | /* |
536 | * Map the security flavour number to a name | 514 | * Map the security flavour number to a name |
@@ -636,13 +614,14 @@ static void nfs_show_mountd_options(struct seq_file *m, struct nfs_server *nfss, | |||
636 | nfs_show_mountd_netid(m, nfss, showdefaults); | 614 | nfs_show_mountd_netid(m, nfss, showdefaults); |
637 | } | 615 | } |
638 | 616 | ||
639 | #if IS_ENABLED(CONFIG_NFS_V4) | 617 | #ifdef CONFIG_NFS_V4 |
640 | static void nfs_show_nfsv4_options(struct seq_file *m, struct nfs_server *nfss, | 618 | static void nfs_show_nfsv4_options(struct seq_file *m, struct nfs_server *nfss, |
641 | int showdefaults) | 619 | int showdefaults) |
642 | { | 620 | { |
643 | struct nfs_client *clp = nfss->nfs_client; | 621 | struct nfs_client *clp = nfss->nfs_client; |
644 | 622 | ||
645 | seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr); | 623 | seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr); |
624 | seq_printf(m, ",minorversion=%u", clp->cl_minorversion); | ||
646 | } | 625 | } |
647 | #else | 626 | #else |
648 | static void nfs_show_nfsv4_options(struct seq_file *m, struct nfs_server *nfss, | 627 | static void nfs_show_nfsv4_options(struct seq_file *m, struct nfs_server *nfss, |
@@ -651,15 +630,6 @@ static void nfs_show_nfsv4_options(struct seq_file *m, struct nfs_server *nfss, | |||
651 | } | 630 | } |
652 | #endif | 631 | #endif |
653 | 632 | ||
654 | static void nfs_show_nfs_version(struct seq_file *m, | ||
655 | unsigned int version, | ||
656 | unsigned int minorversion) | ||
657 | { | ||
658 | seq_printf(m, ",vers=%u", version); | ||
659 | if (version == 4) | ||
660 | seq_printf(m, ".%u", minorversion); | ||
661 | } | ||
662 | |||
663 | /* | 633 | /* |
664 | * Describe the mount options in force on this server representation | 634 | * Describe the mount options in force on this server representation |
665 | */ | 635 | */ |
@@ -687,7 +657,7 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
687 | u32 version = clp->rpc_ops->version; | 657 | u32 version = clp->rpc_ops->version; |
688 | int local_flock, local_fcntl; | 658 | int local_flock, local_fcntl; |
689 | 659 | ||
690 | nfs_show_nfs_version(m, version, clp->cl_minorversion); | 660 | seq_printf(m, ",vers=%u", version); |
691 | seq_printf(m, ",rsize=%u", nfss->rsize); | 661 | seq_printf(m, ",rsize=%u", nfss->rsize); |
692 | seq_printf(m, ",wsize=%u", nfss->wsize); | 662 | seq_printf(m, ",wsize=%u", nfss->wsize); |
693 | if (nfss->bsize != 0) | 663 | if (nfss->bsize != 0) |
@@ -707,10 +677,8 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
707 | else | 677 | else |
708 | seq_puts(m, nfs_infop->nostr); | 678 | seq_puts(m, nfs_infop->nostr); |
709 | } | 679 | } |
710 | rcu_read_lock(); | ||
711 | seq_printf(m, ",proto=%s", | 680 | seq_printf(m, ",proto=%s", |
712 | rpc_peeraddr2str(nfss->client, RPC_DISPLAY_NETID)); | 681 | rpc_peeraddr2str(nfss->client, RPC_DISPLAY_NETID)); |
713 | rcu_read_unlock(); | ||
714 | if (version == 4) { | 682 | if (version == 4) { |
715 | if (nfss->port != NFS_PORT) | 683 | if (nfss->port != NFS_PORT) |
716 | seq_printf(m, ",port=%u", nfss->port); | 684 | seq_printf(m, ",port=%u", nfss->port); |
@@ -730,9 +698,6 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
730 | if (nfss->options & NFS_OPTION_FSCACHE) | 698 | if (nfss->options & NFS_OPTION_FSCACHE) |
731 | seq_printf(m, ",fsc"); | 699 | seq_printf(m, ",fsc"); |
732 | 700 | ||
733 | if (nfss->options & NFS_OPTION_MIGRATION) | ||
734 | seq_printf(m, ",migration"); | ||
735 | |||
736 | if (nfss->flags & NFS_MOUNT_LOOKUP_CACHE_NONEG) { | 701 | if (nfss->flags & NFS_MOUNT_LOOKUP_CACHE_NONEG) { |
737 | if (nfss->flags & NFS_MOUNT_LOOKUP_CACHE_NONE) | 702 | if (nfss->flags & NFS_MOUNT_LOOKUP_CACHE_NONE) |
738 | seq_printf(m, ",lookupcache=none"); | 703 | seq_printf(m, ",lookupcache=none"); |
@@ -756,36 +721,30 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
756 | /* | 721 | /* |
757 | * Describe the mount options on this VFS mountpoint | 722 | * Describe the mount options on this VFS mountpoint |
758 | */ | 723 | */ |
759 | int nfs_show_options(struct seq_file *m, struct dentry *root) | 724 | static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) |
760 | { | 725 | { |
761 | struct nfs_server *nfss = NFS_SB(root->d_sb); | 726 | struct nfs_server *nfss = NFS_SB(mnt->mnt_sb); |
762 | 727 | ||
763 | nfs_show_mount_options(m, nfss, 0); | 728 | nfs_show_mount_options(m, nfss, 0); |
764 | 729 | ||
765 | rcu_read_lock(); | ||
766 | seq_printf(m, ",addr=%s", | 730 | seq_printf(m, ",addr=%s", |
767 | rpc_peeraddr2str(nfss->nfs_client->cl_rpcclient, | 731 | rpc_peeraddr2str(nfss->nfs_client->cl_rpcclient, |
768 | RPC_DISPLAY_ADDR)); | 732 | RPC_DISPLAY_ADDR)); |
769 | rcu_read_unlock(); | ||
770 | 733 | ||
771 | return 0; | 734 | return 0; |
772 | } | 735 | } |
773 | EXPORT_SYMBOL_GPL(nfs_show_options); | ||
774 | |||
775 | #if IS_ENABLED(CONFIG_NFS_V4) | ||
776 | #ifdef CONFIG_NFS_V4_1 | 736 | #ifdef CONFIG_NFS_V4_1 |
777 | static void show_sessions(struct seq_file *m, struct nfs_server *server) | 737 | void show_sessions(struct seq_file *m, struct nfs_server *server) |
778 | { | 738 | { |
779 | if (nfs4_has_session(server->nfs_client)) | 739 | if (nfs4_has_session(server->nfs_client)) |
780 | seq_printf(m, ",sessions"); | 740 | seq_printf(m, ",sessions"); |
781 | } | 741 | } |
782 | #else | 742 | #else |
783 | static void show_sessions(struct seq_file *m, struct nfs_server *server) {} | 743 | void show_sessions(struct seq_file *m, struct nfs_server *server) {} |
784 | #endif | ||
785 | #endif | 744 | #endif |
786 | 745 | ||
787 | #ifdef CONFIG_NFS_V4_1 | 746 | #ifdef CONFIG_NFS_V4_1 |
788 | static void show_pnfs(struct seq_file *m, struct nfs_server *server) | 747 | void show_pnfs(struct seq_file *m, struct nfs_server *server) |
789 | { | 748 | { |
790 | seq_printf(m, ",pnfs="); | 749 | seq_printf(m, ",pnfs="); |
791 | if (server->pnfs_curr_ld) | 750 | if (server->pnfs_curr_ld) |
@@ -793,36 +752,18 @@ static void show_pnfs(struct seq_file *m, struct nfs_server *server) | |||
793 | else | 752 | else |
794 | seq_printf(m, "not configured"); | 753 | seq_printf(m, "not configured"); |
795 | } | 754 | } |
755 | #else /* CONFIG_NFS_V4_1 */ | ||
756 | void show_pnfs(struct seq_file *m, struct nfs_server *server) {} | ||
757 | #endif /* CONFIG_NFS_V4_1 */ | ||
796 | 758 | ||
797 | static void show_implementation_id(struct seq_file *m, struct nfs_server *nfss) | 759 | static int nfs_show_devname(struct seq_file *m, struct vfsmount *mnt) |
798 | { | ||
799 | if (nfss->nfs_client && nfss->nfs_client->cl_implid) { | ||
800 | struct nfs41_impl_id *impl_id = nfss->nfs_client->cl_implid; | ||
801 | seq_printf(m, "\n\timpl_id:\tname='%s',domain='%s'," | ||
802 | "date='%llu,%u'", | ||
803 | impl_id->name, impl_id->domain, | ||
804 | impl_id->date.seconds, impl_id->date.nseconds); | ||
805 | } | ||
806 | } | ||
807 | #else | ||
808 | #if IS_ENABLED(CONFIG_NFS_V4) | ||
809 | static void show_pnfs(struct seq_file *m, struct nfs_server *server) | ||
810 | { | ||
811 | } | ||
812 | #endif | ||
813 | static void show_implementation_id(struct seq_file *m, struct nfs_server *nfss) | ||
814 | { | ||
815 | } | ||
816 | #endif | ||
817 | |||
818 | int nfs_show_devname(struct seq_file *m, struct dentry *root) | ||
819 | { | 760 | { |
820 | char *page = (char *) __get_free_page(GFP_KERNEL); | 761 | char *page = (char *) __get_free_page(GFP_KERNEL); |
821 | char *devname, *dummy; | 762 | char *devname, *dummy; |
822 | int err = 0; | 763 | int err = 0; |
823 | if (!page) | 764 | if (!page) |
824 | return -ENOMEM; | 765 | return -ENOMEM; |
825 | devname = nfs_path(&dummy, root, page, PAGE_SIZE, 0); | 766 | devname = nfs_path(&dummy, mnt->mnt_root, page, PAGE_SIZE); |
826 | if (IS_ERR(devname)) | 767 | if (IS_ERR(devname)) |
827 | err = PTR_ERR(devname); | 768 | err = PTR_ERR(devname); |
828 | else | 769 | else |
@@ -830,22 +771,20 @@ int nfs_show_devname(struct seq_file *m, struct dentry *root) | |||
830 | free_page((unsigned long)page); | 771 | free_page((unsigned long)page); |
831 | return err; | 772 | return err; |
832 | } | 773 | } |
833 | EXPORT_SYMBOL_GPL(nfs_show_devname); | ||
834 | 774 | ||
835 | int nfs_show_path(struct seq_file *m, struct dentry *dentry) | 775 | static int nfs_show_path(struct seq_file *m, struct vfsmount *mnt) |
836 | { | 776 | { |
837 | seq_puts(m, "/"); | 777 | seq_puts(m, "/"); |
838 | return 0; | 778 | return 0; |
839 | } | 779 | } |
840 | EXPORT_SYMBOL_GPL(nfs_show_path); | ||
841 | 780 | ||
842 | /* | 781 | /* |
843 | * Present statistical information for this VFS mountpoint | 782 | * Present statistical information for this VFS mountpoint |
844 | */ | 783 | */ |
845 | int nfs_show_stats(struct seq_file *m, struct dentry *root) | 784 | static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt) |
846 | { | 785 | { |
847 | int i, cpu; | 786 | int i, cpu; |
848 | struct nfs_server *nfss = NFS_SB(root->d_sb); | 787 | struct nfs_server *nfss = NFS_SB(mnt->mnt_sb); |
849 | struct rpc_auth *auth = nfss->client->cl_auth; | 788 | struct rpc_auth *auth = nfss->client->cl_auth; |
850 | struct nfs_iostats totals = { }; | 789 | struct nfs_iostats totals = { }; |
851 | 790 | ||
@@ -855,16 +794,14 @@ int nfs_show_stats(struct seq_file *m, struct dentry *root) | |||
855 | * Display all mount option settings | 794 | * Display all mount option settings |
856 | */ | 795 | */ |
857 | seq_printf(m, "\n\topts:\t"); | 796 | seq_printf(m, "\n\topts:\t"); |
858 | seq_puts(m, root->d_sb->s_flags & MS_RDONLY ? "ro" : "rw"); | 797 | seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? "ro" : "rw"); |
859 | seq_puts(m, root->d_sb->s_flags & MS_SYNCHRONOUS ? ",sync" : ""); | 798 | seq_puts(m, mnt->mnt_sb->s_flags & MS_SYNCHRONOUS ? ",sync" : ""); |
860 | seq_puts(m, root->d_sb->s_flags & MS_NOATIME ? ",noatime" : ""); | 799 | seq_puts(m, mnt->mnt_sb->s_flags & MS_NOATIME ? ",noatime" : ""); |
861 | seq_puts(m, root->d_sb->s_flags & MS_NODIRATIME ? ",nodiratime" : ""); | 800 | seq_puts(m, mnt->mnt_sb->s_flags & MS_NODIRATIME ? ",nodiratime" : ""); |
862 | nfs_show_mount_options(m, nfss, 1); | 801 | nfs_show_mount_options(m, nfss, 1); |
863 | 802 | ||
864 | seq_printf(m, "\n\tage:\t%lu", (jiffies - nfss->mount_time) / HZ); | 803 | seq_printf(m, "\n\tage:\t%lu", (jiffies - nfss->mount_time) / HZ); |
865 | 804 | ||
866 | show_implementation_id(m, nfss); | ||
867 | |||
868 | seq_printf(m, "\n\tcaps:\t"); | 805 | seq_printf(m, "\n\tcaps:\t"); |
869 | seq_printf(m, "caps=0x%x", nfss->caps); | 806 | seq_printf(m, "caps=0x%x", nfss->caps); |
870 | seq_printf(m, ",wtmult=%u", nfss->wtmult); | 807 | seq_printf(m, ",wtmult=%u", nfss->wtmult); |
@@ -872,7 +809,7 @@ int nfs_show_stats(struct seq_file *m, struct dentry *root) | |||
872 | seq_printf(m, ",bsize=%u", nfss->bsize); | 809 | seq_printf(m, ",bsize=%u", nfss->bsize); |
873 | seq_printf(m, ",namlen=%u", nfss->namelen); | 810 | seq_printf(m, ",namlen=%u", nfss->namelen); |
874 | 811 | ||
875 | #if IS_ENABLED(CONFIG_NFS_V4) | 812 | #ifdef CONFIG_NFS_V4 |
876 | if (nfss->nfs_client->rpc_ops->version == 4) { | 813 | if (nfss->nfs_client->rpc_ops->version == 4) { |
877 | seq_printf(m, "\n\tnfsv4:\t"); | 814 | seq_printf(m, "\n\tnfsv4:\t"); |
878 | seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]); | 815 | seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]); |
@@ -930,13 +867,12 @@ int nfs_show_stats(struct seq_file *m, struct dentry *root) | |||
930 | 867 | ||
931 | return 0; | 868 | return 0; |
932 | } | 869 | } |
933 | EXPORT_SYMBOL_GPL(nfs_show_stats); | ||
934 | 870 | ||
935 | /* | 871 | /* |
936 | * Begin unmount by attempting to remove all automounted mountpoints we added | 872 | * Begin unmount by attempting to remove all automounted mountpoints we added |
937 | * in response to xdev traversals and referrals | 873 | * in response to xdev traversals and referrals |
938 | */ | 874 | */ |
939 | void nfs_umount_begin(struct super_block *sb) | 875 | static void nfs_umount_begin(struct super_block *sb) |
940 | { | 876 | { |
941 | struct nfs_server *server; | 877 | struct nfs_server *server; |
942 | struct rpc_clnt *rpc; | 878 | struct rpc_clnt *rpc; |
@@ -950,9 +886,8 @@ void nfs_umount_begin(struct super_block *sb) | |||
950 | if (!IS_ERR(rpc)) | 886 | if (!IS_ERR(rpc)) |
951 | rpc_killall_tasks(rpc); | 887 | rpc_killall_tasks(rpc); |
952 | } | 888 | } |
953 | EXPORT_SYMBOL_GPL(nfs_umount_begin); | ||
954 | 889 | ||
955 | static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void) | 890 | static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(unsigned int version) |
956 | { | 891 | { |
957 | struct nfs_parsed_mount_data *data; | 892 | struct nfs_parsed_mount_data *data; |
958 | 893 | ||
@@ -967,9 +902,8 @@ static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void) | |||
967 | data->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 902 | data->nfs_server.protocol = XPRT_TRANSPORT_TCP; |
968 | data->auth_flavors[0] = RPC_AUTH_UNIX; | 903 | data->auth_flavors[0] = RPC_AUTH_UNIX; |
969 | data->auth_flavor_len = 1; | 904 | data->auth_flavor_len = 1; |
905 | data->version = version; | ||
970 | data->minorversion = 0; | 906 | data->minorversion = 0; |
971 | data->need_mount = true; | ||
972 | data->net = current->nsproxy->net_ns; | ||
973 | security_init_mnt_opts(&data->lsm_opts); | 907 | security_init_mnt_opts(&data->lsm_opts); |
974 | } | 908 | } |
975 | return data; | 909 | return data; |
@@ -1114,45 +1048,11 @@ static int nfs_parse_security_flavors(char *value, | |||
1114 | return 1; | 1048 | return 1; |
1115 | } | 1049 | } |
1116 | 1050 | ||
1117 | static int nfs_parse_version_string(char *string, | ||
1118 | struct nfs_parsed_mount_data *mnt, | ||
1119 | substring_t *args) | ||
1120 | { | ||
1121 | mnt->flags &= ~NFS_MOUNT_VER3; | ||
1122 | switch (match_token(string, nfs_vers_tokens, args)) { | ||
1123 | case Opt_vers_2: | ||
1124 | mnt->version = 2; | ||
1125 | break; | ||
1126 | case Opt_vers_3: | ||
1127 | mnt->flags |= NFS_MOUNT_VER3; | ||
1128 | mnt->version = 3; | ||
1129 | break; | ||
1130 | case Opt_vers_4: | ||
1131 | /* Backward compatibility option. In future, | ||
1132 | * the mount program should always supply | ||
1133 | * a NFSv4 minor version number. | ||
1134 | */ | ||
1135 | mnt->version = 4; | ||
1136 | break; | ||
1137 | case Opt_vers_4_0: | ||
1138 | mnt->version = 4; | ||
1139 | mnt->minorversion = 0; | ||
1140 | break; | ||
1141 | case Opt_vers_4_1: | ||
1142 | mnt->version = 4; | ||
1143 | mnt->minorversion = 1; | ||
1144 | break; | ||
1145 | default: | ||
1146 | return 0; | ||
1147 | } | ||
1148 | return 1; | ||
1149 | } | ||
1150 | |||
1151 | static int nfs_get_option_str(substring_t args[], char **option) | 1051 | static int nfs_get_option_str(substring_t args[], char **option) |
1152 | { | 1052 | { |
1153 | kfree(*option); | 1053 | kfree(*option); |
1154 | *option = match_strdup(args); | 1054 | *option = match_strdup(args); |
1155 | return !*option; | 1055 | return !option; |
1156 | } | 1056 | } |
1157 | 1057 | ||
1158 | static int nfs_get_option_ul(substring_t args[], unsigned long *option) | 1058 | static int nfs_get_option_ul(substring_t args[], unsigned long *option) |
@@ -1163,7 +1063,7 @@ static int nfs_get_option_ul(substring_t args[], unsigned long *option) | |||
1163 | string = match_strdup(args); | 1063 | string = match_strdup(args); |
1164 | if (string == NULL) | 1064 | if (string == NULL) |
1165 | return -ENOMEM; | 1065 | return -ENOMEM; |
1166 | rc = kstrtoul(string, 10, option); | 1066 | rc = strict_strtoul(string, 10, option); |
1167 | kfree(string); | 1067 | kfree(string); |
1168 | 1068 | ||
1169 | return rc; | 1069 | return rc; |
@@ -1253,6 +1153,18 @@ static int nfs_parse_mount_options(char *raw, | |||
1253 | mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK | | 1153 | mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK | |
1254 | NFS_MOUNT_LOCAL_FCNTL); | 1154 | NFS_MOUNT_LOCAL_FCNTL); |
1255 | break; | 1155 | break; |
1156 | case Opt_v2: | ||
1157 | mnt->flags &= ~NFS_MOUNT_VER3; | ||
1158 | mnt->version = 2; | ||
1159 | break; | ||
1160 | case Opt_v3: | ||
1161 | mnt->flags |= NFS_MOUNT_VER3; | ||
1162 | mnt->version = 3; | ||
1163 | break; | ||
1164 | case Opt_v4: | ||
1165 | mnt->flags &= ~NFS_MOUNT_VER3; | ||
1166 | mnt->version = 4; | ||
1167 | break; | ||
1256 | case Opt_udp: | 1168 | case Opt_udp: |
1257 | mnt->flags &= ~NFS_MOUNT_TCP; | 1169 | mnt->flags &= ~NFS_MOUNT_TCP; |
1258 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; | 1170 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; |
@@ -1300,12 +1212,6 @@ static int nfs_parse_mount_options(char *raw, | |||
1300 | kfree(mnt->fscache_uniq); | 1212 | kfree(mnt->fscache_uniq); |
1301 | mnt->fscache_uniq = NULL; | 1213 | mnt->fscache_uniq = NULL; |
1302 | break; | 1214 | break; |
1303 | case Opt_migration: | ||
1304 | mnt->options |= NFS_OPTION_MIGRATION; | ||
1305 | break; | ||
1306 | case Opt_nomigration: | ||
1307 | mnt->options &= NFS_OPTION_MIGRATION; | ||
1308 | break; | ||
1309 | 1215 | ||
1310 | /* | 1216 | /* |
1311 | * options that take numeric values | 1217 | * options that take numeric values |
@@ -1385,6 +1291,26 @@ static int nfs_parse_mount_options(char *raw, | |||
1385 | goto out_invalid_value; | 1291 | goto out_invalid_value; |
1386 | mnt->mount_server.version = option; | 1292 | mnt->mount_server.version = option; |
1387 | break; | 1293 | break; |
1294 | case Opt_nfsvers: | ||
1295 | if (nfs_get_option_ul(args, &option)) | ||
1296 | goto out_invalid_value; | ||
1297 | switch (option) { | ||
1298 | case NFS2_VERSION: | ||
1299 | mnt->flags &= ~NFS_MOUNT_VER3; | ||
1300 | mnt->version = 2; | ||
1301 | break; | ||
1302 | case NFS3_VERSION: | ||
1303 | mnt->flags |= NFS_MOUNT_VER3; | ||
1304 | mnt->version = 3; | ||
1305 | break; | ||
1306 | case NFS4_VERSION: | ||
1307 | mnt->flags &= ~NFS_MOUNT_VER3; | ||
1308 | mnt->version = 4; | ||
1309 | break; | ||
1310 | default: | ||
1311 | goto out_invalid_value; | ||
1312 | } | ||
1313 | break; | ||
1388 | case Opt_minorversion: | 1314 | case Opt_minorversion: |
1389 | if (nfs_get_option_ul(args, &option)) | 1315 | if (nfs_get_option_ul(args, &option)) |
1390 | goto out_invalid_value; | 1316 | goto out_invalid_value; |
@@ -1396,15 +1322,6 @@ static int nfs_parse_mount_options(char *raw, | |||
1396 | /* | 1322 | /* |
1397 | * options that take text values | 1323 | * options that take text values |
1398 | */ | 1324 | */ |
1399 | case Opt_nfsvers: | ||
1400 | string = match_strdup(args); | ||
1401 | if (string == NULL) | ||
1402 | goto out_nomem; | ||
1403 | rc = nfs_parse_version_string(string, mnt, args); | ||
1404 | kfree(string); | ||
1405 | if (!rc) | ||
1406 | goto out_invalid_value; | ||
1407 | break; | ||
1408 | case Opt_sec: | 1325 | case Opt_sec: |
1409 | string = match_strdup(args); | 1326 | string = match_strdup(args); |
1410 | if (string == NULL) | 1327 | if (string == NULL) |
@@ -1484,7 +1401,7 @@ static int nfs_parse_mount_options(char *raw, | |||
1484 | if (string == NULL) | 1401 | if (string == NULL) |
1485 | goto out_nomem; | 1402 | goto out_nomem; |
1486 | mnt->nfs_server.addrlen = | 1403 | mnt->nfs_server.addrlen = |
1487 | rpc_pton(mnt->net, string, strlen(string), | 1404 | rpc_pton(string, strlen(string), |
1488 | (struct sockaddr *) | 1405 | (struct sockaddr *) |
1489 | &mnt->nfs_server.address, | 1406 | &mnt->nfs_server.address, |
1490 | sizeof(mnt->nfs_server.address)); | 1407 | sizeof(mnt->nfs_server.address)); |
@@ -1506,7 +1423,7 @@ static int nfs_parse_mount_options(char *raw, | |||
1506 | if (string == NULL) | 1423 | if (string == NULL) |
1507 | goto out_nomem; | 1424 | goto out_nomem; |
1508 | mnt->mount_server.addrlen = | 1425 | mnt->mount_server.addrlen = |
1509 | rpc_pton(mnt->net, string, strlen(string), | 1426 | rpc_pton(string, strlen(string), |
1510 | (struct sockaddr *) | 1427 | (struct sockaddr *) |
1511 | &mnt->mount_server.address, | 1428 | &mnt->mount_server.address, |
1512 | sizeof(mnt->mount_server.address)); | 1429 | sizeof(mnt->mount_server.address)); |
@@ -1595,16 +1512,9 @@ static int nfs_parse_mount_options(char *raw, | |||
1595 | if (!sloppy && invalid_option) | 1512 | if (!sloppy && invalid_option) |
1596 | return 0; | 1513 | return 0; |
1597 | 1514 | ||
1598 | if (mnt->minorversion && mnt->version != 4) | ||
1599 | goto out_minorversion_mismatch; | ||
1600 | |||
1601 | if (mnt->options & NFS_OPTION_MIGRATION && | ||
1602 | mnt->version != 4 && mnt->minorversion != 0) | ||
1603 | goto out_migration_misuse; | ||
1604 | |||
1605 | /* | 1515 | /* |
1606 | * verify that any proto=/mountproto= options match the address | 1516 | * verify that any proto=/mountproto= options match the address |
1607 | * families in the addr=/mountaddr= options. | 1517 | * familiies in the addr=/mountaddr= options. |
1608 | */ | 1518 | */ |
1609 | if (protofamily != AF_UNSPEC && | 1519 | if (protofamily != AF_UNSPEC && |
1610 | protofamily != mnt->nfs_server.address.ss_family) | 1520 | protofamily != mnt->nfs_server.address.ss_family) |
@@ -1635,14 +1545,6 @@ out_invalid_address: | |||
1635 | out_invalid_value: | 1545 | out_invalid_value: |
1636 | printk(KERN_INFO "NFS: bad mount option value specified: %s\n", p); | 1546 | printk(KERN_INFO "NFS: bad mount option value specified: %s\n", p); |
1637 | return 0; | 1547 | return 0; |
1638 | out_minorversion_mismatch: | ||
1639 | printk(KERN_INFO "NFS: mount option vers=%u does not support " | ||
1640 | "minorversion=%u\n", mnt->version, mnt->minorversion); | ||
1641 | return 0; | ||
1642 | out_migration_misuse: | ||
1643 | printk(KERN_INFO | ||
1644 | "NFS: 'migration' not supported for this NFS version\n"); | ||
1645 | return 0; | ||
1646 | out_nomem: | 1548 | out_nomem: |
1647 | printk(KERN_INFO "NFS: not enough memory to parse option\n"); | 1549 | printk(KERN_INFO "NFS: not enough memory to parse option\n"); |
1648 | return 0; | 1550 | return 0; |
@@ -1702,8 +1604,8 @@ static int nfs_walk_authlist(struct nfs_parsed_mount_data *args, | |||
1702 | * Use the remote server's MOUNT service to request the NFS file handle | 1604 | * Use the remote server's MOUNT service to request the NFS file handle |
1703 | * corresponding to the provided path. | 1605 | * corresponding to the provided path. |
1704 | */ | 1606 | */ |
1705 | static int nfs_request_mount(struct nfs_parsed_mount_data *args, | 1607 | static int nfs_try_mount(struct nfs_parsed_mount_data *args, |
1706 | struct nfs_fh *root_fh) | 1608 | struct nfs_fh *root_fh) |
1707 | { | 1609 | { |
1708 | rpc_authflavor_t server_authlist[NFS_MAX_SECFLAVORS]; | 1610 | rpc_authflavor_t server_authlist[NFS_MAX_SECFLAVORS]; |
1709 | unsigned int server_authlist_len = ARRAY_SIZE(server_authlist); | 1611 | unsigned int server_authlist_len = ARRAY_SIZE(server_authlist); |
@@ -1716,7 +1618,6 @@ static int nfs_request_mount(struct nfs_parsed_mount_data *args, | |||
1716 | .noresvport = args->flags & NFS_MOUNT_NORESVPORT, | 1618 | .noresvport = args->flags & NFS_MOUNT_NORESVPORT, |
1717 | .auth_flav_len = &server_authlist_len, | 1619 | .auth_flav_len = &server_authlist_len, |
1718 | .auth_flavs = server_authlist, | 1620 | .auth_flavs = server_authlist, |
1719 | .net = args->net, | ||
1720 | }; | 1621 | }; |
1721 | int status; | 1622 | int status; |
1722 | 1623 | ||
@@ -1766,28 +1667,6 @@ static int nfs_request_mount(struct nfs_parsed_mount_data *args, | |||
1766 | return nfs_walk_authlist(args, &request); | 1667 | return nfs_walk_authlist(args, &request); |
1767 | } | 1668 | } |
1768 | 1669 | ||
1769 | struct dentry *nfs_try_mount(int flags, const char *dev_name, | ||
1770 | struct nfs_mount_info *mount_info, | ||
1771 | struct nfs_subversion *nfs_mod) | ||
1772 | { | ||
1773 | int status; | ||
1774 | struct nfs_server *server; | ||
1775 | |||
1776 | if (mount_info->parsed->need_mount) { | ||
1777 | status = nfs_request_mount(mount_info->parsed, mount_info->mntfh); | ||
1778 | if (status) | ||
1779 | return ERR_PTR(status); | ||
1780 | } | ||
1781 | |||
1782 | /* Get a volume representation */ | ||
1783 | server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod); | ||
1784 | if (IS_ERR(server)) | ||
1785 | return ERR_CAST(server); | ||
1786 | |||
1787 | return nfs_fs_mount_common(server, flags, dev_name, mount_info, nfs_mod); | ||
1788 | } | ||
1789 | EXPORT_SYMBOL_GPL(nfs_try_mount); | ||
1790 | |||
1791 | /* | 1670 | /* |
1792 | * Split "dev_name" into "hostname:export_path". | 1671 | * Split "dev_name" into "hostname:export_path". |
1793 | * | 1672 | * |
@@ -1876,10 +1755,10 @@ out_path: | |||
1876 | * + breaking back: trying proto=udp after proto=tcp, v2 after v3, | 1755 | * + breaking back: trying proto=udp after proto=tcp, v2 after v3, |
1877 | * mountproto=tcp after mountproto=udp, and so on | 1756 | * mountproto=tcp after mountproto=udp, and so on |
1878 | */ | 1757 | */ |
1879 | static int nfs23_validate_mount_data(void *options, | 1758 | static int nfs_validate_mount_data(void *options, |
1880 | struct nfs_parsed_mount_data *args, | 1759 | struct nfs_parsed_mount_data *args, |
1881 | struct nfs_fh *mntfh, | 1760 | struct nfs_fh *mntfh, |
1882 | const char *dev_name) | 1761 | const char *dev_name) |
1883 | { | 1762 | { |
1884 | struct nfs_mount_data *data = (struct nfs_mount_data *)options; | 1763 | struct nfs_mount_data *data = (struct nfs_mount_data *)options; |
1885 | struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address; | 1764 | struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address; |
@@ -1887,7 +1766,6 @@ static int nfs23_validate_mount_data(void *options, | |||
1887 | if (data == NULL) | 1766 | if (data == NULL) |
1888 | goto out_no_data; | 1767 | goto out_no_data; |
1889 | 1768 | ||
1890 | args->version = NFS_DEFAULT_VERSION; | ||
1891 | switch (data->version) { | 1769 | switch (data->version) { |
1892 | case 1: | 1770 | case 1: |
1893 | data->namlen = 0; | 1771 | data->namlen = 0; |
@@ -1934,11 +1812,9 @@ static int nfs23_validate_mount_data(void *options, | |||
1934 | args->acregmax = data->acregmax; | 1812 | args->acregmax = data->acregmax; |
1935 | args->acdirmin = data->acdirmin; | 1813 | args->acdirmin = data->acdirmin; |
1936 | args->acdirmax = data->acdirmax; | 1814 | args->acdirmax = data->acdirmax; |
1937 | args->need_mount = false; | ||
1938 | 1815 | ||
1939 | memcpy(sap, &data->addr, sizeof(data->addr)); | 1816 | memcpy(sap, &data->addr, sizeof(data->addr)); |
1940 | args->nfs_server.addrlen = sizeof(data->addr); | 1817 | args->nfs_server.addrlen = sizeof(data->addr); |
1941 | args->nfs_server.port = ntohs(data->addr.sin_port); | ||
1942 | if (!nfs_verify_server_address(sap)) | 1818 | if (!nfs_verify_server_address(sap)) |
1943 | goto out_no_address; | 1819 | goto out_no_address; |
1944 | 1820 | ||
@@ -1987,11 +1863,46 @@ static int nfs23_validate_mount_data(void *options, | |||
1987 | } | 1863 | } |
1988 | 1864 | ||
1989 | break; | 1865 | break; |
1990 | default: | 1866 | default: { |
1991 | return NFS_TEXT_DATA; | 1867 | int status; |
1868 | |||
1869 | if (nfs_parse_mount_options((char *)options, args) == 0) | ||
1870 | return -EINVAL; | ||
1871 | |||
1872 | if (!nfs_verify_server_address(sap)) | ||
1873 | goto out_no_address; | ||
1874 | |||
1875 | if (args->version == 4) | ||
1876 | #ifdef CONFIG_NFS_V4 | ||
1877 | return nfs4_validate_text_mount_data(options, | ||
1878 | args, dev_name); | ||
1879 | #else | ||
1880 | goto out_v4_not_compiled; | ||
1881 | #endif | ||
1882 | |||
1883 | nfs_set_port(sap, &args->nfs_server.port, 0); | ||
1884 | |||
1885 | nfs_set_mount_transport_protocol(args); | ||
1886 | |||
1887 | status = nfs_parse_devname(dev_name, | ||
1888 | &args->nfs_server.hostname, | ||
1889 | PAGE_SIZE, | ||
1890 | &args->nfs_server.export_path, | ||
1891 | NFS_MAXPATHLEN); | ||
1892 | if (!status) | ||
1893 | status = nfs_try_mount(args, mntfh); | ||
1894 | |||
1895 | kfree(args->nfs_server.export_path); | ||
1896 | args->nfs_server.export_path = NULL; | ||
1897 | |||
1898 | if (status) | ||
1899 | return status; | ||
1900 | |||
1901 | break; | ||
1902 | } | ||
1992 | } | 1903 | } |
1993 | 1904 | ||
1994 | #if !IS_ENABLED(CONFIG_NFS_V3) | 1905 | #ifndef CONFIG_NFS_V3 |
1995 | if (args->version == 3) | 1906 | if (args->version == 3) |
1996 | goto out_v3_not_compiled; | 1907 | goto out_v3_not_compiled; |
1997 | #endif /* !CONFIG_NFS_V3 */ | 1908 | #endif /* !CONFIG_NFS_V3 */ |
@@ -2011,12 +1922,18 @@ out_no_sec: | |||
2011 | dfprintk(MOUNT, "NFS: nfs_mount_data version supports only AUTH_SYS\n"); | 1922 | dfprintk(MOUNT, "NFS: nfs_mount_data version supports only AUTH_SYS\n"); |
2012 | return -EINVAL; | 1923 | return -EINVAL; |
2013 | 1924 | ||
2014 | #if !IS_ENABLED(CONFIG_NFS_V3) | 1925 | #ifndef CONFIG_NFS_V3 |
2015 | out_v3_not_compiled: | 1926 | out_v3_not_compiled: |
2016 | dfprintk(MOUNT, "NFS: NFSv3 is not compiled into kernel\n"); | 1927 | dfprintk(MOUNT, "NFS: NFSv3 is not compiled into kernel\n"); |
2017 | return -EPROTONOSUPPORT; | 1928 | return -EPROTONOSUPPORT; |
2018 | #endif /* !CONFIG_NFS_V3 */ | 1929 | #endif /* !CONFIG_NFS_V3 */ |
2019 | 1930 | ||
1931 | #ifndef CONFIG_NFS_V4 | ||
1932 | out_v4_not_compiled: | ||
1933 | dfprintk(MOUNT, "NFS: NFSv4 is not compiled into kernel\n"); | ||
1934 | return -EPROTONOSUPPORT; | ||
1935 | #endif /* !CONFIG_NFS_V4 */ | ||
1936 | |||
2020 | out_nomem: | 1937 | out_nomem: |
2021 | dfprintk(MOUNT, "NFS: not enough memory to handle mount options\n"); | 1938 | dfprintk(MOUNT, "NFS: not enough memory to handle mount options\n"); |
2022 | return -ENOMEM; | 1939 | return -ENOMEM; |
@@ -2030,82 +1947,6 @@ out_invalid_fh: | |||
2030 | return -EINVAL; | 1947 | return -EINVAL; |
2031 | } | 1948 | } |
2032 | 1949 | ||
2033 | #if IS_ENABLED(CONFIG_NFS_V4) | ||
2034 | static int nfs_validate_mount_data(struct file_system_type *fs_type, | ||
2035 | void *options, | ||
2036 | struct nfs_parsed_mount_data *args, | ||
2037 | struct nfs_fh *mntfh, | ||
2038 | const char *dev_name) | ||
2039 | { | ||
2040 | if (fs_type == &nfs_fs_type) | ||
2041 | return nfs23_validate_mount_data(options, args, mntfh, dev_name); | ||
2042 | return nfs4_validate_mount_data(options, args, dev_name); | ||
2043 | } | ||
2044 | #else | ||
2045 | static int nfs_validate_mount_data(struct file_system_type *fs_type, | ||
2046 | void *options, | ||
2047 | struct nfs_parsed_mount_data *args, | ||
2048 | struct nfs_fh *mntfh, | ||
2049 | const char *dev_name) | ||
2050 | { | ||
2051 | return nfs23_validate_mount_data(options, args, mntfh, dev_name); | ||
2052 | } | ||
2053 | #endif | ||
2054 | |||
2055 | static int nfs_validate_text_mount_data(void *options, | ||
2056 | struct nfs_parsed_mount_data *args, | ||
2057 | const char *dev_name) | ||
2058 | { | ||
2059 | int port = 0; | ||
2060 | int max_namelen = PAGE_SIZE; | ||
2061 | int max_pathlen = NFS_MAXPATHLEN; | ||
2062 | struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address; | ||
2063 | |||
2064 | if (nfs_parse_mount_options((char *)options, args) == 0) | ||
2065 | return -EINVAL; | ||
2066 | |||
2067 | if (!nfs_verify_server_address(sap)) | ||
2068 | goto out_no_address; | ||
2069 | |||
2070 | if (args->version == 4) { | ||
2071 | #if IS_ENABLED(CONFIG_NFS_V4) | ||
2072 | port = NFS_PORT; | ||
2073 | max_namelen = NFS4_MAXNAMLEN; | ||
2074 | max_pathlen = NFS4_MAXPATHLEN; | ||
2075 | nfs_validate_transport_protocol(args); | ||
2076 | nfs4_validate_mount_flags(args); | ||
2077 | #else | ||
2078 | goto out_v4_not_compiled; | ||
2079 | #endif /* CONFIG_NFS_V4 */ | ||
2080 | } else | ||
2081 | nfs_set_mount_transport_protocol(args); | ||
2082 | |||
2083 | nfs_set_port(sap, &args->nfs_server.port, port); | ||
2084 | |||
2085 | if (args->auth_flavor_len > 1) | ||
2086 | goto out_bad_auth; | ||
2087 | |||
2088 | return nfs_parse_devname(dev_name, | ||
2089 | &args->nfs_server.hostname, | ||
2090 | max_namelen, | ||
2091 | &args->nfs_server.export_path, | ||
2092 | max_pathlen); | ||
2093 | |||
2094 | #if !IS_ENABLED(CONFIG_NFS_V4) | ||
2095 | out_v4_not_compiled: | ||
2096 | dfprintk(MOUNT, "NFS: NFSv4 is not compiled into kernel\n"); | ||
2097 | return -EPROTONOSUPPORT; | ||
2098 | #endif /* !CONFIG_NFS_V4 */ | ||
2099 | |||
2100 | out_no_address: | ||
2101 | dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n"); | ||
2102 | return -EINVAL; | ||
2103 | |||
2104 | out_bad_auth: | ||
2105 | dfprintk(MOUNT, "NFS: Too many RPC auth flavours specified\n"); | ||
2106 | return -EINVAL; | ||
2107 | } | ||
2108 | |||
2109 | static int | 1950 | static int |
2110 | nfs_compare_remount_data(struct nfs_server *nfss, | 1951 | nfs_compare_remount_data(struct nfs_server *nfss, |
2111 | struct nfs_parsed_mount_data *data) | 1952 | struct nfs_parsed_mount_data *data) |
@@ -2129,7 +1970,7 @@ nfs_compare_remount_data(struct nfs_server *nfss, | |||
2129 | return 0; | 1970 | return 0; |
2130 | } | 1971 | } |
2131 | 1972 | ||
2132 | int | 1973 | static int |
2133 | nfs_remount(struct super_block *sb, int *flags, char *raw_data) | 1974 | nfs_remount(struct super_block *sb, int *flags, char *raw_data) |
2134 | { | 1975 | { |
2135 | int error; | 1976 | int error; |
@@ -2190,12 +2031,11 @@ out: | |||
2190 | kfree(data); | 2031 | kfree(data); |
2191 | return error; | 2032 | return error; |
2192 | } | 2033 | } |
2193 | EXPORT_SYMBOL_GPL(nfs_remount); | ||
2194 | 2034 | ||
2195 | /* | 2035 | /* |
2196 | * Initialise the common bits of the superblock | 2036 | * Initialise the common bits of the superblock |
2197 | */ | 2037 | */ |
2198 | inline void nfs_initialise_sb(struct super_block *sb) | 2038 | static inline void nfs_initialise_sb(struct super_block *sb) |
2199 | { | 2039 | { |
2200 | struct nfs_server *server = NFS_SB(sb); | 2040 | struct nfs_server *server = NFS_SB(sb); |
2201 | 2041 | ||
@@ -2203,7 +2043,7 @@ inline void nfs_initialise_sb(struct super_block *sb) | |||
2203 | 2043 | ||
2204 | /* We probably want something more informative here */ | 2044 | /* We probably want something more informative here */ |
2205 | snprintf(sb->s_id, sizeof(sb->s_id), | 2045 | snprintf(sb->s_id, sizeof(sb->s_id), |
2206 | "%u:%u", MAJOR(sb->s_dev), MINOR(sb->s_dev)); | 2046 | "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev)); |
2207 | 2047 | ||
2208 | if (sb->s_blocksize == 0) | 2048 | if (sb->s_blocksize == 0) |
2209 | sb->s_blocksize = nfs_block_bits(server->wsize, | 2049 | sb->s_blocksize = nfs_block_bits(server->wsize, |
@@ -2217,19 +2057,17 @@ inline void nfs_initialise_sb(struct super_block *sb) | |||
2217 | /* | 2057 | /* |
2218 | * Finish setting up an NFS2/3 superblock | 2058 | * Finish setting up an NFS2/3 superblock |
2219 | */ | 2059 | */ |
2220 | void nfs_fill_super(struct super_block *sb, struct nfs_mount_info *mount_info) | 2060 | static void nfs_fill_super(struct super_block *sb, |
2061 | struct nfs_parsed_mount_data *data) | ||
2221 | { | 2062 | { |
2222 | struct nfs_parsed_mount_data *data = mount_info->parsed; | ||
2223 | struct nfs_server *server = NFS_SB(sb); | 2063 | struct nfs_server *server = NFS_SB(sb); |
2224 | 2064 | ||
2225 | sb->s_blocksize_bits = 0; | 2065 | sb->s_blocksize_bits = 0; |
2226 | sb->s_blocksize = 0; | 2066 | sb->s_blocksize = 0; |
2227 | sb->s_xattr = server->nfs_client->cl_nfs_mod->xattr; | 2067 | if (data->bsize) |
2228 | sb->s_op = server->nfs_client->cl_nfs_mod->sops; | ||
2229 | if (data && data->bsize) | ||
2230 | sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits); | 2068 | sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits); |
2231 | 2069 | ||
2232 | if (server->nfs_client->rpc_ops->version != 2) { | 2070 | if (server->nfs_client->rpc_ops->version == 3) { |
2233 | /* The VFS shouldn't apply the umask to mode bits. We will do | 2071 | /* The VFS shouldn't apply the umask to mode bits. We will do |
2234 | * so ourselves when necessary. | 2072 | * so ourselves when necessary. |
2235 | */ | 2073 | */ |
@@ -2237,32 +2075,31 @@ void nfs_fill_super(struct super_block *sb, struct nfs_mount_info *mount_info) | |||
2237 | sb->s_time_gran = 1; | 2075 | sb->s_time_gran = 1; |
2238 | } | 2076 | } |
2239 | 2077 | ||
2078 | sb->s_op = &nfs_sops; | ||
2240 | nfs_initialise_sb(sb); | 2079 | nfs_initialise_sb(sb); |
2241 | } | 2080 | } |
2242 | EXPORT_SYMBOL_GPL(nfs_fill_super); | ||
2243 | 2081 | ||
2244 | /* | 2082 | /* |
2245 | * Finish setting up a cloned NFS2/3/4 superblock | 2083 | * Finish setting up a cloned NFS2/3 superblock |
2246 | */ | 2084 | */ |
2247 | void nfs_clone_super(struct super_block *sb, struct nfs_mount_info *mount_info) | 2085 | static void nfs_clone_super(struct super_block *sb, |
2086 | const struct super_block *old_sb) | ||
2248 | { | 2087 | { |
2249 | const struct super_block *old_sb = mount_info->cloned->sb; | ||
2250 | struct nfs_server *server = NFS_SB(sb); | 2088 | struct nfs_server *server = NFS_SB(sb); |
2251 | 2089 | ||
2252 | sb->s_blocksize_bits = old_sb->s_blocksize_bits; | 2090 | sb->s_blocksize_bits = old_sb->s_blocksize_bits; |
2253 | sb->s_blocksize = old_sb->s_blocksize; | 2091 | sb->s_blocksize = old_sb->s_blocksize; |
2254 | sb->s_maxbytes = old_sb->s_maxbytes; | 2092 | sb->s_maxbytes = old_sb->s_maxbytes; |
2255 | sb->s_xattr = old_sb->s_xattr; | ||
2256 | sb->s_op = old_sb->s_op; | ||
2257 | sb->s_time_gran = 1; | ||
2258 | 2093 | ||
2259 | if (server->nfs_client->rpc_ops->version != 2) { | 2094 | if (server->nfs_client->rpc_ops->version == 3) { |
2260 | /* The VFS shouldn't apply the umask to mode bits. We will do | 2095 | /* The VFS shouldn't apply the umask to mode bits. We will do |
2261 | * so ourselves when necessary. | 2096 | * so ourselves when necessary. |
2262 | */ | 2097 | */ |
2263 | sb->s_flags |= MS_POSIXACL; | 2098 | sb->s_flags |= MS_POSIXACL; |
2099 | sb->s_time_gran = 1; | ||
2264 | } | 2100 | } |
2265 | 2101 | ||
2102 | sb->s_op = old_sb->s_op; | ||
2266 | nfs_initialise_sb(sb); | 2103 | nfs_initialise_sb(sb); |
2267 | } | 2104 | } |
2268 | 2105 | ||
@@ -2370,83 +2207,52 @@ static int nfs_compare_super(struct super_block *sb, void *data) | |||
2370 | return nfs_compare_mount_options(sb, server, mntflags); | 2207 | return nfs_compare_mount_options(sb, server, mntflags); |
2371 | } | 2208 | } |
2372 | 2209 | ||
2373 | #ifdef CONFIG_NFS_FSCACHE | ||
2374 | static void nfs_get_cache_cookie(struct super_block *sb, | ||
2375 | struct nfs_parsed_mount_data *parsed, | ||
2376 | struct nfs_clone_mount *cloned) | ||
2377 | { | ||
2378 | struct nfs_server *nfss = NFS_SB(sb); | ||
2379 | char *uniq = NULL; | ||
2380 | int ulen = 0; | ||
2381 | |||
2382 | nfss->fscache_key = NULL; | ||
2383 | nfss->fscache = NULL; | ||
2384 | |||
2385 | if (parsed) { | ||
2386 | if (!(parsed->options & NFS_OPTION_FSCACHE)) | ||
2387 | return; | ||
2388 | if (parsed->fscache_uniq) { | ||
2389 | uniq = parsed->fscache_uniq; | ||
2390 | ulen = strlen(parsed->fscache_uniq); | ||
2391 | } | ||
2392 | } else if (cloned) { | ||
2393 | struct nfs_server *mnt_s = NFS_SB(cloned->sb); | ||
2394 | if (!(mnt_s->options & NFS_OPTION_FSCACHE)) | ||
2395 | return; | ||
2396 | if (mnt_s->fscache_key) { | ||
2397 | uniq = mnt_s->fscache_key->key.uniquifier; | ||
2398 | ulen = mnt_s->fscache_key->key.uniq_len; | ||
2399 | }; | ||
2400 | } else | ||
2401 | return; | ||
2402 | |||
2403 | nfs_fscache_get_super_cookie(sb, uniq, ulen); | ||
2404 | } | ||
2405 | #else | ||
2406 | static void nfs_get_cache_cookie(struct super_block *sb, | ||
2407 | struct nfs_parsed_mount_data *parsed, | ||
2408 | struct nfs_clone_mount *cloned) | ||
2409 | { | ||
2410 | } | ||
2411 | #endif | ||
2412 | |||
2413 | static int nfs_bdi_register(struct nfs_server *server) | 2210 | static int nfs_bdi_register(struct nfs_server *server) |
2414 | { | 2211 | { |
2415 | return bdi_register_dev(&server->backing_dev_info, server->s_dev); | 2212 | return bdi_register_dev(&server->backing_dev_info, server->s_dev); |
2416 | } | 2213 | } |
2417 | 2214 | ||
2418 | int nfs_set_sb_security(struct super_block *s, struct dentry *mntroot, | 2215 | static struct dentry *nfs_fs_mount(struct file_system_type *fs_type, |
2419 | struct nfs_mount_info *mount_info) | 2216 | int flags, const char *dev_name, void *raw_data) |
2420 | { | ||
2421 | return security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts); | ||
2422 | } | ||
2423 | EXPORT_SYMBOL_GPL(nfs_set_sb_security); | ||
2424 | |||
2425 | int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot, | ||
2426 | struct nfs_mount_info *mount_info) | ||
2427 | { | ||
2428 | /* clone any lsm security options from the parent to the new sb */ | ||
2429 | security_sb_clone_mnt_opts(mount_info->cloned->sb, s); | ||
2430 | if (mntroot->d_inode->i_op != NFS_SB(s)->nfs_client->rpc_ops->dir_inode_ops) | ||
2431 | return -ESTALE; | ||
2432 | return 0; | ||
2433 | } | ||
2434 | EXPORT_SYMBOL_GPL(nfs_clone_sb_security); | ||
2435 | |||
2436 | struct dentry *nfs_fs_mount_common(struct nfs_server *server, | ||
2437 | int flags, const char *dev_name, | ||
2438 | struct nfs_mount_info *mount_info, | ||
2439 | struct nfs_subversion *nfs_mod) | ||
2440 | { | 2217 | { |
2218 | struct nfs_server *server = NULL; | ||
2441 | struct super_block *s; | 2219 | struct super_block *s; |
2220 | struct nfs_parsed_mount_data *data; | ||
2221 | struct nfs_fh *mntfh; | ||
2442 | struct dentry *mntroot = ERR_PTR(-ENOMEM); | 2222 | struct dentry *mntroot = ERR_PTR(-ENOMEM); |
2443 | int (*compare_super)(struct super_block *, void *) = nfs_compare_super; | 2223 | int (*compare_super)(struct super_block *, void *) = nfs_compare_super; |
2444 | struct nfs_sb_mountdata sb_mntdata = { | 2224 | struct nfs_sb_mountdata sb_mntdata = { |
2445 | .mntflags = flags, | 2225 | .mntflags = flags, |
2446 | .server = server, | ||
2447 | }; | 2226 | }; |
2448 | int error; | 2227 | int error; |
2449 | 2228 | ||
2229 | data = nfs_alloc_parsed_mount_data(NFS_DEFAULT_VERSION); | ||
2230 | mntfh = nfs_alloc_fhandle(); | ||
2231 | if (data == NULL || mntfh == NULL) | ||
2232 | goto out; | ||
2233 | |||
2234 | /* Validate the mount data */ | ||
2235 | error = nfs_validate_mount_data(raw_data, data, mntfh, dev_name); | ||
2236 | if (error < 0) { | ||
2237 | mntroot = ERR_PTR(error); | ||
2238 | goto out; | ||
2239 | } | ||
2240 | |||
2241 | #ifdef CONFIG_NFS_V4 | ||
2242 | if (data->version == 4) { | ||
2243 | mntroot = nfs4_try_mount(flags, dev_name, data); | ||
2244 | goto out; | ||
2245 | } | ||
2246 | #endif /* CONFIG_NFS_V4 */ | ||
2247 | |||
2248 | /* Get a volume representation */ | ||
2249 | server = nfs_create_server(data, mntfh); | ||
2250 | if (IS_ERR(server)) { | ||
2251 | mntroot = ERR_CAST(server); | ||
2252 | goto out; | ||
2253 | } | ||
2254 | sb_mntdata.server = server; | ||
2255 | |||
2450 | if (server->flags & NFS_MOUNT_UNSHARED) | 2256 | if (server->flags & NFS_MOUNT_UNSHARED) |
2451 | compare_super = NULL; | 2257 | compare_super = NULL; |
2452 | 2258 | ||
@@ -2455,7 +2261,7 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server, | |||
2455 | sb_mntdata.mntflags |= MS_SYNCHRONOUS; | 2261 | sb_mntdata.mntflags |= MS_SYNCHRONOUS; |
2456 | 2262 | ||
2457 | /* Get a superblock - note that we may end up sharing one that already exists */ | 2263 | /* Get a superblock - note that we may end up sharing one that already exists */ |
2458 | s = sget(nfs_mod->nfs_fs, compare_super, nfs_set_super, flags, &sb_mntdata); | 2264 | s = sget(fs_type, compare_super, nfs_set_super, &sb_mntdata); |
2459 | if (IS_ERR(s)) { | 2265 | if (IS_ERR(s)) { |
2460 | mntroot = ERR_CAST(s); | 2266 | mntroot = ERR_CAST(s); |
2461 | goto out_err_nosb; | 2267 | goto out_err_nosb; |
@@ -2474,21 +2280,23 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server, | |||
2474 | 2280 | ||
2475 | if (!s->s_root) { | 2281 | if (!s->s_root) { |
2476 | /* initial superblock/root creation */ | 2282 | /* initial superblock/root creation */ |
2477 | mount_info->fill_super(s, mount_info); | 2283 | nfs_fill_super(s, data); |
2478 | nfs_get_cache_cookie(s, mount_info->parsed, mount_info->cloned); | 2284 | nfs_fscache_get_super_cookie(s, data->fscache_uniq, NULL); |
2479 | } | 2285 | } |
2480 | 2286 | ||
2481 | mntroot = nfs_get_root(s, mount_info->mntfh, dev_name); | 2287 | mntroot = nfs_get_root(s, mntfh, dev_name); |
2482 | if (IS_ERR(mntroot)) | 2288 | if (IS_ERR(mntroot)) |
2483 | goto error_splat_super; | 2289 | goto error_splat_super; |
2484 | 2290 | ||
2485 | error = mount_info->set_security(s, mntroot, mount_info); | 2291 | error = security_sb_set_mnt_opts(s, &data->lsm_opts); |
2486 | if (error) | 2292 | if (error) |
2487 | goto error_splat_root; | 2293 | goto error_splat_root; |
2488 | 2294 | ||
2489 | s->s_flags |= MS_ACTIVE; | 2295 | s->s_flags |= MS_ACTIVE; |
2490 | 2296 | ||
2491 | out: | 2297 | out: |
2298 | nfs_free_parsed_mount_data(data); | ||
2299 | nfs_free_fhandle(mntfh); | ||
2492 | return mntroot; | 2300 | return mntroot; |
2493 | 2301 | ||
2494 | out_err_nosb: | 2302 | out_err_nosb: |
@@ -2505,65 +2313,22 @@ error_splat_bdi: | |||
2505 | deactivate_locked_super(s); | 2313 | deactivate_locked_super(s); |
2506 | goto out; | 2314 | goto out; |
2507 | } | 2315 | } |
2508 | EXPORT_SYMBOL_GPL(nfs_fs_mount_common); | ||
2509 | |||
2510 | struct dentry *nfs_fs_mount(struct file_system_type *fs_type, | ||
2511 | int flags, const char *dev_name, void *raw_data) | ||
2512 | { | ||
2513 | struct nfs_mount_info mount_info = { | ||
2514 | .fill_super = nfs_fill_super, | ||
2515 | .set_security = nfs_set_sb_security, | ||
2516 | }; | ||
2517 | struct dentry *mntroot = ERR_PTR(-ENOMEM); | ||
2518 | struct nfs_subversion *nfs_mod; | ||
2519 | int error; | ||
2520 | |||
2521 | mount_info.parsed = nfs_alloc_parsed_mount_data(); | ||
2522 | mount_info.mntfh = nfs_alloc_fhandle(); | ||
2523 | if (mount_info.parsed == NULL || mount_info.mntfh == NULL) | ||
2524 | goto out; | ||
2525 | |||
2526 | /* Validate the mount data */ | ||
2527 | error = nfs_validate_mount_data(fs_type, raw_data, mount_info.parsed, mount_info.mntfh, dev_name); | ||
2528 | if (error == NFS_TEXT_DATA) | ||
2529 | error = nfs_validate_text_mount_data(raw_data, mount_info.parsed, dev_name); | ||
2530 | if (error < 0) { | ||
2531 | mntroot = ERR_PTR(error); | ||
2532 | goto out; | ||
2533 | } | ||
2534 | |||
2535 | nfs_mod = get_nfs_version(mount_info.parsed->version); | ||
2536 | if (IS_ERR(nfs_mod)) { | ||
2537 | mntroot = ERR_CAST(nfs_mod); | ||
2538 | goto out; | ||
2539 | } | ||
2540 | |||
2541 | mntroot = nfs_mod->rpc_ops->try_mount(flags, dev_name, &mount_info, nfs_mod); | ||
2542 | |||
2543 | put_nfs_version(nfs_mod); | ||
2544 | out: | ||
2545 | nfs_free_parsed_mount_data(mount_info.parsed); | ||
2546 | nfs_free_fhandle(mount_info.mntfh); | ||
2547 | return mntroot; | ||
2548 | } | ||
2549 | EXPORT_SYMBOL_GPL(nfs_fs_mount); | ||
2550 | 2316 | ||
2551 | /* | 2317 | /* |
2552 | * Ensure that we unregister the bdi before kill_anon_super | 2318 | * Ensure that we unregister the bdi before kill_anon_super |
2553 | * releases the device name | 2319 | * releases the device name |
2554 | */ | 2320 | */ |
2555 | void nfs_put_super(struct super_block *s) | 2321 | static void nfs_put_super(struct super_block *s) |
2556 | { | 2322 | { |
2557 | struct nfs_server *server = NFS_SB(s); | 2323 | struct nfs_server *server = NFS_SB(s); |
2558 | 2324 | ||
2559 | bdi_unregister(&server->backing_dev_info); | 2325 | bdi_unregister(&server->backing_dev_info); |
2560 | } | 2326 | } |
2561 | EXPORT_SYMBOL_GPL(nfs_put_super); | ||
2562 | 2327 | ||
2563 | /* | 2328 | /* |
2564 | * Destroy an NFS2/3 superblock | 2329 | * Destroy an NFS2/3 superblock |
2565 | */ | 2330 | */ |
2566 | void nfs_kill_super(struct super_block *s) | 2331 | static void nfs_kill_super(struct super_block *s) |
2567 | { | 2332 | { |
2568 | struct nfs_server *server = NFS_SB(s); | 2333 | struct nfs_server *server = NFS_SB(s); |
2569 | 2334 | ||
@@ -2571,48 +2336,134 @@ void nfs_kill_super(struct super_block *s) | |||
2571 | nfs_fscache_release_super_cookie(s); | 2336 | nfs_fscache_release_super_cookie(s); |
2572 | nfs_free_server(server); | 2337 | nfs_free_server(server); |
2573 | } | 2338 | } |
2574 | EXPORT_SYMBOL_GPL(nfs_kill_super); | ||
2575 | 2339 | ||
2576 | /* | 2340 | /* |
2577 | * Clone an NFS2/3/4 server record on xdev traversal (FSID-change) | 2341 | * Clone an NFS2/3 server record on xdev traversal (FSID-change) |
2578 | */ | 2342 | */ |
2579 | static struct dentry * | 2343 | static struct dentry * |
2580 | nfs_xdev_mount(struct file_system_type *fs_type, int flags, | 2344 | nfs_xdev_mount(struct file_system_type *fs_type, int flags, |
2581 | const char *dev_name, void *raw_data) | 2345 | const char *dev_name, void *raw_data) |
2582 | { | 2346 | { |
2583 | struct nfs_clone_mount *data = raw_data; | 2347 | struct nfs_clone_mount *data = raw_data; |
2584 | struct nfs_mount_info mount_info = { | 2348 | struct super_block *s; |
2585 | .fill_super = nfs_clone_super, | ||
2586 | .set_security = nfs_clone_sb_security, | ||
2587 | .cloned = data, | ||
2588 | }; | ||
2589 | struct nfs_server *server; | 2349 | struct nfs_server *server; |
2590 | struct dentry *mntroot = ERR_PTR(-ENOMEM); | 2350 | struct dentry *mntroot; |
2591 | struct nfs_subversion *nfs_mod = NFS_SB(data->sb)->nfs_client->cl_nfs_mod; | 2351 | int (*compare_super)(struct super_block *, void *) = nfs_compare_super; |
2352 | struct nfs_sb_mountdata sb_mntdata = { | ||
2353 | .mntflags = flags, | ||
2354 | }; | ||
2592 | int error; | 2355 | int error; |
2593 | 2356 | ||
2594 | dprintk("--> nfs_xdev_mount_common()\n"); | 2357 | dprintk("--> nfs_xdev_mount()\n"); |
2595 | |||
2596 | mount_info.mntfh = mount_info.cloned->fh; | ||
2597 | 2358 | ||
2598 | /* create a new volume representation */ | 2359 | /* create a new volume representation */ |
2599 | server = nfs_mod->rpc_ops->clone_server(NFS_SB(data->sb), data->fh, data->fattr, data->authflavor); | 2360 | server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr); |
2600 | if (IS_ERR(server)) { | 2361 | if (IS_ERR(server)) { |
2601 | error = PTR_ERR(server); | 2362 | error = PTR_ERR(server); |
2602 | goto out_err; | 2363 | goto out_err_noserver; |
2603 | } | 2364 | } |
2365 | sb_mntdata.server = server; | ||
2604 | 2366 | ||
2605 | mntroot = nfs_fs_mount_common(server, flags, dev_name, &mount_info, nfs_mod); | 2367 | if (server->flags & NFS_MOUNT_UNSHARED) |
2606 | dprintk("<-- nfs_xdev_mount_common() = 0\n"); | 2368 | compare_super = NULL; |
2607 | out: | 2369 | |
2370 | /* -o noac implies -o sync */ | ||
2371 | if (server->flags & NFS_MOUNT_NOAC) | ||
2372 | sb_mntdata.mntflags |= MS_SYNCHRONOUS; | ||
2373 | |||
2374 | /* Get a superblock - note that we may end up sharing one that already exists */ | ||
2375 | s = sget(&nfs_fs_type, compare_super, nfs_set_super, &sb_mntdata); | ||
2376 | if (IS_ERR(s)) { | ||
2377 | error = PTR_ERR(s); | ||
2378 | goto out_err_nosb; | ||
2379 | } | ||
2380 | |||
2381 | if (s->s_fs_info != server) { | ||
2382 | nfs_free_server(server); | ||
2383 | server = NULL; | ||
2384 | } else { | ||
2385 | error = nfs_bdi_register(server); | ||
2386 | if (error) | ||
2387 | goto error_splat_bdi; | ||
2388 | } | ||
2389 | |||
2390 | if (!s->s_root) { | ||
2391 | /* initial superblock/root creation */ | ||
2392 | nfs_clone_super(s, data->sb); | ||
2393 | nfs_fscache_get_super_cookie(s, NULL, data); | ||
2394 | } | ||
2395 | |||
2396 | mntroot = nfs_get_root(s, data->fh, dev_name); | ||
2397 | if (IS_ERR(mntroot)) { | ||
2398 | error = PTR_ERR(mntroot); | ||
2399 | goto error_splat_super; | ||
2400 | } | ||
2401 | if (mntroot->d_inode->i_op != NFS_SB(s)->nfs_client->rpc_ops->dir_inode_ops) { | ||
2402 | dput(mntroot); | ||
2403 | error = -ESTALE; | ||
2404 | goto error_splat_super; | ||
2405 | } | ||
2406 | |||
2407 | s->s_flags |= MS_ACTIVE; | ||
2408 | |||
2409 | /* clone any lsm security options from the parent to the new sb */ | ||
2410 | security_sb_clone_mnt_opts(data->sb, s); | ||
2411 | |||
2412 | dprintk("<-- nfs_xdev_mount() = 0\n"); | ||
2608 | return mntroot; | 2413 | return mntroot; |
2609 | 2414 | ||
2610 | out_err: | 2415 | out_err_nosb: |
2611 | dprintk("<-- nfs_xdev_mount_common() = %d [error]\n", error); | 2416 | nfs_free_server(server); |
2612 | goto out; | 2417 | out_err_noserver: |
2418 | dprintk("<-- nfs_xdev_mount() = %d [error]\n", error); | ||
2419 | return ERR_PTR(error); | ||
2420 | |||
2421 | error_splat_super: | ||
2422 | if (server && !s->s_root) | ||
2423 | bdi_unregister(&server->backing_dev_info); | ||
2424 | error_splat_bdi: | ||
2425 | deactivate_locked_super(s); | ||
2426 | dprintk("<-- nfs_xdev_mount() = %d [splat]\n", error); | ||
2427 | return ERR_PTR(error); | ||
2428 | } | ||
2429 | |||
2430 | #ifdef CONFIG_NFS_V4 | ||
2431 | |||
2432 | /* | ||
2433 | * Finish setting up a cloned NFS4 superblock | ||
2434 | */ | ||
2435 | static void nfs4_clone_super(struct super_block *sb, | ||
2436 | const struct super_block *old_sb) | ||
2437 | { | ||
2438 | sb->s_blocksize_bits = old_sb->s_blocksize_bits; | ||
2439 | sb->s_blocksize = old_sb->s_blocksize; | ||
2440 | sb->s_maxbytes = old_sb->s_maxbytes; | ||
2441 | sb->s_time_gran = 1; | ||
2442 | sb->s_op = old_sb->s_op; | ||
2443 | /* | ||
2444 | * The VFS shouldn't apply the umask to mode bits. We will do | ||
2445 | * so ourselves when necessary. | ||
2446 | */ | ||
2447 | sb->s_flags |= MS_POSIXACL; | ||
2448 | sb->s_xattr = old_sb->s_xattr; | ||
2449 | nfs_initialise_sb(sb); | ||
2613 | } | 2450 | } |
2614 | 2451 | ||
2615 | #if IS_ENABLED(CONFIG_NFS_V4) | 2452 | /* |
2453 | * Set up an NFS4 superblock | ||
2454 | */ | ||
2455 | static void nfs4_fill_super(struct super_block *sb) | ||
2456 | { | ||
2457 | sb->s_time_gran = 1; | ||
2458 | sb->s_op = &nfs4_sops; | ||
2459 | /* | ||
2460 | * The VFS shouldn't apply the umask to mode bits. We will do | ||
2461 | * so ourselves when necessary. | ||
2462 | */ | ||
2463 | sb->s_flags |= MS_POSIXACL; | ||
2464 | sb->s_xattr = nfs4_xattr_handlers; | ||
2465 | nfs_initialise_sb(sb); | ||
2466 | } | ||
2616 | 2467 | ||
2617 | static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args) | 2468 | static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args) |
2618 | { | 2469 | { |
@@ -2620,6 +2471,43 @@ static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args) | |||
2620 | NFS_MOUNT_LOCAL_FLOCK|NFS_MOUNT_LOCAL_FCNTL); | 2471 | NFS_MOUNT_LOCAL_FLOCK|NFS_MOUNT_LOCAL_FCNTL); |
2621 | } | 2472 | } |
2622 | 2473 | ||
2474 | static int nfs4_validate_text_mount_data(void *options, | ||
2475 | struct nfs_parsed_mount_data *args, | ||
2476 | const char *dev_name) | ||
2477 | { | ||
2478 | struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address; | ||
2479 | |||
2480 | nfs_set_port(sap, &args->nfs_server.port, NFS_PORT); | ||
2481 | |||
2482 | nfs_validate_transport_protocol(args); | ||
2483 | |||
2484 | nfs4_validate_mount_flags(args); | ||
2485 | |||
2486 | if (args->version != 4) { | ||
2487 | dfprintk(MOUNT, | ||
2488 | "NFS4: Illegal mount version\n"); | ||
2489 | return -EINVAL; | ||
2490 | } | ||
2491 | |||
2492 | if (args->auth_flavor_len > 1) { | ||
2493 | dfprintk(MOUNT, | ||
2494 | "NFS4: Too many RPC auth flavours specified\n"); | ||
2495 | return -EINVAL; | ||
2496 | } | ||
2497 | |||
2498 | if (args->client_address == NULL) { | ||
2499 | dfprintk(MOUNT, | ||
2500 | "NFS4: mount program didn't pass callback address\n"); | ||
2501 | return -EINVAL; | ||
2502 | } | ||
2503 | |||
2504 | return nfs_parse_devname(dev_name, | ||
2505 | &args->nfs_server.hostname, | ||
2506 | NFS4_MAXNAMLEN, | ||
2507 | &args->nfs_server.export_path, | ||
2508 | NFS4_MAXPATHLEN); | ||
2509 | } | ||
2510 | |||
2623 | /* | 2511 | /* |
2624 | * Validate NFSv4 mount options | 2512 | * Validate NFSv4 mount options |
2625 | */ | 2513 | */ |
@@ -2634,8 +2522,6 @@ static int nfs4_validate_mount_data(void *options, | |||
2634 | if (data == NULL) | 2522 | if (data == NULL) |
2635 | goto out_no_data; | 2523 | goto out_no_data; |
2636 | 2524 | ||
2637 | args->version = 4; | ||
2638 | |||
2639 | switch (data->version) { | 2525 | switch (data->version) { |
2640 | case 1: | 2526 | case 1: |
2641 | if (data->host_addrlen > sizeof(args->nfs_server.address)) | 2527 | if (data->host_addrlen > sizeof(args->nfs_server.address)) |
@@ -2647,7 +2533,6 @@ static int nfs4_validate_mount_data(void *options, | |||
2647 | return -EFAULT; | 2533 | return -EFAULT; |
2648 | if (!nfs_verify_server_address(sap)) | 2534 | if (!nfs_verify_server_address(sap)) |
2649 | goto out_no_address; | 2535 | goto out_no_address; |
2650 | args->nfs_server.port = ntohs(((struct sockaddr_in *)sap)->sin_port); | ||
2651 | 2536 | ||
2652 | if (data->auth_flavourlen) { | 2537 | if (data->auth_flavourlen) { |
2653 | if (data->auth_flavourlen > 1) | 2538 | if (data->auth_flavourlen > 1) |
@@ -2693,7 +2578,13 @@ static int nfs4_validate_mount_data(void *options, | |||
2693 | 2578 | ||
2694 | break; | 2579 | break; |
2695 | default: | 2580 | default: |
2696 | return NFS_TEXT_DATA; | 2581 | if (nfs_parse_mount_options((char *)options, args) == 0) |
2582 | return -EINVAL; | ||
2583 | |||
2584 | if (!nfs_verify_server_address(sap)) | ||
2585 | return -EINVAL; | ||
2586 | |||
2587 | return nfs4_validate_text_mount_data(options, args, dev_name); | ||
2697 | } | 2588 | } |
2698 | 2589 | ||
2699 | return 0; | 2590 | return 0; |
@@ -2713,62 +2604,503 @@ out_no_address: | |||
2713 | } | 2604 | } |
2714 | 2605 | ||
2715 | /* | 2606 | /* |
2716 | * NFS v4 module parameters need to stay in the | 2607 | * Get the superblock for the NFS4 root partition |
2717 | * NFS client for backwards compatibility | ||
2718 | */ | 2608 | */ |
2719 | unsigned int nfs_callback_set_tcpport; | 2609 | static struct dentry * |
2720 | unsigned short nfs_callback_tcpport; | 2610 | nfs4_remote_mount(struct file_system_type *fs_type, int flags, |
2721 | /* Default cache timeout is 10 minutes */ | 2611 | const char *dev_name, void *raw_data) |
2722 | unsigned int nfs_idmap_cache_timeout = 600; | ||
2723 | /* Turn off NFSv4 uid/gid mapping when using AUTH_SYS */ | ||
2724 | bool nfs4_disable_idmapping = true; | ||
2725 | unsigned short max_session_slots = NFS4_DEF_SLOT_TABLE_SIZE; | ||
2726 | unsigned short send_implementation_id = 1; | ||
2727 | char nfs4_client_id_uniquifier[NFS4_CLIENT_ID_UNIQ_LEN] = ""; | ||
2728 | |||
2729 | EXPORT_SYMBOL_GPL(nfs_callback_set_tcpport); | ||
2730 | EXPORT_SYMBOL_GPL(nfs_callback_tcpport); | ||
2731 | EXPORT_SYMBOL_GPL(nfs_idmap_cache_timeout); | ||
2732 | EXPORT_SYMBOL_GPL(nfs4_disable_idmapping); | ||
2733 | EXPORT_SYMBOL_GPL(max_session_slots); | ||
2734 | EXPORT_SYMBOL_GPL(send_implementation_id); | ||
2735 | EXPORT_SYMBOL_GPL(nfs4_client_id_uniquifier); | ||
2736 | |||
2737 | #define NFS_CALLBACK_MAXPORTNR (65535U) | ||
2738 | |||
2739 | static int param_set_portnr(const char *val, const struct kernel_param *kp) | ||
2740 | { | 2612 | { |
2741 | unsigned long num; | 2613 | struct nfs_parsed_mount_data *data = raw_data; |
2742 | int ret; | 2614 | struct super_block *s; |
2615 | struct nfs_server *server; | ||
2616 | struct nfs_fh *mntfh; | ||
2617 | struct dentry *mntroot; | ||
2618 | int (*compare_super)(struct super_block *, void *) = nfs_compare_super; | ||
2619 | struct nfs_sb_mountdata sb_mntdata = { | ||
2620 | .mntflags = flags, | ||
2621 | }; | ||
2622 | int error = -ENOMEM; | ||
2743 | 2623 | ||
2744 | if (!val) | 2624 | mntfh = nfs_alloc_fhandle(); |
2745 | return -EINVAL; | 2625 | if (data == NULL || mntfh == NULL) |
2746 | ret = kstrtoul(val, 0, &num); | 2626 | goto out; |
2747 | if (ret == -EINVAL || num > NFS_CALLBACK_MAXPORTNR) | 2627 | |
2748 | return -EINVAL; | 2628 | /* Get a volume representation */ |
2749 | *((unsigned int *)kp->arg) = num; | 2629 | server = nfs4_create_server(data, mntfh); |
2750 | return 0; | 2630 | if (IS_ERR(server)) { |
2631 | error = PTR_ERR(server); | ||
2632 | goto out; | ||
2633 | } | ||
2634 | sb_mntdata.server = server; | ||
2635 | |||
2636 | if (server->flags & NFS4_MOUNT_UNSHARED) | ||
2637 | compare_super = NULL; | ||
2638 | |||
2639 | /* -o noac implies -o sync */ | ||
2640 | if (server->flags & NFS_MOUNT_NOAC) | ||
2641 | sb_mntdata.mntflags |= MS_SYNCHRONOUS; | ||
2642 | |||
2643 | /* Get a superblock - note that we may end up sharing one that already exists */ | ||
2644 | s = sget(&nfs4_fs_type, compare_super, nfs_set_super, &sb_mntdata); | ||
2645 | if (IS_ERR(s)) { | ||
2646 | error = PTR_ERR(s); | ||
2647 | goto out_free; | ||
2648 | } | ||
2649 | |||
2650 | if (s->s_fs_info != server) { | ||
2651 | nfs_free_server(server); | ||
2652 | server = NULL; | ||
2653 | } else { | ||
2654 | error = nfs_bdi_register(server); | ||
2655 | if (error) | ||
2656 | goto error_splat_bdi; | ||
2657 | } | ||
2658 | |||
2659 | if (!s->s_root) { | ||
2660 | /* initial superblock/root creation */ | ||
2661 | nfs4_fill_super(s); | ||
2662 | nfs_fscache_get_super_cookie( | ||
2663 | s, data ? data->fscache_uniq : NULL, NULL); | ||
2664 | } | ||
2665 | |||
2666 | mntroot = nfs4_get_root(s, mntfh, dev_name); | ||
2667 | if (IS_ERR(mntroot)) { | ||
2668 | error = PTR_ERR(mntroot); | ||
2669 | goto error_splat_super; | ||
2670 | } | ||
2671 | |||
2672 | error = security_sb_set_mnt_opts(s, &data->lsm_opts); | ||
2673 | if (error) | ||
2674 | goto error_splat_root; | ||
2675 | |||
2676 | s->s_flags |= MS_ACTIVE; | ||
2677 | |||
2678 | nfs_free_fhandle(mntfh); | ||
2679 | return mntroot; | ||
2680 | |||
2681 | out: | ||
2682 | nfs_free_fhandle(mntfh); | ||
2683 | return ERR_PTR(error); | ||
2684 | |||
2685 | out_free: | ||
2686 | nfs_free_server(server); | ||
2687 | goto out; | ||
2688 | |||
2689 | error_splat_root: | ||
2690 | dput(mntroot); | ||
2691 | error_splat_super: | ||
2692 | if (server && !s->s_root) | ||
2693 | bdi_unregister(&server->backing_dev_info); | ||
2694 | error_splat_bdi: | ||
2695 | deactivate_locked_super(s); | ||
2696 | goto out; | ||
2751 | } | 2697 | } |
2752 | static struct kernel_param_ops param_ops_portnr = { | 2698 | |
2753 | .set = param_set_portnr, | 2699 | static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type, |
2754 | .get = param_get_uint, | 2700 | int flags, void *data, const char *hostname) |
2701 | { | ||
2702 | struct vfsmount *root_mnt; | ||
2703 | char *root_devname; | ||
2704 | size_t len; | ||
2705 | |||
2706 | len = strlen(hostname) + 3; | ||
2707 | root_devname = kmalloc(len, GFP_KERNEL); | ||
2708 | if (root_devname == NULL) | ||
2709 | return ERR_PTR(-ENOMEM); | ||
2710 | snprintf(root_devname, len, "%s:/", hostname); | ||
2711 | root_mnt = vfs_kern_mount(fs_type, flags, root_devname, data); | ||
2712 | kfree(root_devname); | ||
2713 | return root_mnt; | ||
2714 | } | ||
2715 | |||
2716 | struct nfs_referral_count { | ||
2717 | struct list_head list; | ||
2718 | const struct task_struct *task; | ||
2719 | unsigned int referral_count; | ||
2755 | }; | 2720 | }; |
2756 | #define param_check_portnr(name, p) __param_check(name, p, unsigned int); | 2721 | |
2757 | 2722 | static LIST_HEAD(nfs_referral_count_list); | |
2758 | module_param_named(callback_tcpport, nfs_callback_set_tcpport, portnr, 0644); | 2723 | static DEFINE_SPINLOCK(nfs_referral_count_list_lock); |
2759 | module_param(nfs_idmap_cache_timeout, int, 0644); | 2724 | |
2760 | module_param(nfs4_disable_idmapping, bool, 0644); | 2725 | static struct nfs_referral_count *nfs_find_referral_count(void) |
2761 | module_param_string(nfs4_unique_id, nfs4_client_id_uniquifier, | 2726 | { |
2762 | NFS4_CLIENT_ID_UNIQ_LEN, 0600); | 2727 | struct nfs_referral_count *p; |
2763 | MODULE_PARM_DESC(nfs4_disable_idmapping, | 2728 | |
2764 | "Turn off NFSv4 idmapping when using 'sec=sys'"); | 2729 | list_for_each_entry(p, &nfs_referral_count_list, list) { |
2765 | module_param(max_session_slots, ushort, 0644); | 2730 | if (p->task == current) |
2766 | MODULE_PARM_DESC(max_session_slots, "Maximum number of outstanding NFSv4.1 " | 2731 | return p; |
2767 | "requests the client will negotiate"); | 2732 | } |
2768 | module_param(send_implementation_id, ushort, 0644); | 2733 | return NULL; |
2769 | MODULE_PARM_DESC(send_implementation_id, | 2734 | } |
2770 | "Send implementation ID with NFSv4.1 exchange_id"); | 2735 | |
2771 | MODULE_PARM_DESC(nfs4_unique_id, "nfs_client_id4 uniquifier string"); | 2736 | #define NFS_MAX_NESTED_REFERRALS 2 |
2772 | MODULE_ALIAS("nfs4"); | 2737 | |
2738 | static int nfs_referral_loop_protect(void) | ||
2739 | { | ||
2740 | struct nfs_referral_count *p, *new; | ||
2741 | int ret = -ENOMEM; | ||
2742 | |||
2743 | new = kmalloc(sizeof(*new), GFP_KERNEL); | ||
2744 | if (!new) | ||
2745 | goto out; | ||
2746 | new->task = current; | ||
2747 | new->referral_count = 1; | ||
2748 | |||
2749 | ret = 0; | ||
2750 | spin_lock(&nfs_referral_count_list_lock); | ||
2751 | p = nfs_find_referral_count(); | ||
2752 | if (p != NULL) { | ||
2753 | if (p->referral_count >= NFS_MAX_NESTED_REFERRALS) | ||
2754 | ret = -ELOOP; | ||
2755 | else | ||
2756 | p->referral_count++; | ||
2757 | } else { | ||
2758 | list_add(&new->list, &nfs_referral_count_list); | ||
2759 | new = NULL; | ||
2760 | } | ||
2761 | spin_unlock(&nfs_referral_count_list_lock); | ||
2762 | kfree(new); | ||
2763 | out: | ||
2764 | return ret; | ||
2765 | } | ||
2766 | |||
2767 | static void nfs_referral_loop_unprotect(void) | ||
2768 | { | ||
2769 | struct nfs_referral_count *p; | ||
2770 | |||
2771 | spin_lock(&nfs_referral_count_list_lock); | ||
2772 | p = nfs_find_referral_count(); | ||
2773 | p->referral_count--; | ||
2774 | if (p->referral_count == 0) | ||
2775 | list_del(&p->list); | ||
2776 | else | ||
2777 | p = NULL; | ||
2778 | spin_unlock(&nfs_referral_count_list_lock); | ||
2779 | kfree(p); | ||
2780 | } | ||
2781 | |||
2782 | static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt, | ||
2783 | const char *export_path) | ||
2784 | { | ||
2785 | struct mnt_namespace *ns_private; | ||
2786 | struct super_block *s; | ||
2787 | struct dentry *dentry; | ||
2788 | struct path path; | ||
2789 | int ret; | ||
2790 | |||
2791 | ns_private = create_mnt_ns(root_mnt); | ||
2792 | ret = PTR_ERR(ns_private); | ||
2793 | if (IS_ERR(ns_private)) | ||
2794 | goto out_mntput; | ||
2795 | |||
2796 | ret = nfs_referral_loop_protect(); | ||
2797 | if (ret != 0) | ||
2798 | goto out_put_mnt_ns; | ||
2799 | |||
2800 | ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt, | ||
2801 | export_path, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &path); | ||
2802 | |||
2803 | nfs_referral_loop_unprotect(); | ||
2804 | put_mnt_ns(ns_private); | ||
2805 | |||
2806 | if (ret != 0) | ||
2807 | goto out_err; | ||
2808 | |||
2809 | s = path.mnt->mnt_sb; | ||
2810 | atomic_inc(&s->s_active); | ||
2811 | dentry = dget(path.dentry); | ||
2812 | |||
2813 | path_put(&path); | ||
2814 | down_write(&s->s_umount); | ||
2815 | return dentry; | ||
2816 | out_put_mnt_ns: | ||
2817 | put_mnt_ns(ns_private); | ||
2818 | out_mntput: | ||
2819 | mntput(root_mnt); | ||
2820 | out_err: | ||
2821 | return ERR_PTR(ret); | ||
2822 | } | ||
2823 | |||
2824 | static struct dentry *nfs4_try_mount(int flags, const char *dev_name, | ||
2825 | struct nfs_parsed_mount_data *data) | ||
2826 | { | ||
2827 | char *export_path; | ||
2828 | struct vfsmount *root_mnt; | ||
2829 | struct dentry *res; | ||
2830 | |||
2831 | dfprintk(MOUNT, "--> nfs4_try_mount()\n"); | ||
2832 | |||
2833 | export_path = data->nfs_server.export_path; | ||
2834 | data->nfs_server.export_path = "/"; | ||
2835 | root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, data, | ||
2836 | data->nfs_server.hostname); | ||
2837 | data->nfs_server.export_path = export_path; | ||
2838 | |||
2839 | res = ERR_CAST(root_mnt); | ||
2840 | if (!IS_ERR(root_mnt)) | ||
2841 | res = nfs_follow_remote_path(root_mnt, export_path); | ||
2842 | |||
2843 | dfprintk(MOUNT, "<-- nfs4_try_mount() = %ld%s\n", | ||
2844 | IS_ERR(res) ? PTR_ERR(res) : 0, | ||
2845 | IS_ERR(res) ? " [error]" : ""); | ||
2846 | return res; | ||
2847 | } | ||
2848 | |||
2849 | /* | ||
2850 | * Get the superblock for an NFS4 mountpoint | ||
2851 | */ | ||
2852 | static struct dentry *nfs4_mount(struct file_system_type *fs_type, | ||
2853 | int flags, const char *dev_name, void *raw_data) | ||
2854 | { | ||
2855 | struct nfs_parsed_mount_data *data; | ||
2856 | int error = -ENOMEM; | ||
2857 | struct dentry *res = ERR_PTR(-ENOMEM); | ||
2858 | |||
2859 | data = nfs_alloc_parsed_mount_data(4); | ||
2860 | if (data == NULL) | ||
2861 | goto out; | ||
2862 | |||
2863 | /* Validate the mount data */ | ||
2864 | error = nfs4_validate_mount_data(raw_data, data, dev_name); | ||
2865 | if (error < 0) { | ||
2866 | res = ERR_PTR(error); | ||
2867 | goto out; | ||
2868 | } | ||
2869 | |||
2870 | res = nfs4_try_mount(flags, dev_name, data); | ||
2871 | if (IS_ERR(res)) | ||
2872 | error = PTR_ERR(res); | ||
2873 | |||
2874 | out: | ||
2875 | nfs_free_parsed_mount_data(data); | ||
2876 | dprintk("<-- nfs4_mount() = %d%s\n", error, | ||
2877 | error != 0 ? " [error]" : ""); | ||
2878 | return res; | ||
2879 | } | ||
2880 | |||
2881 | static void nfs4_kill_super(struct super_block *sb) | ||
2882 | { | ||
2883 | struct nfs_server *server = NFS_SB(sb); | ||
2884 | |||
2885 | dprintk("--> %s\n", __func__); | ||
2886 | nfs_super_return_all_delegations(sb); | ||
2887 | kill_anon_super(sb); | ||
2888 | nfs_fscache_release_super_cookie(sb); | ||
2889 | nfs_free_server(server); | ||
2890 | dprintk("<-- %s\n", __func__); | ||
2891 | } | ||
2892 | |||
2893 | /* | ||
2894 | * Clone an NFS4 server record on xdev traversal (FSID-change) | ||
2895 | */ | ||
2896 | static struct dentry * | ||
2897 | nfs4_xdev_mount(struct file_system_type *fs_type, int flags, | ||
2898 | const char *dev_name, void *raw_data) | ||
2899 | { | ||
2900 | struct nfs_clone_mount *data = raw_data; | ||
2901 | struct super_block *s; | ||
2902 | struct nfs_server *server; | ||
2903 | struct dentry *mntroot; | ||
2904 | int (*compare_super)(struct super_block *, void *) = nfs_compare_super; | ||
2905 | struct nfs_sb_mountdata sb_mntdata = { | ||
2906 | .mntflags = flags, | ||
2907 | }; | ||
2908 | int error; | ||
2909 | |||
2910 | dprintk("--> nfs4_xdev_mount()\n"); | ||
2911 | |||
2912 | /* create a new volume representation */ | ||
2913 | server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr); | ||
2914 | if (IS_ERR(server)) { | ||
2915 | error = PTR_ERR(server); | ||
2916 | goto out_err_noserver; | ||
2917 | } | ||
2918 | sb_mntdata.server = server; | ||
2919 | |||
2920 | if (server->flags & NFS4_MOUNT_UNSHARED) | ||
2921 | compare_super = NULL; | ||
2922 | |||
2923 | /* -o noac implies -o sync */ | ||
2924 | if (server->flags & NFS_MOUNT_NOAC) | ||
2925 | sb_mntdata.mntflags |= MS_SYNCHRONOUS; | ||
2926 | |||
2927 | /* Get a superblock - note that we may end up sharing one that already exists */ | ||
2928 | s = sget(&nfs4_fs_type, compare_super, nfs_set_super, &sb_mntdata); | ||
2929 | if (IS_ERR(s)) { | ||
2930 | error = PTR_ERR(s); | ||
2931 | goto out_err_nosb; | ||
2932 | } | ||
2933 | |||
2934 | if (s->s_fs_info != server) { | ||
2935 | nfs_free_server(server); | ||
2936 | server = NULL; | ||
2937 | } else { | ||
2938 | error = nfs_bdi_register(server); | ||
2939 | if (error) | ||
2940 | goto error_splat_bdi; | ||
2941 | } | ||
2942 | |||
2943 | if (!s->s_root) { | ||
2944 | /* initial superblock/root creation */ | ||
2945 | nfs4_clone_super(s, data->sb); | ||
2946 | nfs_fscache_get_super_cookie(s, NULL, data); | ||
2947 | } | ||
2948 | |||
2949 | mntroot = nfs4_get_root(s, data->fh, dev_name); | ||
2950 | if (IS_ERR(mntroot)) { | ||
2951 | error = PTR_ERR(mntroot); | ||
2952 | goto error_splat_super; | ||
2953 | } | ||
2954 | if (mntroot->d_inode->i_op != NFS_SB(s)->nfs_client->rpc_ops->dir_inode_ops) { | ||
2955 | dput(mntroot); | ||
2956 | error = -ESTALE; | ||
2957 | goto error_splat_super; | ||
2958 | } | ||
2959 | |||
2960 | s->s_flags |= MS_ACTIVE; | ||
2961 | |||
2962 | security_sb_clone_mnt_opts(data->sb, s); | ||
2963 | |||
2964 | dprintk("<-- nfs4_xdev_mount() = 0\n"); | ||
2965 | return mntroot; | ||
2966 | |||
2967 | out_err_nosb: | ||
2968 | nfs_free_server(server); | ||
2969 | out_err_noserver: | ||
2970 | dprintk("<-- nfs4_xdev_mount() = %d [error]\n", error); | ||
2971 | return ERR_PTR(error); | ||
2972 | |||
2973 | error_splat_super: | ||
2974 | if (server && !s->s_root) | ||
2975 | bdi_unregister(&server->backing_dev_info); | ||
2976 | error_splat_bdi: | ||
2977 | deactivate_locked_super(s); | ||
2978 | dprintk("<-- nfs4_xdev_mount() = %d [splat]\n", error); | ||
2979 | return ERR_PTR(error); | ||
2980 | } | ||
2981 | |||
2982 | static struct dentry * | ||
2983 | nfs4_remote_referral_mount(struct file_system_type *fs_type, int flags, | ||
2984 | const char *dev_name, void *raw_data) | ||
2985 | { | ||
2986 | struct nfs_clone_mount *data = raw_data; | ||
2987 | struct super_block *s; | ||
2988 | struct nfs_server *server; | ||
2989 | struct dentry *mntroot; | ||
2990 | struct nfs_fh *mntfh; | ||
2991 | int (*compare_super)(struct super_block *, void *) = nfs_compare_super; | ||
2992 | struct nfs_sb_mountdata sb_mntdata = { | ||
2993 | .mntflags = flags, | ||
2994 | }; | ||
2995 | int error = -ENOMEM; | ||
2996 | |||
2997 | dprintk("--> nfs4_referral_get_sb()\n"); | ||
2998 | |||
2999 | mntfh = nfs_alloc_fhandle(); | ||
3000 | if (mntfh == NULL) | ||
3001 | goto out_err_nofh; | ||
3002 | |||
3003 | /* create a new volume representation */ | ||
3004 | server = nfs4_create_referral_server(data, mntfh); | ||
3005 | if (IS_ERR(server)) { | ||
3006 | error = PTR_ERR(server); | ||
3007 | goto out_err_noserver; | ||
3008 | } | ||
3009 | sb_mntdata.server = server; | ||
3010 | |||
3011 | if (server->flags & NFS4_MOUNT_UNSHARED) | ||
3012 | compare_super = NULL; | ||
3013 | |||
3014 | /* -o noac implies -o sync */ | ||
3015 | if (server->flags & NFS_MOUNT_NOAC) | ||
3016 | sb_mntdata.mntflags |= MS_SYNCHRONOUS; | ||
3017 | |||
3018 | /* Get a superblock - note that we may end up sharing one that already exists */ | ||
3019 | s = sget(&nfs4_fs_type, compare_super, nfs_set_super, &sb_mntdata); | ||
3020 | if (IS_ERR(s)) { | ||
3021 | error = PTR_ERR(s); | ||
3022 | goto out_err_nosb; | ||
3023 | } | ||
3024 | |||
3025 | if (s->s_fs_info != server) { | ||
3026 | nfs_free_server(server); | ||
3027 | server = NULL; | ||
3028 | } else { | ||
3029 | error = nfs_bdi_register(server); | ||
3030 | if (error) | ||
3031 | goto error_splat_bdi; | ||
3032 | } | ||
3033 | |||
3034 | if (!s->s_root) { | ||
3035 | /* initial superblock/root creation */ | ||
3036 | nfs4_fill_super(s); | ||
3037 | nfs_fscache_get_super_cookie(s, NULL, data); | ||
3038 | } | ||
3039 | |||
3040 | mntroot = nfs4_get_root(s, mntfh, dev_name); | ||
3041 | if (IS_ERR(mntroot)) { | ||
3042 | error = PTR_ERR(mntroot); | ||
3043 | goto error_splat_super; | ||
3044 | } | ||
3045 | if (mntroot->d_inode->i_op != NFS_SB(s)->nfs_client->rpc_ops->dir_inode_ops) { | ||
3046 | dput(mntroot); | ||
3047 | error = -ESTALE; | ||
3048 | goto error_splat_super; | ||
3049 | } | ||
3050 | |||
3051 | s->s_flags |= MS_ACTIVE; | ||
3052 | |||
3053 | security_sb_clone_mnt_opts(data->sb, s); | ||
3054 | |||
3055 | nfs_free_fhandle(mntfh); | ||
3056 | dprintk("<-- nfs4_referral_get_sb() = 0\n"); | ||
3057 | return mntroot; | ||
3058 | |||
3059 | out_err_nosb: | ||
3060 | nfs_free_server(server); | ||
3061 | out_err_noserver: | ||
3062 | nfs_free_fhandle(mntfh); | ||
3063 | out_err_nofh: | ||
3064 | dprintk("<-- nfs4_referral_get_sb() = %d [error]\n", error); | ||
3065 | return ERR_PTR(error); | ||
3066 | |||
3067 | error_splat_super: | ||
3068 | if (server && !s->s_root) | ||
3069 | bdi_unregister(&server->backing_dev_info); | ||
3070 | error_splat_bdi: | ||
3071 | deactivate_locked_super(s); | ||
3072 | nfs_free_fhandle(mntfh); | ||
3073 | dprintk("<-- nfs4_referral_get_sb() = %d [splat]\n", error); | ||
3074 | return ERR_PTR(error); | ||
3075 | } | ||
3076 | |||
3077 | /* | ||
3078 | * Create an NFS4 server record on referral traversal | ||
3079 | */ | ||
3080 | static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type, | ||
3081 | int flags, const char *dev_name, void *raw_data) | ||
3082 | { | ||
3083 | struct nfs_clone_mount *data = raw_data; | ||
3084 | char *export_path; | ||
3085 | struct vfsmount *root_mnt; | ||
3086 | struct dentry *res; | ||
3087 | |||
3088 | dprintk("--> nfs4_referral_mount()\n"); | ||
3089 | |||
3090 | export_path = data->mnt_path; | ||
3091 | data->mnt_path = "/"; | ||
3092 | |||
3093 | root_mnt = nfs_do_root_mount(&nfs4_remote_referral_fs_type, | ||
3094 | flags, data, data->hostname); | ||
3095 | data->mnt_path = export_path; | ||
3096 | |||
3097 | res = ERR_CAST(root_mnt); | ||
3098 | if (!IS_ERR(root_mnt)) | ||
3099 | res = nfs_follow_remote_path(root_mnt, export_path); | ||
3100 | dprintk("<-- nfs4_referral_mount() = %ld%s\n", | ||
3101 | IS_ERR(res) ? PTR_ERR(res) : 0, | ||
3102 | IS_ERR(res) ? " [error]" : ""); | ||
3103 | return res; | ||
3104 | } | ||
2773 | 3105 | ||
2774 | #endif /* CONFIG_NFS_V4 */ | 3106 | #endif /* CONFIG_NFS_V4 */ |