Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 153833
b: refs/heads/master
c: c02d7ad
h: refs/heads/master
i:
  153831: 1d9cf0b
v: v3
  • Loading branch information
Trond Myklebust authored and Linus Torvalds committed Jun 23, 2009
1 parent 150833e commit ebefe70
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 22 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: cf8d2c11cb77f129675478792122f50827e5b0ae
refs/heads/master: c02d7adf8c5429727a98bad1d039bccad4c61c50
178 changes: 157 additions & 21 deletions trunk/fs/nfs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
#include <linux/smp_lock.h>
#include <linux/seq_file.h>
#include <linux/mount.h>
#include <linux/mnt_namespace.h>
#include <linux/namei.h>
#include <linux/nfs_idmap.h>
#include <linux/vfs.h>
#include <linux/inet.h>
Expand Down Expand Up @@ -272,10 +274,14 @@ static const struct super_operations nfs_sops = {
#ifdef CONFIG_NFS_V4
static int nfs4_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
static int nfs4_remote_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
static int nfs4_xdev_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
static int nfs4_referral_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
static void nfs4_kill_super(struct super_block *sb);

static struct file_system_type nfs4_fs_type = {
Expand All @@ -286,6 +292,14 @@ static struct file_system_type nfs4_fs_type = {
.fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
};

static struct file_system_type nfs4_remote_fs_type = {
.owner = THIS_MODULE,
.name = "nfs4",
.get_sb = nfs4_remote_get_sb,
.kill_sb = nfs4_kill_super,
.fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
};

struct file_system_type nfs4_xdev_fs_type = {
.owner = THIS_MODULE,
.name = "nfs4",
Expand All @@ -294,6 +308,14 @@ struct file_system_type nfs4_xdev_fs_type = {
.fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
};

static struct file_system_type nfs4_remote_referral_fs_type = {
.owner = THIS_MODULE,
.name = "nfs4",
.get_sb = nfs4_remote_referral_get_sb,
.kill_sb = nfs4_kill_super,
.fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
};

struct file_system_type nfs4_referral_fs_type = {
.owner = THIS_MODULE,
.name = "nfs4",
Expand Down Expand Up @@ -2433,12 +2455,12 @@ static int nfs4_validate_mount_data(void *options,
}

/*
* Get the superblock for an NFS4 mountpoint
* Get the superblock for the NFS4 root partition
*/
static int nfs4_get_sb(struct file_system_type *fs_type,
static int nfs4_remote_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
{
struct nfs_parsed_mount_data *data;
struct nfs_parsed_mount_data *data = raw_data;
struct super_block *s;
struct nfs_server *server;
struct nfs_fh *mntfh;
Expand All @@ -2449,18 +2471,12 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
};
int error = -ENOMEM;

data = kzalloc(sizeof(*data), GFP_KERNEL);
mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL);
if (data == NULL || mntfh == NULL)
goto out_free_fh;

security_init_mnt_opts(&data->lsm_opts);

/* Validate the mount data */
error = nfs4_validate_mount_data(raw_data, data, dev_name);
if (error < 0)
goto out;

/* Get a volume representation */
server = nfs4_create_server(data, mntfh);
if (IS_ERR(server)) {
Expand All @@ -2473,7 +2489,7 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
compare_super = NULL;

/* Get a superblock - note that we may end up sharing one that already exists */
s = sget(fs_type, compare_super, nfs_set_super, &sb_mntdata);
s = sget(&nfs4_fs_type, compare_super, nfs_set_super, &sb_mntdata);
if (IS_ERR(s)) {
error = PTR_ERR(s);
goto out_free;
Expand Down Expand Up @@ -2510,14 +2526,9 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
error = 0;

out:
kfree(data->client_address);
kfree(data->nfs_server.export_path);
kfree(data->nfs_server.hostname);
kfree(data->fscache_uniq);
security_free_mnt_opts(&data->lsm_opts);
out_free_fh:
kfree(mntfh);
kfree(data);
return error;

out_free:
Expand All @@ -2531,6 +2542,102 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
goto out;
}

static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type,
int flags, void *data, const char *hostname)
{
struct vfsmount *root_mnt;
char *root_devname;
size_t len;

len = strlen(hostname) + 3;
root_devname = kmalloc(len, GFP_KERNEL);
if (root_devname == NULL)
return ERR_PTR(-ENOMEM);
snprintf(root_devname, len, "%s:/", hostname);
root_mnt = vfs_kern_mount(fs_type, flags, root_devname, data);
kfree(root_devname);
return root_mnt;
}

static int nfs_follow_remote_path(struct vfsmount *root_mnt,
const char *export_path, struct vfsmount *mnt_target)
{
struct mnt_namespace *ns_private;
struct nameidata nd;
struct super_block *s;
int ret;

ns_private = create_mnt_ns(root_mnt);
ret = PTR_ERR(ns_private);
if (IS_ERR(ns_private))
goto out_mntput;

ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt,
export_path, LOOKUP_FOLLOW, &nd);

put_mnt_ns(ns_private);

if (ret != 0)
goto out_err;

s = nd.path.mnt->mnt_sb;
atomic_inc(&s->s_active);
mnt_target->mnt_sb = s;
mnt_target->mnt_root = dget(nd.path.dentry);

path_put(&nd.path);
down_write(&s->s_umount);
return 0;
out_mntput:
mntput(root_mnt);
out_err:
return ret;
}

/*
* Get the superblock for an NFS4 mountpoint
*/
static int nfs4_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
{
struct nfs_parsed_mount_data *data;
char *export_path;
struct vfsmount *root_mnt;
int error = -ENOMEM;

data = kzalloc(sizeof(*data), GFP_KERNEL);
if (data == NULL)
goto out_free_data;

/* Validate the mount data */
error = nfs4_validate_mount_data(raw_data, data, dev_name);
if (error < 0)
goto out;

export_path = data->nfs_server.export_path;
data->nfs_server.export_path = "/";
root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, data,
data->nfs_server.hostname);
data->nfs_server.export_path = export_path;

error = PTR_ERR(root_mnt);
if (IS_ERR(root_mnt))
goto out;

error = nfs_follow_remote_path(root_mnt, export_path, mnt);

out:
kfree(data->client_address);
kfree(data->nfs_server.export_path);
kfree(data->nfs_server.hostname);
kfree(data->fscache_uniq);
out_free_data:
kfree(data);
dprintk("<-- nfs4_get_sb() = %d%s\n", error,
error != 0 ? " [error]" : "");
return error;
}

static void nfs4_kill_super(struct super_block *sb)
{
struct nfs_server *server = NFS_SB(sb);
Expand Down Expand Up @@ -2627,12 +2734,9 @@ static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags,
return error;
}

/*
* Create an NFS4 server record on referral traversal
*/
static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags,
const char *dev_name, void *raw_data,
struct vfsmount *mnt)
static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *raw_data,
struct vfsmount *mnt)
{
struct nfs_clone_mount *data = raw_data;
struct super_block *s;
Expand Down Expand Up @@ -2711,4 +2815,36 @@ static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags,
return error;
}

/*
* Create an NFS4 server record on referral traversal
*/
static int nfs4_referral_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *raw_data,
struct vfsmount *mnt)
{
struct nfs_clone_mount *data = raw_data;
char *export_path;
struct vfsmount *root_mnt;
int error;

dprintk("--> nfs4_referral_get_sb()\n");

export_path = data->mnt_path;
data->mnt_path = "/";

root_mnt = nfs_do_root_mount(&nfs4_remote_referral_fs_type,
flags, data, data->hostname);
data->mnt_path = export_path;

error = PTR_ERR(root_mnt);
if (IS_ERR(root_mnt))
goto out;

error = nfs_follow_remote_path(root_mnt, export_path, mnt);
out:
dprintk("<-- nfs4_referral_get_sb() = %d%s\n", error,
error != 0 ? " [error]" : "");
return error;
}

#endif /* CONFIG_NFS_V4 */

0 comments on commit ebefe70

Please sign in to comment.