diff options
author | Yan <yanzheng@21cn.com> | 2007-08-29 09:11:44 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-08-29 09:11:44 -0400 |
commit | 4b82d6e4a592016ac75e756ca519923e0fc18f00 (patch) | |
tree | 19b272d2d0558b8e6749aec7a79daff522f2cb44 /fs/btrfs/super.c | |
parent | 1b4ab1bb4bbd3045cd041259c30b826654599e96 (diff) | |
download | kernel_samsung_smdk4412-4b82d6e4a592016ac75e756ca519923e0fc18f00.zip kernel_samsung_smdk4412-4b82d6e4a592016ac75e756ca519923e0fc18f00.tar.gz kernel_samsung_smdk4412-4b82d6e4a592016ac75e756ca519923e0fc18f00.tar.bz2 |
Btrfs: Add mount into directory support
Modified form of original patch from Christoph Hellwig to make btrfs
mount into the default subvolume by default.
mount /dev/somedevice:subvolumename to get other subvolumes or
mount /dev/somedevice:. to get the root
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/super.c')
-rw-r--r-- | fs/btrfs/super.c | 123 |
1 files changed, 120 insertions, 3 deletions
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index a68101a..8a94be1 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -16,6 +16,7 @@ * Boston, MA 021110-1307, USA. */ +#include <linux/blkdev.h> #include <linux/module.h> #include <linux/buffer_head.h> #include <linux/fs.h> @@ -26,6 +27,7 @@ #include <linux/string.h> #include <linux/smp_lock.h> #include <linux/backing-dev.h> +#include <linux/mount.h> #include <linux/mpage.h> #include <linux/swap.h> #include <linux/writeback.h> @@ -145,11 +147,126 @@ static void btrfs_write_super(struct super_block *sb) sb->s_dirt = 0; } +/* + * This is almost a copy of get_sb_bdev in fs/super.c. + * We need the local copy to allow direct mounting of + * subvolumes, but this could be easily integrated back + * into the generic version. --hch + */ + +/* start copy & paste */ +static int set_bdev_super(struct super_block *s, void *data) +{ + s->s_bdev = data; + s->s_dev = s->s_bdev->bd_dev; + return 0; +} + +static int test_bdev_super(struct super_block *s, void *data) +{ + return (void *)s->s_bdev == data; +} + +int btrfs_get_sb_bdev(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, + int (*fill_super)(struct super_block *, void *, int), + struct vfsmount *mnt, const char *subvol) +{ + struct block_device *bdev = NULL; + struct super_block *s; + struct dentry *root; + int error = 0; + + bdev = open_bdev_excl(dev_name, flags, fs_type); + if (IS_ERR(bdev)) + return PTR_ERR(bdev); + + /* + * once the super is inserted into the list by sget, s_umount + * will protect the lockfs code from trying to start a snapshot + * while we are mounting + */ + down(&bdev->bd_mount_sem); + s = sget(fs_type, test_bdev_super, set_bdev_super, bdev); + up(&bdev->bd_mount_sem); + if (IS_ERR(s)) + goto error_s; + + if (s->s_root) { + if ((flags ^ s->s_flags) & MS_RDONLY) { + up_write(&s->s_umount); + deactivate_super(s); + error = -EBUSY; + goto error_bdev; + } + + close_bdev_excl(bdev); + } else { + char b[BDEVNAME_SIZE]; + + s->s_flags = flags; + strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id)); + sb_set_blocksize(s, block_size(bdev)); + error = fill_super(s, data, flags & MS_SILENT ? 1 : 0); + if (error) { + up_write(&s->s_umount); + deactivate_super(s); + goto error; + } + + s->s_flags |= MS_ACTIVE; + } + + if (subvol) { + root = lookup_one_len(subvol, s->s_root, strlen(subvol)); + if (IS_ERR(root)) { + up_write(&s->s_umount); + deactivate_super(s); + error = PTR_ERR(root); + goto error; + } + if (!root->d_inode) { + dput(root); + up_write(&s->s_umount); + deactivate_super(s); + error = -ENXIO; + goto error; + } + } else { + root = dget(s->s_root); + } + + mnt->mnt_sb = s; + mnt->mnt_root = root; + return 0; + +error_s: + error = PTR_ERR(s); +error_bdev: + close_bdev_excl(bdev); +error: + return error; +} +/* end copy & paste */ + static int btrfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) + int flags, const char *identifier, void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, - btrfs_fill_super, mnt); + int ret; + char *_identifier = kstrdup(identifier, GFP_KERNEL); + char *subvol_name; + const char *dev_name; + + subvol_name = _identifier; + dev_name = strsep(&subvol_name, ":"); + if (!dev_name) + return -ENOMEM; + + ret = btrfs_get_sb_bdev(fs_type, flags, dev_name, data, + btrfs_fill_super, mnt, + subvol_name ? subvol_name : "default"); + kfree(_identifier); + return ret; } static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) |