diff options
author | Bryan Schumaker <bjschuma@netapp.com> | 2012-07-16 16:39:20 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-07-17 13:33:55 -0400 |
commit | fbdefd6442811392e857721573b63a51d1149cc8 (patch) | |
tree | d3b36fa0af3a91a22c3799db13c4cb07d0ec2fff /fs/nfs/super.c | |
parent | 3cadf4b864cab9d19b935289c004799d1065cd03 (diff) |
NFS: Split out the NFS v4 filesystem types
This allows me to move the v4 mounting and unmounting functions out of
the generic client and into a file that is only compiled when CONFIG_NFS_V4
is enabled.
Signed-off-by: Bryan Schumaker <bjschuma@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/super.c')
-rw-r--r-- | fs/nfs/super.c | 395 |
1 files changed, 22 insertions, 373 deletions
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index ca3c0e8cf774..95866a8c21bb 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -278,29 +278,8 @@ static match_table_t nfs_vers_tokens = { | |||
278 | { Opt_vers_err, NULL } | 278 | { Opt_vers_err, NULL } |
279 | }; | 279 | }; |
280 | 280 | ||
281 | struct nfs_mount_info { | ||
282 | void (*fill_super)(struct super_block *, struct nfs_mount_info *); | ||
283 | int (*set_security)(struct super_block *, struct dentry *, struct nfs_mount_info *); | ||
284 | struct nfs_parsed_mount_data *parsed; | ||
285 | struct nfs_clone_mount *cloned; | ||
286 | struct nfs_fh *mntfh; | ||
287 | }; | ||
288 | |||
289 | static void nfs_umount_begin(struct super_block *); | ||
290 | static int nfs_statfs(struct dentry *, struct kstatfs *); | ||
291 | static int nfs_show_options(struct seq_file *, struct dentry *); | ||
292 | static int nfs_show_devname(struct seq_file *, struct dentry *); | ||
293 | static int nfs_show_path(struct seq_file *, struct dentry *); | ||
294 | static int nfs_show_stats(struct seq_file *, struct dentry *); | ||
295 | static struct dentry *nfs_fs_mount_common(struct file_system_type *, | ||
296 | struct nfs_server *, int, const char *, struct nfs_mount_info *); | ||
297 | static struct dentry *nfs_fs_mount(struct file_system_type *, | ||
298 | int, const char *, void *); | ||
299 | static struct dentry *nfs_xdev_mount(struct file_system_type *fs_type, | 281 | static struct dentry *nfs_xdev_mount(struct file_system_type *fs_type, |
300 | int flags, const char *dev_name, void *raw_data); | 282 | int flags, const char *dev_name, void *raw_data); |
301 | static void nfs_put_super(struct super_block *); | ||
302 | static void nfs_kill_super(struct super_block *); | ||
303 | static int nfs_remount(struct super_block *sb, int *flags, char *raw_data); | ||
304 | 283 | ||
305 | static struct file_system_type nfs_fs_type = { | 284 | static struct file_system_type nfs_fs_type = { |
306 | .owner = THIS_MODULE, | 285 | .owner = THIS_MODULE, |
@@ -337,71 +316,6 @@ static const struct super_operations nfs_sops = { | |||
337 | static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *); | 316 | static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *); |
338 | static int nfs4_validate_mount_data(void *options, | 317 | static int nfs4_validate_mount_data(void *options, |
339 | struct nfs_parsed_mount_data *args, const char *dev_name); | 318 | struct nfs_parsed_mount_data *args, const char *dev_name); |
340 | static struct dentry *nfs4_try_mount(int flags, const char *dev_name, | ||
341 | struct nfs_mount_info *mount_info); | ||
342 | static struct dentry *nfs4_remote_mount(struct file_system_type *fs_type, | ||
343 | int flags, const char *dev_name, void *raw_data); | ||
344 | static struct dentry *nfs4_xdev_mount(struct file_system_type *fs_type, | ||
345 | int flags, const char *dev_name, void *raw_data); | ||
346 | static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type, | ||
347 | int flags, const char *dev_name, void *raw_data); | ||
348 | static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type, | ||
349 | int flags, const char *dev_name, void *raw_data); | ||
350 | |||
351 | static struct file_system_type nfs4_fs_type = { | ||
352 | .owner = THIS_MODULE, | ||
353 | .name = "nfs4", | ||
354 | .mount = nfs_fs_mount, | ||
355 | .kill_sb = nfs_kill_super, | ||
356 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
357 | }; | ||
358 | |||
359 | static struct file_system_type nfs4_remote_fs_type = { | ||
360 | .owner = THIS_MODULE, | ||
361 | .name = "nfs4", | ||
362 | .mount = nfs4_remote_mount, | ||
363 | .kill_sb = nfs_kill_super, | ||
364 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
365 | }; | ||
366 | |||
367 | struct file_system_type nfs4_xdev_fs_type = { | ||
368 | .owner = THIS_MODULE, | ||
369 | .name = "nfs4", | ||
370 | .mount = nfs4_xdev_mount, | ||
371 | .kill_sb = nfs_kill_super, | ||
372 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
373 | }; | ||
374 | |||
375 | static struct file_system_type nfs4_remote_referral_fs_type = { | ||
376 | .owner = THIS_MODULE, | ||
377 | .name = "nfs4", | ||
378 | .mount = nfs4_remote_referral_mount, | ||
379 | .kill_sb = nfs_kill_super, | ||
380 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
381 | }; | ||
382 | |||
383 | struct file_system_type nfs4_referral_fs_type = { | ||
384 | .owner = THIS_MODULE, | ||
385 | .name = "nfs4", | ||
386 | .mount = nfs4_referral_mount, | ||
387 | .kill_sb = nfs_kill_super, | ||
388 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
389 | }; | ||
390 | |||
391 | static const struct super_operations nfs4_sops = { | ||
392 | .alloc_inode = nfs_alloc_inode, | ||
393 | .destroy_inode = nfs_destroy_inode, | ||
394 | .write_inode = nfs4_write_inode, | ||
395 | .put_super = nfs_put_super, | ||
396 | .statfs = nfs_statfs, | ||
397 | .evict_inode = nfs4_evict_inode, | ||
398 | .umount_begin = nfs_umount_begin, | ||
399 | .show_options = nfs_show_options, | ||
400 | .show_devname = nfs_show_devname, | ||
401 | .show_path = nfs_show_path, | ||
402 | .show_stats = nfs_show_stats, | ||
403 | .remount_fs = nfs_remount, | ||
404 | }; | ||
405 | #endif | 319 | #endif |
406 | 320 | ||
407 | static struct shrinker acl_shrinker = { | 321 | static struct shrinker acl_shrinker = { |
@@ -423,18 +337,9 @@ int __init register_nfs_fs(void) | |||
423 | ret = nfs_register_sysctl(); | 337 | ret = nfs_register_sysctl(); |
424 | if (ret < 0) | 338 | if (ret < 0) |
425 | goto error_1; | 339 | goto error_1; |
426 | #ifdef CONFIG_NFS_V4 | ||
427 | ret = register_filesystem(&nfs4_fs_type); | ||
428 | if (ret < 0) | ||
429 | goto error_2; | ||
430 | #endif | ||
431 | register_shrinker(&acl_shrinker); | 340 | register_shrinker(&acl_shrinker); |
432 | return 0; | 341 | return 0; |
433 | 342 | ||
434 | #ifdef CONFIG_NFS_V4 | ||
435 | error_2: | ||
436 | nfs_unregister_sysctl(); | ||
437 | #endif | ||
438 | error_1: | 343 | error_1: |
439 | unregister_filesystem(&nfs_fs_type); | 344 | unregister_filesystem(&nfs_fs_type); |
440 | error_0: | 345 | error_0: |
@@ -447,9 +352,6 @@ error_0: | |||
447 | void __exit unregister_nfs_fs(void) | 352 | void __exit unregister_nfs_fs(void) |
448 | { | 353 | { |
449 | unregister_shrinker(&acl_shrinker); | 354 | unregister_shrinker(&acl_shrinker); |
450 | #ifdef CONFIG_NFS_V4 | ||
451 | unregister_filesystem(&nfs4_fs_type); | ||
452 | #endif | ||
453 | nfs_unregister_sysctl(); | 355 | nfs_unregister_sysctl(); |
454 | unregister_filesystem(&nfs_fs_type); | 356 | unregister_filesystem(&nfs_fs_type); |
455 | } | 357 | } |
@@ -473,7 +375,7 @@ void nfs_sb_deactive(struct super_block *sb) | |||
473 | /* | 375 | /* |
474 | * Deliver file system statistics to userspace | 376 | * Deliver file system statistics to userspace |
475 | */ | 377 | */ |
476 | static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) | 378 | int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) |
477 | { | 379 | { |
478 | struct nfs_server *server = NFS_SB(dentry->d_sb); | 380 | struct nfs_server *server = NFS_SB(dentry->d_sb); |
479 | unsigned char blockbits; | 381 | unsigned char blockbits; |
@@ -756,7 +658,7 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
756 | /* | 658 | /* |
757 | * Describe the mount options on this VFS mountpoint | 659 | * Describe the mount options on this VFS mountpoint |
758 | */ | 660 | */ |
759 | static int nfs_show_options(struct seq_file *m, struct dentry *root) | 661 | int nfs_show_options(struct seq_file *m, struct dentry *root) |
760 | { | 662 | { |
761 | struct nfs_server *nfss = NFS_SB(root->d_sb); | 663 | struct nfs_server *nfss = NFS_SB(root->d_sb); |
762 | 664 | ||
@@ -814,7 +716,7 @@ static void show_implementation_id(struct seq_file *m, struct nfs_server *nfss) | |||
814 | } | 716 | } |
815 | #endif | 717 | #endif |
816 | 718 | ||
817 | static int nfs_show_devname(struct seq_file *m, struct dentry *root) | 719 | int nfs_show_devname(struct seq_file *m, struct dentry *root) |
818 | { | 720 | { |
819 | char *page = (char *) __get_free_page(GFP_KERNEL); | 721 | char *page = (char *) __get_free_page(GFP_KERNEL); |
820 | char *devname, *dummy; | 722 | char *devname, *dummy; |
@@ -830,7 +732,7 @@ static int nfs_show_devname(struct seq_file *m, struct dentry *root) | |||
830 | return err; | 732 | return err; |
831 | } | 733 | } |
832 | 734 | ||
833 | static int nfs_show_path(struct seq_file *m, struct dentry *dentry) | 735 | int nfs_show_path(struct seq_file *m, struct dentry *dentry) |
834 | { | 736 | { |
835 | seq_puts(m, "/"); | 737 | seq_puts(m, "/"); |
836 | return 0; | 738 | return 0; |
@@ -839,7 +741,7 @@ static int nfs_show_path(struct seq_file *m, struct dentry *dentry) | |||
839 | /* | 741 | /* |
840 | * Present statistical information for this VFS mountpoint | 742 | * Present statistical information for this VFS mountpoint |
841 | */ | 743 | */ |
842 | static int nfs_show_stats(struct seq_file *m, struct dentry *root) | 744 | int nfs_show_stats(struct seq_file *m, struct dentry *root) |
843 | { | 745 | { |
844 | int i, cpu; | 746 | int i, cpu; |
845 | struct nfs_server *nfss = NFS_SB(root->d_sb); | 747 | struct nfs_server *nfss = NFS_SB(root->d_sb); |
@@ -932,7 +834,7 @@ static int nfs_show_stats(struct seq_file *m, struct dentry *root) | |||
932 | * Begin unmount by attempting to remove all automounted mountpoints we added | 834 | * Begin unmount by attempting to remove all automounted mountpoints we added |
933 | * in response to xdev traversals and referrals | 835 | * in response to xdev traversals and referrals |
934 | */ | 836 | */ |
935 | static void nfs_umount_begin(struct super_block *sb) | 837 | void nfs_umount_begin(struct super_block *sb) |
936 | { | 838 | { |
937 | struct nfs_server *server; | 839 | struct nfs_server *server; |
938 | struct rpc_clnt *rpc; | 840 | struct rpc_clnt *rpc; |
@@ -2107,7 +2009,7 @@ nfs_compare_remount_data(struct nfs_server *nfss, | |||
2107 | return 0; | 2009 | return 0; |
2108 | } | 2010 | } |
2109 | 2011 | ||
2110 | static int | 2012 | int |
2111 | nfs_remount(struct super_block *sb, int *flags, char *raw_data) | 2013 | nfs_remount(struct super_block *sb, int *flags, char *raw_data) |
2112 | { | 2014 | { |
2113 | int error; | 2015 | int error; |
@@ -2172,7 +2074,7 @@ out: | |||
2172 | /* | 2074 | /* |
2173 | * Initialise the common bits of the superblock | 2075 | * Initialise the common bits of the superblock |
2174 | */ | 2076 | */ |
2175 | static inline void nfs_initialise_sb(struct super_block *sb) | 2077 | inline void nfs_initialise_sb(struct super_block *sb) |
2176 | { | 2078 | { |
2177 | struct nfs_server *server = NFS_SB(sb); | 2079 | struct nfs_server *server = NFS_SB(sb); |
2178 | 2080 | ||
@@ -2194,8 +2096,7 @@ static inline void nfs_initialise_sb(struct super_block *sb) | |||
2194 | /* | 2096 | /* |
2195 | * Finish setting up an NFS2/3 superblock | 2097 | * Finish setting up an NFS2/3 superblock |
2196 | */ | 2098 | */ |
2197 | static void nfs_fill_super(struct super_block *sb, | 2099 | void nfs_fill_super(struct super_block *sb, struct nfs_mount_info *mount_info) |
2198 | struct nfs_mount_info *mount_info) | ||
2199 | { | 2100 | { |
2200 | struct nfs_parsed_mount_data *data = mount_info->parsed; | 2101 | struct nfs_parsed_mount_data *data = mount_info->parsed; |
2201 | struct nfs_server *server = NFS_SB(sb); | 2102 | struct nfs_server *server = NFS_SB(sb); |
@@ -2220,8 +2121,7 @@ static void nfs_fill_super(struct super_block *sb, | |||
2220 | /* | 2121 | /* |
2221 | * Finish setting up a cloned NFS2/3/4 superblock | 2122 | * Finish setting up a cloned NFS2/3/4 superblock |
2222 | */ | 2123 | */ |
2223 | static void nfs_clone_super(struct super_block *sb, | 2124 | void nfs_clone_super(struct super_block *sb, struct nfs_mount_info *mount_info) |
2224 | struct nfs_mount_info *mount_info) | ||
2225 | { | 2125 | { |
2226 | const struct super_block *old_sb = mount_info->cloned->sb; | 2126 | const struct super_block *old_sb = mount_info->cloned->sb; |
2227 | struct nfs_server *server = NFS_SB(sb); | 2127 | struct nfs_server *server = NFS_SB(sb); |
@@ -2381,14 +2281,14 @@ static int nfs_bdi_register(struct nfs_server *server) | |||
2381 | return bdi_register_dev(&server->backing_dev_info, server->s_dev); | 2281 | return bdi_register_dev(&server->backing_dev_info, server->s_dev); |
2382 | } | 2282 | } |
2383 | 2283 | ||
2384 | static int nfs_set_sb_security(struct super_block *s, struct dentry *mntroot, | 2284 | int nfs_set_sb_security(struct super_block *s, struct dentry *mntroot, |
2385 | struct nfs_mount_info *mount_info) | 2285 | struct nfs_mount_info *mount_info) |
2386 | { | 2286 | { |
2387 | return security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts); | 2287 | return security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts); |
2388 | } | 2288 | } |
2389 | 2289 | ||
2390 | static int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot, | 2290 | int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot, |
2391 | struct nfs_mount_info *mount_info) | 2291 | struct nfs_mount_info *mount_info) |
2392 | { | 2292 | { |
2393 | /* clone any lsm security options from the parent to the new sb */ | 2293 | /* clone any lsm security options from the parent to the new sb */ |
2394 | security_sb_clone_mnt_opts(mount_info->cloned->sb, s); | 2294 | security_sb_clone_mnt_opts(mount_info->cloned->sb, s); |
@@ -2397,10 +2297,10 @@ static int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot, | |||
2397 | return 0; | 2297 | return 0; |
2398 | } | 2298 | } |
2399 | 2299 | ||
2400 | static struct dentry *nfs_fs_mount_common(struct file_system_type *fs_type, | 2300 | struct dentry *nfs_fs_mount_common(struct file_system_type *fs_type, |
2401 | struct nfs_server *server, | 2301 | struct nfs_server *server, |
2402 | int flags, const char *dev_name, | 2302 | int flags, const char *dev_name, |
2403 | struct nfs_mount_info *mount_info) | 2303 | struct nfs_mount_info *mount_info) |
2404 | { | 2304 | { |
2405 | struct super_block *s; | 2305 | struct super_block *s; |
2406 | struct dentry *mntroot = ERR_PTR(-ENOMEM); | 2306 | struct dentry *mntroot = ERR_PTR(-ENOMEM); |
@@ -2470,7 +2370,7 @@ error_splat_bdi: | |||
2470 | goto out; | 2370 | goto out; |
2471 | } | 2371 | } |
2472 | 2372 | ||
2473 | static struct dentry *nfs_fs_mount(struct file_system_type *fs_type, | 2373 | struct dentry *nfs_fs_mount(struct file_system_type *fs_type, |
2474 | int flags, const char *dev_name, void *raw_data) | 2374 | int flags, const char *dev_name, void *raw_data) |
2475 | { | 2375 | { |
2476 | struct nfs_mount_info mount_info = { | 2376 | struct nfs_mount_info mount_info = { |
@@ -2511,7 +2411,7 @@ out: | |||
2511 | * Ensure that we unregister the bdi before kill_anon_super | 2411 | * Ensure that we unregister the bdi before kill_anon_super |
2512 | * releases the device name | 2412 | * releases the device name |
2513 | */ | 2413 | */ |
2514 | static void nfs_put_super(struct super_block *s) | 2414 | void nfs_put_super(struct super_block *s) |
2515 | { | 2415 | { |
2516 | struct nfs_server *server = NFS_SB(s); | 2416 | struct nfs_server *server = NFS_SB(s); |
2517 | 2417 | ||
@@ -2521,7 +2421,7 @@ static void nfs_put_super(struct super_block *s) | |||
2521 | /* | 2421 | /* |
2522 | * Destroy an NFS2/3 superblock | 2422 | * Destroy an NFS2/3 superblock |
2523 | */ | 2423 | */ |
2524 | static void nfs_kill_super(struct super_block *s) | 2424 | void nfs_kill_super(struct super_block *s) |
2525 | { | 2425 | { |
2526 | struct nfs_server *server = NFS_SB(s); | 2426 | struct nfs_server *server = NFS_SB(s); |
2527 | 2427 | ||
@@ -2533,7 +2433,7 @@ static void nfs_kill_super(struct super_block *s) | |||
2533 | /* | 2433 | /* |
2534 | * Clone an NFS2/3/4 server record on xdev traversal (FSID-change) | 2434 | * Clone an NFS2/3/4 server record on xdev traversal (FSID-change) |
2535 | */ | 2435 | */ |
2536 | static struct dentry * | 2436 | struct dentry * |
2537 | nfs_xdev_mount_common(struct file_system_type *fs_type, int flags, | 2437 | nfs_xdev_mount_common(struct file_system_type *fs_type, int flags, |
2538 | const char *dev_name, struct nfs_mount_info *mount_info) | 2438 | const char *dev_name, struct nfs_mount_info *mount_info) |
2539 | { | 2439 | { |
@@ -2580,23 +2480,6 @@ nfs_xdev_mount(struct file_system_type *fs_type, int flags, | |||
2580 | 2480 | ||
2581 | #ifdef CONFIG_NFS_V4 | 2481 | #ifdef CONFIG_NFS_V4 |
2582 | 2482 | ||
2583 | /* | ||
2584 | * Set up an NFS4 superblock | ||
2585 | */ | ||
2586 | static void nfs4_fill_super(struct super_block *sb, | ||
2587 | struct nfs_mount_info *mount_info) | ||
2588 | { | ||
2589 | sb->s_time_gran = 1; | ||
2590 | sb->s_op = &nfs4_sops; | ||
2591 | /* | ||
2592 | * The VFS shouldn't apply the umask to mode bits. We will do | ||
2593 | * so ourselves when necessary. | ||
2594 | */ | ||
2595 | sb->s_flags |= MS_POSIXACL; | ||
2596 | sb->s_xattr = nfs4_xattr_handlers; | ||
2597 | nfs_initialise_sb(sb); | ||
2598 | } | ||
2599 | |||
2600 | static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args) | 2483 | static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args) |
2601 | { | 2484 | { |
2602 | args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3| | 2485 | args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3| |
@@ -2694,238 +2577,4 @@ out_no_address: | |||
2694 | return -EINVAL; | 2577 | return -EINVAL; |
2695 | } | 2578 | } |
2696 | 2579 | ||
2697 | /* | ||
2698 | * Get the superblock for the NFS4 root partition | ||
2699 | */ | ||
2700 | static struct dentry * | ||
2701 | nfs4_remote_mount(struct file_system_type *fs_type, int flags, | ||
2702 | const char *dev_name, void *info) | ||
2703 | { | ||
2704 | struct nfs_mount_info *mount_info = info; | ||
2705 | struct nfs_server *server; | ||
2706 | struct dentry *mntroot = ERR_PTR(-ENOMEM); | ||
2707 | |||
2708 | mount_info->fill_super = nfs4_fill_super; | ||
2709 | mount_info->set_security = nfs_set_sb_security; | ||
2710 | |||
2711 | /* Get a volume representation */ | ||
2712 | server = nfs4_create_server(mount_info->parsed, mount_info->mntfh); | ||
2713 | if (IS_ERR(server)) { | ||
2714 | mntroot = ERR_CAST(server); | ||
2715 | goto out; | ||
2716 | } | ||
2717 | |||
2718 | mntroot = nfs_fs_mount_common(fs_type, server, flags, dev_name, mount_info); | ||
2719 | |||
2720 | out: | ||
2721 | return mntroot; | ||
2722 | } | ||
2723 | |||
2724 | static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type, | ||
2725 | int flags, void *data, const char *hostname) | ||
2726 | { | ||
2727 | struct vfsmount *root_mnt; | ||
2728 | char *root_devname; | ||
2729 | size_t len; | ||
2730 | |||
2731 | len = strlen(hostname) + 5; | ||
2732 | root_devname = kmalloc(len, GFP_KERNEL); | ||
2733 | if (root_devname == NULL) | ||
2734 | return ERR_PTR(-ENOMEM); | ||
2735 | /* Does hostname needs to be enclosed in brackets? */ | ||
2736 | if (strchr(hostname, ':')) | ||
2737 | snprintf(root_devname, len, "[%s]:/", hostname); | ||
2738 | else | ||
2739 | snprintf(root_devname, len, "%s:/", hostname); | ||
2740 | root_mnt = vfs_kern_mount(fs_type, flags, root_devname, data); | ||
2741 | kfree(root_devname); | ||
2742 | return root_mnt; | ||
2743 | } | ||
2744 | |||
2745 | struct nfs_referral_count { | ||
2746 | struct list_head list; | ||
2747 | const struct task_struct *task; | ||
2748 | unsigned int referral_count; | ||
2749 | }; | ||
2750 | |||
2751 | static LIST_HEAD(nfs_referral_count_list); | ||
2752 | static DEFINE_SPINLOCK(nfs_referral_count_list_lock); | ||
2753 | |||
2754 | static struct nfs_referral_count *nfs_find_referral_count(void) | ||
2755 | { | ||
2756 | struct nfs_referral_count *p; | ||
2757 | |||
2758 | list_for_each_entry(p, &nfs_referral_count_list, list) { | ||
2759 | if (p->task == current) | ||
2760 | return p; | ||
2761 | } | ||
2762 | return NULL; | ||
2763 | } | ||
2764 | |||
2765 | #define NFS_MAX_NESTED_REFERRALS 2 | ||
2766 | |||
2767 | static int nfs_referral_loop_protect(void) | ||
2768 | { | ||
2769 | struct nfs_referral_count *p, *new; | ||
2770 | int ret = -ENOMEM; | ||
2771 | |||
2772 | new = kmalloc(sizeof(*new), GFP_KERNEL); | ||
2773 | if (!new) | ||
2774 | goto out; | ||
2775 | new->task = current; | ||
2776 | new->referral_count = 1; | ||
2777 | |||
2778 | ret = 0; | ||
2779 | spin_lock(&nfs_referral_count_list_lock); | ||
2780 | p = nfs_find_referral_count(); | ||
2781 | if (p != NULL) { | ||
2782 | if (p->referral_count >= NFS_MAX_NESTED_REFERRALS) | ||
2783 | ret = -ELOOP; | ||
2784 | else | ||
2785 | p->referral_count++; | ||
2786 | } else { | ||
2787 | list_add(&new->list, &nfs_referral_count_list); | ||
2788 | new = NULL; | ||
2789 | } | ||
2790 | spin_unlock(&nfs_referral_count_list_lock); | ||
2791 | kfree(new); | ||
2792 | out: | ||
2793 | return ret; | ||
2794 | } | ||
2795 | |||
2796 | static void nfs_referral_loop_unprotect(void) | ||
2797 | { | ||
2798 | struct nfs_referral_count *p; | ||
2799 | |||
2800 | spin_lock(&nfs_referral_count_list_lock); | ||
2801 | p = nfs_find_referral_count(); | ||
2802 | p->referral_count--; | ||
2803 | if (p->referral_count == 0) | ||
2804 | list_del(&p->list); | ||
2805 | else | ||
2806 | p = NULL; | ||
2807 | spin_unlock(&nfs_referral_count_list_lock); | ||
2808 | kfree(p); | ||
2809 | } | ||
2810 | |||
2811 | static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt, | ||
2812 | const char *export_path) | ||
2813 | { | ||
2814 | struct dentry *dentry; | ||
2815 | int err; | ||
2816 | |||
2817 | if (IS_ERR(root_mnt)) | ||
2818 | return ERR_CAST(root_mnt); | ||
2819 | |||
2820 | err = nfs_referral_loop_protect(); | ||
2821 | if (err) { | ||
2822 | mntput(root_mnt); | ||
2823 | return ERR_PTR(err); | ||
2824 | } | ||
2825 | |||
2826 | dentry = mount_subtree(root_mnt, export_path); | ||
2827 | nfs_referral_loop_unprotect(); | ||
2828 | |||
2829 | return dentry; | ||
2830 | } | ||
2831 | |||
2832 | static struct dentry *nfs4_try_mount(int flags, const char *dev_name, | ||
2833 | struct nfs_mount_info *mount_info) | ||
2834 | { | ||
2835 | char *export_path; | ||
2836 | struct vfsmount *root_mnt; | ||
2837 | struct dentry *res; | ||
2838 | struct nfs_parsed_mount_data *data = mount_info->parsed; | ||
2839 | |||
2840 | dfprintk(MOUNT, "--> nfs4_try_mount()\n"); | ||
2841 | |||
2842 | mount_info->fill_super = nfs4_fill_super; | ||
2843 | |||
2844 | export_path = data->nfs_server.export_path; | ||
2845 | data->nfs_server.export_path = "/"; | ||
2846 | root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, mount_info, | ||
2847 | data->nfs_server.hostname); | ||
2848 | data->nfs_server.export_path = export_path; | ||
2849 | |||
2850 | res = nfs_follow_remote_path(root_mnt, export_path); | ||
2851 | |||
2852 | dfprintk(MOUNT, "<-- nfs4_try_mount() = %ld%s\n", | ||
2853 | IS_ERR(res) ? PTR_ERR(res) : 0, | ||
2854 | IS_ERR(res) ? " [error]" : ""); | ||
2855 | return res; | ||
2856 | } | ||
2857 | |||
2858 | /* | ||
2859 | * Clone an NFS4 server record on xdev traversal (FSID-change) | ||
2860 | */ | ||
2861 | static struct dentry * | ||
2862 | nfs4_xdev_mount(struct file_system_type *fs_type, int flags, | ||
2863 | const char *dev_name, void *raw_data) | ||
2864 | { | ||
2865 | struct nfs_mount_info mount_info = { | ||
2866 | .fill_super = nfs_clone_super, | ||
2867 | .set_security = nfs_clone_sb_security, | ||
2868 | .cloned = raw_data, | ||
2869 | }; | ||
2870 | return nfs_xdev_mount_common(&nfs4_fs_type, flags, dev_name, &mount_info); | ||
2871 | } | ||
2872 | |||
2873 | static struct dentry * | ||
2874 | nfs4_remote_referral_mount(struct file_system_type *fs_type, int flags, | ||
2875 | const char *dev_name, void *raw_data) | ||
2876 | { | ||
2877 | struct nfs_mount_info mount_info = { | ||
2878 | .fill_super = nfs4_fill_super, | ||
2879 | .set_security = nfs_clone_sb_security, | ||
2880 | .cloned = raw_data, | ||
2881 | }; | ||
2882 | struct nfs_server *server; | ||
2883 | struct dentry *mntroot = ERR_PTR(-ENOMEM); | ||
2884 | |||
2885 | dprintk("--> nfs4_referral_get_sb()\n"); | ||
2886 | |||
2887 | mount_info.mntfh = nfs_alloc_fhandle(); | ||
2888 | if (mount_info.cloned == NULL || mount_info.mntfh == NULL) | ||
2889 | goto out; | ||
2890 | |||
2891 | /* create a new volume representation */ | ||
2892 | server = nfs4_create_referral_server(mount_info.cloned, mount_info.mntfh); | ||
2893 | if (IS_ERR(server)) { | ||
2894 | mntroot = ERR_CAST(server); | ||
2895 | goto out; | ||
2896 | } | ||
2897 | |||
2898 | mntroot = nfs_fs_mount_common(&nfs4_fs_type, server, flags, dev_name, &mount_info); | ||
2899 | out: | ||
2900 | nfs_free_fhandle(mount_info.mntfh); | ||
2901 | return mntroot; | ||
2902 | } | ||
2903 | |||
2904 | /* | ||
2905 | * Create an NFS4 server record on referral traversal | ||
2906 | */ | ||
2907 | static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type, | ||
2908 | int flags, const char *dev_name, void *raw_data) | ||
2909 | { | ||
2910 | struct nfs_clone_mount *data = raw_data; | ||
2911 | char *export_path; | ||
2912 | struct vfsmount *root_mnt; | ||
2913 | struct dentry *res; | ||
2914 | |||
2915 | dprintk("--> nfs4_referral_mount()\n"); | ||
2916 | |||
2917 | export_path = data->mnt_path; | ||
2918 | data->mnt_path = "/"; | ||
2919 | |||
2920 | root_mnt = nfs_do_root_mount(&nfs4_remote_referral_fs_type, | ||
2921 | flags, data, data->hostname); | ||
2922 | data->mnt_path = export_path; | ||
2923 | |||
2924 | res = nfs_follow_remote_path(root_mnt, export_path); | ||
2925 | dprintk("<-- nfs4_referral_mount() = %ld%s\n", | ||
2926 | IS_ERR(res) ? PTR_ERR(res) : 0, | ||
2927 | IS_ERR(res) ? " [error]" : ""); | ||
2928 | return res; | ||
2929 | } | ||
2930 | |||
2931 | #endif /* CONFIG_NFS_V4 */ | 2580 | #endif /* CONFIG_NFS_V4 */ |