]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - fs/btrfs/super.c
Btrfs: Add support for device scanning and detection ioctls
[mv-sheeva.git] / fs / btrfs / super.c
index f8a1016600b182ae31814dba3852fb35885ab69c..9624923a33dc03f8006988d3f63aa72d49ff90f8 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/parser.h>
 #include <linux/ctype.h>
 #include <linux/namei.h>
+#include <linux/miscdevice.h>
 #include "ctree.h"
 #include "disk-io.h"
 #include "transaction.h"
@@ -43,6 +44,7 @@
 #include "ioctl.h"
 #include "print-tree.h"
 #include "xattr.h"
+#include "volumes.h"
 
 #define BTRFS_SUPER_MAGIC 0x9123683E
 
@@ -64,7 +66,7 @@ static void btrfs_put_super (struct super_block * sb)
 
 enum {
        Opt_subvol, Opt_nodatasum, Opt_nodatacow, Opt_max_extent,
-       Opt_alloc_start, Opt_nobarrier, Opt_ssd, Opt_err,
+       Opt_max_inline, Opt_alloc_start, Opt_nobarrier, Opt_ssd, Opt_err,
 };
 
 static match_table_t tokens = {
@@ -73,6 +75,7 @@ static match_table_t tokens = {
        {Opt_nodatacow, "nodatacow"},
        {Opt_nobarrier, "nobarrier"},
        {Opt_max_extent, "max_extent=%s"},
+       {Opt_max_inline, "max_inline=%s"},
        {Opt_alloc_start, "alloc_start=%s"},
        {Opt_ssd, "ssd"},
        {Opt_err, NULL}
@@ -178,6 +181,22 @@ static int parse_options (char * options,
                                }
                        }
                        break;
+               case Opt_max_inline:
+                       if (info) {
+                               char *num = match_strdup(&args[0]);
+                               if (num) {
+                                       info->max_inline =
+                                               btrfs_parse_size(num);
+                                       kfree(num);
+
+                                       info->max_inline = max_t(u64,
+                                                        info->max_inline,
+                                                        root->sectorsize);
+                                       printk("btrfs: max_inline at %Lu\n",
+                                              info->max_inline);
+                               }
+                       }
+                       break;
                case Opt_alloc_start:
                        if (info) {
                                char *num = match_strdup(&args[0]);
@@ -198,7 +217,9 @@ static int parse_options (char * options,
        return 1;
 }
 
-static int btrfs_fill_super(struct super_block * sb, void * data, int silent)
+static int btrfs_fill_super(struct super_block * sb,
+                           struct btrfs_fs_devices *fs_devices,
+                           void * data, int silent)
 {
        struct inode * inode;
        struct dentry * root_dentry;
@@ -213,7 +234,7 @@ static int btrfs_fill_super(struct super_block * sb, void * data, int silent)
        sb->s_xattr = btrfs_xattr_handlers;
        sb->s_time_gran = 1;
 
-       tree_root = open_ctree(sb);
+       tree_root = open_ctree(sb, fs_devices);
 
        if (!tree_root || IS_ERR(tree_root)) {
                printk("btrfs: open_ctree failed\n");
@@ -255,6 +276,11 @@ static int btrfs_fill_super(struct super_block * sb, void * data, int silent)
 
        sb->s_root = root_dentry;
        btrfs_transaction_queue_work(tree_root, HZ * 30);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
+       save_mount_options(sb, data);
+#endif
+
        return 0;
 
 fail_close:
@@ -311,18 +337,23 @@ static int test_bdev_super(struct super_block *s, void *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;
+       struct btrfs_fs_devices *fs_devices = NULL;
        int error = 0;
 
-       bdev = open_bdev_excl(dev_name, flags, fs_type);
-       if (IS_ERR(bdev))
-               return PTR_ERR(bdev);
+       error = btrfs_scan_one_device(dev_name, flags, fs_type, &fs_devices);
+       if (error)
+               return error;
 
+       error = btrfs_open_devices(fs_devices, flags, fs_type);
+       if (error)
+               return error;
+
+       bdev = fs_devices->lowest_bdev;
        /*
         * once the super is inserted into the list by sget, s_umount
         * will protect the lockfs code from trying to start a snapshot
@@ -349,7 +380,8 @@ int btrfs_get_sb_bdev(struct file_system_type *fs_type,
                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);
+               error = btrfs_fill_super(s, fs_devices, data,
+                                        flags & MS_SILENT ? 1 : 0);
                if (error) {
                        up_write(&s->s_umount);
                        deactivate_super(s);
@@ -385,7 +417,7 @@ int btrfs_get_sb_bdev(struct file_system_type *fs_type,
 error_s:
        error = PTR_ERR(s);
 error_bdev:
-       close_bdev_excl(bdev);
+       btrfs_close_devices(fs_devices);
 error:
        return error;
 }
@@ -398,8 +430,7 @@ static int btrfs_get_sb(struct file_system_type *fs_type,
        char *subvol_name = NULL;
 
        parse_options((char *)data, NULL, &subvol_name);
-       ret = btrfs_get_sb_bdev(fs_type, flags, dev_name, data,
-                       btrfs_fill_super, mnt,
+       ret = btrfs_get_sb_bdev(fs_type, flags, dev_name, data, mnt,
                        subvol_name ? subvol_name : "default");
        if (subvol_name)
                kfree(subvol_name);
@@ -429,6 +460,32 @@ static struct file_system_type btrfs_fs_type = {
        .kill_sb        = kill_block_super,
        .fs_flags       = FS_REQUIRES_DEV,
 };
+
+static long btrfs_control_ioctl(struct file *file, unsigned int cmd,
+                               unsigned long arg)
+{
+       struct btrfs_ioctl_vol_args *vol;
+       struct btrfs_fs_devices *fs_devices;
+       int ret;
+       int len;
+
+       vol = kmalloc(sizeof(*vol), GFP_KERNEL);
+       if (copy_from_user(vol, (void __user *)arg, sizeof(*vol))) {
+               ret = -EFAULT;
+               goto out;
+       }
+       len = strnlen(vol->name, BTRFS_PATH_NAME_MAX);
+       switch (cmd) {
+       case BTRFS_IOC_SCAN_DEV:
+               ret = btrfs_scan_one_device(vol->name, MS_RDONLY,
+                                           &btrfs_fs_type, &fs_devices);
+               break;
+       }
+out:
+       kfree(vol);
+       return 0;
+}
+
 static void btrfs_write_super_lockfs(struct super_block *sb)
 {
        struct btrfs_root *root = btrfs_sb(sb);
@@ -445,9 +502,13 @@ static struct super_operations btrfs_super_ops = {
        .delete_inode   = btrfs_delete_inode,
        .put_inode      = btrfs_put_inode,
        .put_super      = btrfs_put_super,
-       .read_inode     = btrfs_read_locked_inode,
        .write_super    = btrfs_write_super,
        .sync_fs        = btrfs_sync_fs,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
+       .read_inode     = btrfs_read_locked_inode,
+#else
+       .show_options   = generic_show_options,
+#endif
        .write_inode    = btrfs_write_inode,
        .dirty_inode    = btrfs_dirty_inode,
        .alloc_inode    = btrfs_alloc_inode,
@@ -456,6 +517,30 @@ static struct super_operations btrfs_super_ops = {
        .write_super_lockfs = btrfs_write_super_lockfs,
        .unlockfs       = btrfs_unlockfs,
 };
+
+static const struct file_operations btrfs_ctl_fops = {
+       .unlocked_ioctl  = btrfs_control_ioctl,
+       .compat_ioctl = btrfs_control_ioctl,
+       .owner   = THIS_MODULE,
+};
+
+static struct miscdevice btrfs_misc = {
+       .minor          = MISC_DYNAMIC_MINOR,
+       .name           = "btrfs-control",
+       .fops           = &btrfs_ctl_fops
+};
+
+static int btrfs_interface_init(void)
+{
+       return misc_register(&btrfs_misc);
+}
+
+void btrfs_interface_exit(void)
+{
+       if (misc_deregister(&btrfs_misc) < 0)
+               printk("misc_deregister failed for control device");
+}
+
 static int __init init_btrfs_fs(void)
 {
        int err;
@@ -477,11 +562,16 @@ static int __init init_btrfs_fs(void)
        if (err)
                goto free_extent_io;
 
-       err = register_filesystem(&btrfs_fs_type);
+       err = btrfs_interface_init();
        if (err)
                goto free_extent_map;
+       err = register_filesystem(&btrfs_fs_type);
+       if (err)
+               goto unregister_ioctl;
        return 0;
 
+unregister_ioctl:
+       btrfs_interface_exit();
 free_extent_map:
        extent_map_exit();
 free_extent_io:
@@ -500,8 +590,10 @@ static void __exit exit_btrfs_fs(void)
        btrfs_destroy_cachep();
        extent_map_exit();
        extent_io_exit();
+       btrfs_interface_exit();
        unregister_filesystem(&btrfs_fs_type);
        btrfs_exit_sysfs();
+       btrfs_cleanup_fs_uuids();
 }
 
 module_init(init_btrfs_fs)