Btrfs: Add new ioctl to add devices
authorChris Mason <chris.mason@oracle.com>
Mon, 28 Apr 2008 19:29:42 +0000 (15:29 -0400)
committerChris Mason <chris.mason@oracle.com>
Thu, 25 Sep 2008 15:04:02 +0000 (11:04 -0400)
Signed-off-by: Chris Mason <chris.mason@oracle.com>
fs/btrfs/ctree.h
fs/btrfs/inode.c
fs/btrfs/ioctl.h
fs/btrfs/super.c
fs/btrfs/volumes.c
fs/btrfs/volumes.h

index ac7106ec5357000b532803b39a5bc858d4bb92d9..b9257b37bb9635a74d486af56aec84f7b0fa5aeb 100644 (file)
@@ -551,6 +551,8 @@ struct btrfs_fs_info {
        u64 data_alloc_profile;
        u64 metadata_alloc_profile;
        u64 system_alloc_profile;
+
+       void *bdev_holder;
 };
 
 /*
index ab707c0930df05e0998b1f03a21ed04f36d2c5c7..1a74b5018699d5c5d181afe5e75e84e739ac6e82 100644 (file)
@@ -3070,6 +3070,27 @@ static int btrfs_ioctl_defrag(struct file *file)
        return 0;
 }
 
+long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg)
+{
+       struct btrfs_ioctl_vol_args *vol_args;
+       int ret;
+
+       vol_args = kmalloc(sizeof(*vol_args), GFP_NOFS);
+
+       if (!vol_args)
+               return -ENOMEM;
+
+       if (copy_from_user(vol_args, arg, sizeof(*vol_args))) {
+               ret = -EFAULT;
+               goto out;
+       }
+       ret = btrfs_init_new_device(root, vol_args->name);
+
+out:
+       kfree(vol_args);
+       return ret;
+}
+
 long btrfs_ioctl(struct file *file, unsigned int
                cmd, unsigned long arg)
 {
@@ -3082,6 +3103,8 @@ long btrfs_ioctl(struct file *file, unsigned int
                return btrfs_ioctl_defrag(file);
        case BTRFS_IOC_RESIZE:
                return btrfs_ioctl_resize(root, (void __user *)arg);
+       case BTRFS_IOC_ADD_DEV:
+               return btrfs_ioctl_add_dev(root, (void __user *)arg);
        }
 
        return -ENOTTY;
index 4551e82013c8ecf99f7ce4382d2720f84e1221c9..8ad35fc4ba56ffc3fe6f602428e22b89af44248f 100644 (file)
@@ -36,4 +36,10 @@ struct btrfs_ioctl_vol_args {
                                   struct btrfs_ioctl_vol_args)
 #define BTRFS_IOC_SCAN_DEV _IOW(BTRFS_IOCTL_MAGIC, 4, \
                                   struct btrfs_ioctl_vol_args)
+#define BTRFS_IOC_ADD_DEV _IOW(BTRFS_IOCTL_MAGIC, 10, \
+                                  struct btrfs_ioctl_vol_args)
+#define BTRFS_IOC_RM_DEV _IOW(BTRFS_IOCTL_MAGIC, 11, \
+                                  struct btrfs_ioctl_vol_args)
+#define BTRFS_IOC_BALANCE _IOW(BTRFS_IOCTL_MAGIC, 12, \
+                                  struct btrfs_ioctl_vol_args)
 #endif
index 892864906880e0442cd1f8d49eac06426892b864..7153dfaa34047b1537fc1054252ffdbb9902bcab 100644 (file)
@@ -388,6 +388,7 @@ int btrfs_get_sb_bdev(struct file_system_type *fs_type,
                        goto error;
                }
 
+               btrfs_sb(s)->fs_info->bdev_holder = fs_type;
                s->s_flags |= MS_ACTIVE;
        }
 
index a2c56de1548a8fb7e2c946c7588e39aa6d52c47b..b93c15aa17db054814e3012bf12e15d2b7dc5f6e 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/bio.h>
 #include <linux/buffer_head.h>
 #include <linux/blkdev.h>
+#include <linux/random.h>
 #include <asm/div64.h>
 #include "ctree.h"
 #include "extent_map.h"
@@ -592,6 +593,80 @@ out:
        return ret;
 }
 
+int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
+{
+       struct btrfs_trans_handle *trans;
+       struct btrfs_device *device;
+       struct block_device *bdev;
+       struct list_head *cur;
+       struct list_head *devices;
+       u64 total_bytes;
+       int ret = 0;
+
+
+       bdev = open_bdev_excl(device_path, 0, root->fs_info->bdev_holder);
+       if (!bdev) {
+               return -EIO;
+       }
+       mutex_lock(&root->fs_info->fs_mutex);
+       trans = btrfs_start_transaction(root, 1);
+       devices = &root->fs_info->fs_devices->devices;
+       list_for_each(cur, devices) {
+               device = list_entry(cur, struct btrfs_device, dev_list);
+               if (device->bdev == bdev) {
+                       ret = -EEXIST;
+                       goto out;
+               }
+       }
+
+       device = kzalloc(sizeof(*device), GFP_NOFS);
+       if (!device) {
+               /* we can safely leave the fs_devices entry around */
+               ret = -ENOMEM;
+               goto out_close_bdev;
+       }
+
+       device->barriers = 1;
+       generate_random_uuid(device->uuid);
+       spin_lock_init(&device->io_lock);
+       device->name = kstrdup(device_path, GFP_NOFS);
+       if (!device->name) {
+               kfree(device);
+               goto out_close_bdev;
+       }
+       device->io_width = root->sectorsize;
+       device->io_align = root->sectorsize;
+       device->sector_size = root->sectorsize;
+       device->total_bytes = i_size_read(bdev->bd_inode);
+       device->dev_root = root->fs_info->dev_root;
+       device->bdev = bdev;
+
+       ret = btrfs_add_device(trans, root, device);
+       if (ret)
+               goto out_close_bdev;
+
+       total_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy);
+       btrfs_set_super_total_bytes(&root->fs_info->super_copy,
+                                   total_bytes + device->total_bytes);
+
+       total_bytes = btrfs_super_num_devices(&root->fs_info->super_copy);
+       btrfs_set_super_num_devices(&root->fs_info->super_copy,
+                                   total_bytes + 1);
+
+       list_add(&device->dev_list, &root->fs_info->fs_devices->devices);
+       list_add(&device->dev_alloc_list,
+                &root->fs_info->fs_devices->alloc_list);
+       root->fs_info->fs_devices->num_devices++;
+out:
+       btrfs_end_transaction(trans, root);
+       mutex_unlock(&root->fs_info->fs_mutex);
+       return ret;
+
+out_close_bdev:
+       close_bdev_excl(bdev);
+       goto out;
+}
+
 int btrfs_update_device(struct btrfs_trans_handle *trans,
                        struct btrfs_device *device)
 {
index 6fe8440b37a78bf2da83fba2cfcd60d19b492f68..6f173450378b121e6fbc20cc1eb6a7ca3f648ee6 100644 (file)
@@ -133,4 +133,5 @@ int btrfs_grow_device(struct btrfs_trans_handle *trans,
 struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid,
                                       u8 *uuid);
 int btrfs_shrink_device(struct btrfs_device *device, u64 new_size);
+int btrfs_init_new_device(struct btrfs_root *root, char *path);
 #endif