aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/super.c178
1 files changed, 157 insertions, 21 deletions
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 3d460527daab..8e0673a0d6aa 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -42,6 +42,8 @@
42#include <linux/smp_lock.h> 42#include <linux/smp_lock.h>
43#include <linux/seq_file.h> 43#include <linux/seq_file.h>
44#include <linux/mount.h> 44#include <linux/mount.h>
45#include <linux/mnt_namespace.h>
46#include <linux/namei.h>
45#include <linux/nfs_idmap.h> 47#include <linux/nfs_idmap.h>
46#include <linux/vfs.h> 48#include <linux/vfs.h>
47#include <linux/inet.h> 49#include <linux/inet.h>
@@ -272,10 +274,14 @@ static const struct super_operations nfs_sops = {
272#ifdef CONFIG_NFS_V4 274#ifdef CONFIG_NFS_V4
273static int nfs4_get_sb(struct file_system_type *fs_type, 275static int nfs4_get_sb(struct file_system_type *fs_type,
274 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); 276 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
277static int nfs4_remote_get_sb(struct file_system_type *fs_type,
278 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
275static int nfs4_xdev_get_sb(struct file_system_type *fs_type, 279static int nfs4_xdev_get_sb(struct file_system_type *fs_type,
276 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); 280 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
277static int nfs4_referral_get_sb(struct file_system_type *fs_type, 281static int nfs4_referral_get_sb(struct file_system_type *fs_type,
278 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); 282 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
283static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type,
284 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
279static void nfs4_kill_super(struct super_block *sb); 285static void nfs4_kill_super(struct super_block *sb);
280 286
281static struct file_system_type nfs4_fs_type = { 287static struct file_system_type nfs4_fs_type = {
@@ -286,6 +292,14 @@ static struct file_system_type nfs4_fs_type = {
286 .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, 292 .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
287}; 293};
288 294
295static struct file_system_type nfs4_remote_fs_type = {
296 .owner = THIS_MODULE,
297 .name = "nfs4",
298 .get_sb = nfs4_remote_get_sb,
299 .kill_sb = nfs4_kill_super,
300 .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
301};
302
289struct file_system_type nfs4_xdev_fs_type = { 303struct file_system_type nfs4_xdev_fs_type = {
290 .owner = THIS_MODULE, 304 .owner = THIS_MODULE,
291 .name = "nfs4", 305 .name = "nfs4",
@@ -294,6 +308,14 @@ struct file_system_type nfs4_xdev_fs_type = {
294 .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, 308 .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
295}; 309};
296 310
311static struct file_system_type nfs4_remote_referral_fs_type = {
312 .owner = THIS_MODULE,
313 .name = "nfs4",
314 .get_sb = nfs4_remote_referral_get_sb,
315 .kill_sb = nfs4_kill_super,
316 .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
317};
318
297struct file_system_type nfs4_referral_fs_type = { 319struct file_system_type nfs4_referral_fs_type = {
298 .owner = THIS_MODULE, 320 .owner = THIS_MODULE,
299 .name = "nfs4", 321 .name = "nfs4",
@@ -2433,12 +2455,12 @@ out_no_client_address:
2433} 2455}
2434 2456
2435/* 2457/*
2436 * Get the superblock for an NFS4 mountpoint 2458 * Get the superblock for the NFS4 root partition
2437 */ 2459 */
2438static int nfs4_get_sb(struct file_system_type *fs_type, 2460static int nfs4_remote_get_sb(struct file_system_type *fs_type,
2439 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) 2461 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
2440{ 2462{
2441 struct nfs_parsed_mount_data *data; 2463 struct nfs_parsed_mount_data *data = raw_data;
2442 struct super_block *s; 2464 struct super_block *s;
2443 struct nfs_server *server; 2465 struct nfs_server *server;
2444 struct nfs_fh *mntfh; 2466 struct nfs_fh *mntfh;
@@ -2449,18 +2471,12 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
2449 }; 2471 };
2450 int error = -ENOMEM; 2472 int error = -ENOMEM;
2451 2473
2452 data = kzalloc(sizeof(*data), GFP_KERNEL);
2453 mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL); 2474 mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL);
2454 if (data == NULL || mntfh == NULL) 2475 if (data == NULL || mntfh == NULL)
2455 goto out_free_fh; 2476 goto out_free_fh;
2456 2477
2457 security_init_mnt_opts(&data->lsm_opts); 2478 security_init_mnt_opts(&data->lsm_opts);
2458 2479
2459 /* Validate the mount data */
2460 error = nfs4_validate_mount_data(raw_data, data, dev_name);
2461 if (error < 0)
2462 goto out;
2463
2464 /* Get a volume representation */ 2480 /* Get a volume representation */
2465 server = nfs4_create_server(data, mntfh); 2481 server = nfs4_create_server(data, mntfh);
2466 if (IS_ERR(server)) { 2482 if (IS_ERR(server)) {
@@ -2473,7 +2489,7 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
2473 compare_super = NULL; 2489 compare_super = NULL;
2474 2490
2475 /* Get a superblock - note that we may end up sharing one that already exists */ 2491 /* Get a superblock - note that we may end up sharing one that already exists */
2476 s = sget(fs_type, compare_super, nfs_set_super, &sb_mntdata); 2492 s = sget(&nfs4_fs_type, compare_super, nfs_set_super, &sb_mntdata);
2477 if (IS_ERR(s)) { 2493 if (IS_ERR(s)) {
2478 error = PTR_ERR(s); 2494 error = PTR_ERR(s);
2479 goto out_free; 2495 goto out_free;
@@ -2510,14 +2526,9 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
2510 error = 0; 2526 error = 0;
2511 2527
2512out: 2528out:
2513 kfree(data->client_address);
2514 kfree(data->nfs_server.export_path);
2515 kfree(data->nfs_server.hostname);
2516 kfree(data->fscache_uniq);
2517 security_free_mnt_opts(&data->lsm_opts); 2529 security_free_mnt_opts(&data->lsm_opts);
2518out_free_fh: 2530out_free_fh:
2519 kfree(mntfh); 2531 kfree(mntfh);
2520 kfree(data);
2521 return error; 2532 return error;
2522 2533
2523out_free: 2534out_free:
@@ -2531,6 +2542,102 @@ error_splat_super:
2531 goto out; 2542 goto out;
2532} 2543}
2533 2544
2545static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type,
2546 int flags, void *data, const char *hostname)
2547{
2548 struct vfsmount *root_mnt;
2549 char *root_devname;
2550 size_t len;
2551
2552 len = strlen(hostname) + 3;
2553 root_devname = kmalloc(len, GFP_KERNEL);
2554 if (root_devname == NULL)
2555 return ERR_PTR(-ENOMEM);
2556 snprintf(root_devname, len, "%s:/", hostname);
2557 root_mnt = vfs_kern_mount(fs_type, flags, root_devname, data);
2558 kfree(root_devname);
2559 return root_mnt;
2560}
2561
2562static int nfs_follow_remote_path(struct vfsmount *root_mnt,
2563 const char *export_path, struct vfsmount *mnt_target)
2564{
2565 struct mnt_namespace *ns_private;
2566 struct nameidata nd;
2567 struct super_block *s;
2568 int ret;
2569
2570 ns_private = create_mnt_ns(root_mnt);
2571 ret = PTR_ERR(ns_private);
2572 if (IS_ERR(ns_private))
2573 goto out_mntput;
2574
2575 ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt,
2576 export_path, LOOKUP_FOLLOW, &nd);
2577
2578 put_mnt_ns(ns_private);
2579
2580 if (ret != 0)
2581 goto out_err;
2582
2583 s = nd.path.mnt->mnt_sb;
2584 atomic_inc(&s->s_active);
2585 mnt_target->mnt_sb = s;
2586 mnt_target->mnt_root = dget(nd.path.dentry);
2587
2588 path_put(&nd.path);
2589 down_write(&s->s_umount);
2590 return 0;
2591out_mntput:
2592 mntput(root_mnt);
2593out_err:
2594 return ret;
2595}
2596
2597/*
2598 * Get the superblock for an NFS4 mountpoint
2599 */
2600static int nfs4_get_sb(struct file_system_type *fs_type,
2601 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
2602{
2603 struct nfs_parsed_mount_data *data;
2604 char *export_path;
2605 struct vfsmount *root_mnt;
2606 int error = -ENOMEM;
2607
2608 data = kzalloc(sizeof(*data), GFP_KERNEL);
2609 if (data == NULL)
2610 goto out_free_data;
2611
2612 /* Validate the mount data */
2613 error = nfs4_validate_mount_data(raw_data, data, dev_name);
2614 if (error < 0)
2615 goto out;
2616
2617 export_path = data->nfs_server.export_path;
2618 data->nfs_server.export_path = "/";
2619 root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, data,
2620 data->nfs_server.hostname);
2621 data->nfs_server.export_path = export_path;
2622
2623 error = PTR_ERR(root_mnt);
2624 if (IS_ERR(root_mnt))
2625 goto out;
2626
2627 error = nfs_follow_remote_path(root_mnt, export_path, mnt);
2628
2629out:
2630 kfree(data->client_address);
2631 kfree(data->nfs_server.export_path);
2632 kfree(data->nfs_server.hostname);
2633 kfree(data->fscache_uniq);
2634out_free_data:
2635 kfree(data);
2636 dprintk("<-- nfs4_get_sb() = %d%s\n", error,
2637 error != 0 ? " [error]" : "");
2638 return error;
2639}
2640
2534static void nfs4_kill_super(struct super_block *sb) 2641static void nfs4_kill_super(struct super_block *sb)
2535{ 2642{
2536 struct nfs_server *server = NFS_SB(sb); 2643 struct nfs_server *server = NFS_SB(sb);
@@ -2627,12 +2734,9 @@ error_splat_super:
2627 return error; 2734 return error;
2628} 2735}
2629 2736
2630/* 2737static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type,
2631 * Create an NFS4 server record on referral traversal 2738 int flags, const char *dev_name, void *raw_data,
2632 */ 2739 struct vfsmount *mnt)
2633static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags,
2634 const char *dev_name, void *raw_data,
2635 struct vfsmount *mnt)
2636{ 2740{
2637 struct nfs_clone_mount *data = raw_data; 2741 struct nfs_clone_mount *data = raw_data;
2638 struct super_block *s; 2742 struct super_block *s;
@@ -2711,4 +2815,36 @@ error_splat_super:
2711 return error; 2815 return error;
2712} 2816}
2713 2817
2818/*
2819 * Create an NFS4 server record on referral traversal
2820 */
2821static int nfs4_referral_get_sb(struct file_system_type *fs_type,
2822 int flags, const char *dev_name, void *raw_data,
2823 struct vfsmount *mnt)
2824{
2825 struct nfs_clone_mount *data = raw_data;
2826 char *export_path;
2827 struct vfsmount *root_mnt;
2828 int error;
2829
2830 dprintk("--> nfs4_referral_get_sb()\n");
2831
2832 export_path = data->mnt_path;
2833 data->mnt_path = "/";
2834
2835 root_mnt = nfs_do_root_mount(&nfs4_remote_referral_fs_type,
2836 flags, data, data->hostname);
2837 data->mnt_path = export_path;
2838
2839 error = PTR_ERR(root_mnt);
2840 if (IS_ERR(root_mnt))
2841 goto out;
2842
2843 error = nfs_follow_remote_path(root_mnt, export_path, mnt);
2844out:
2845 dprintk("<-- nfs4_referral_get_sb() = %d%s\n", error,
2846 error != 0 ? " [error]" : "");
2847 return error;
2848}
2849
2714#endif /* CONFIG_NFS_V4 */ 2850#endif /* CONFIG_NFS_V4 */