Commit 12bd2fc0 authored by Ilya Dryomov's avatar Ilya Dryomov Committed by Chris Mason

Btrfs: add btrfs_alloc_device and switch to it

Currently btrfs_device is allocated ad-hoc in a few different places,
and as a result not all fields are initialized properly.  In particular,
readahead state is only initialized in device_list_add (at scan time),
and not in btrfs_init_new_device (when the new device is added with
'btrfs dev add').  Fix this by adding an allocation helper and switch
everybody but __btrfs_close_devices to it.  (__btrfs_close_devices is
dealt with in a later commit.)
Signed-off-by: default avatarIlya Dryomov <idryomov@gmail.com>
Signed-off-by: default avatarJosef Bacik <jbacik@fusionio.com>
Signed-off-by: default avatarChris Mason <chris.mason@fusionio.com>
parent 53f10659
...@@ -102,6 +102,27 @@ void btrfs_cleanup_fs_uuids(void) ...@@ -102,6 +102,27 @@ void btrfs_cleanup_fs_uuids(void)
} }
} }
static struct btrfs_device *__alloc_device(void)
{
struct btrfs_device *dev;
dev = kzalloc(sizeof(*dev), GFP_NOFS);
if (!dev)
return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&dev->dev_list);
INIT_LIST_HEAD(&dev->dev_alloc_list);
spin_lock_init(&dev->io_lock);
spin_lock_init(&dev->reada_lock);
atomic_set(&dev->reada_in_flight, 0);
INIT_RADIX_TREE(&dev->reada_zones, GFP_NOFS & ~__GFP_WAIT);
INIT_RADIX_TREE(&dev->reada_extents, GFP_NOFS & ~__GFP_WAIT);
return dev;
}
static noinline struct btrfs_device *__find_device(struct list_head *head, static noinline struct btrfs_device *__find_device(struct list_head *head,
u64 devid, u8 *uuid) u64 devid, u8 *uuid)
{ {
...@@ -415,17 +436,12 @@ static noinline int device_list_add(const char *path, ...@@ -415,17 +436,12 @@ static noinline int device_list_add(const char *path,
if (fs_devices->opened) if (fs_devices->opened)
return -EBUSY; return -EBUSY;
device = kzalloc(sizeof(*device), GFP_NOFS); device = btrfs_alloc_device(NULL, &devid,
if (!device) { disk_super->dev_item.uuid);
if (IS_ERR(device)) {
/* we can safely leave the fs_devices entry around */ /* we can safely leave the fs_devices entry around */
return -ENOMEM; return PTR_ERR(device);
} }
device->devid = devid;
device->dev_stats_valid = 0;
device->work.func = pending_bios_fn;
memcpy(device->uuid, disk_super->dev_item.uuid,
BTRFS_UUID_SIZE);
spin_lock_init(&device->io_lock);
name = rcu_string_strdup(path, GFP_NOFS); name = rcu_string_strdup(path, GFP_NOFS);
if (!name) { if (!name) {
...@@ -433,15 +449,6 @@ static noinline int device_list_add(const char *path, ...@@ -433,15 +449,6 @@ static noinline int device_list_add(const char *path,
return -ENOMEM; return -ENOMEM;
} }
rcu_assign_pointer(device->name, name); rcu_assign_pointer(device->name, name);
INIT_LIST_HEAD(&device->dev_alloc_list);
/* init readahead state */
spin_lock_init(&device->reada_lock);
device->reada_curr_zone = NULL;
atomic_set(&device->reada_in_flight, 0);
device->reada_next = 0;
INIT_RADIX_TREE(&device->reada_zones, GFP_NOFS & ~__GFP_WAIT);
INIT_RADIX_TREE(&device->reada_extents, GFP_NOFS & ~__GFP_WAIT);
mutex_lock(&fs_devices->device_list_mutex); mutex_lock(&fs_devices->device_list_mutex);
list_add_rcu(&device->dev_list, &fs_devices->devices); list_add_rcu(&device->dev_list, &fs_devices->devices);
...@@ -492,8 +499,9 @@ static struct btrfs_fs_devices *clone_fs_devices(struct btrfs_fs_devices *orig) ...@@ -492,8 +499,9 @@ static struct btrfs_fs_devices *clone_fs_devices(struct btrfs_fs_devices *orig)
list_for_each_entry(orig_dev, &orig->devices, dev_list) { list_for_each_entry(orig_dev, &orig->devices, dev_list) {
struct rcu_string *name; struct rcu_string *name;
device = kzalloc(sizeof(*device), GFP_NOFS); device = btrfs_alloc_device(NULL, &orig_dev->devid,
if (!device) orig_dev->uuid);
if (IS_ERR(device))
goto error; goto error;
/* /*
...@@ -507,13 +515,6 @@ static struct btrfs_fs_devices *clone_fs_devices(struct btrfs_fs_devices *orig) ...@@ -507,13 +515,6 @@ static struct btrfs_fs_devices *clone_fs_devices(struct btrfs_fs_devices *orig)
} }
rcu_assign_pointer(device->name, name); rcu_assign_pointer(device->name, name);
device->devid = orig_dev->devid;
device->work.func = pending_bios_fn;
memcpy(device->uuid, orig_dev->uuid, sizeof(device->uuid));
spin_lock_init(&device->io_lock);
INIT_LIST_HEAD(&device->dev_list);
INIT_LIST_HEAD(&device->dev_alloc_list);
list_add(&device->dev_list, &fs_devices->devices); list_add(&device->dev_list, &fs_devices->devices);
device->fs_devices = fs_devices; device->fs_devices = fs_devices;
fs_devices->num_devices++; fs_devices->num_devices++;
...@@ -1959,10 +1960,10 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) ...@@ -1959,10 +1960,10 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
} }
mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
device = kzalloc(sizeof(*device), GFP_NOFS); device = btrfs_alloc_device(root->fs_info, NULL, NULL);
if (!device) { if (IS_ERR(device)) {
/* we can safely leave the fs_devices entry around */ /* we can safely leave the fs_devices entry around */
ret = -ENOMEM; ret = PTR_ERR(device);
goto error; goto error;
} }
...@@ -1974,13 +1975,6 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) ...@@ -1974,13 +1975,6 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
} }
rcu_assign_pointer(device->name, name); rcu_assign_pointer(device->name, name);
ret = find_next_devid(root->fs_info, &device->devid);
if (ret) {
rcu_string_free(device->name);
kfree(device);
goto error;
}
trans = btrfs_start_transaction(root, 0); trans = btrfs_start_transaction(root, 0);
if (IS_ERR(trans)) { if (IS_ERR(trans)) {
rcu_string_free(device->name); rcu_string_free(device->name);
...@@ -1995,9 +1989,6 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) ...@@ -1995,9 +1989,6 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
if (blk_queue_discard(q)) if (blk_queue_discard(q))
device->can_discard = 1; device->can_discard = 1;
device->writeable = 1; device->writeable = 1;
device->work.func = pending_bios_fn;
generate_random_uuid(device->uuid);
spin_lock_init(&device->io_lock);
device->generation = trans->transid; device->generation = trans->transid;
device->io_width = root->sectorsize; device->io_width = root->sectorsize;
device->io_align = root->sectorsize; device->io_align = root->sectorsize;
...@@ -2124,6 +2115,7 @@ int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path, ...@@ -2124,6 +2115,7 @@ int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path,
struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_fs_info *fs_info = root->fs_info;
struct list_head *devices; struct list_head *devices;
struct rcu_string *name; struct rcu_string *name;
u64 devid = BTRFS_DEV_REPLACE_DEVID;
int ret = 0; int ret = 0;
*device_out = NULL; *device_out = NULL;
...@@ -2145,9 +2137,9 @@ int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path, ...@@ -2145,9 +2137,9 @@ int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path,
} }
} }
device = kzalloc(sizeof(*device), GFP_NOFS); device = btrfs_alloc_device(NULL, &devid, NULL);
if (!device) { if (IS_ERR(device)) {
ret = -ENOMEM; ret = PTR_ERR(device);
goto error; goto error;
} }
...@@ -2164,10 +2156,6 @@ int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path, ...@@ -2164,10 +2156,6 @@ int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path,
device->can_discard = 1; device->can_discard = 1;
mutex_lock(&root->fs_info->fs_devices->device_list_mutex); mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
device->writeable = 1; device->writeable = 1;
device->work.func = pending_bios_fn;
generate_random_uuid(device->uuid);
device->devid = BTRFS_DEV_REPLACE_DEVID;
spin_lock_init(&device->io_lock);
device->generation = 0; device->generation = 0;
device->io_width = root->sectorsize; device->io_width = root->sectorsize;
device->io_align = root->sectorsize; device->io_align = root->sectorsize;
...@@ -5572,23 +5560,72 @@ static struct btrfs_device *add_missing_dev(struct btrfs_root *root, ...@@ -5572,23 +5560,72 @@ static struct btrfs_device *add_missing_dev(struct btrfs_root *root,
struct btrfs_device *device; struct btrfs_device *device;
struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices; struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;
device = kzalloc(sizeof(*device), GFP_NOFS); device = btrfs_alloc_device(NULL, &devid, dev_uuid);
if (!device) if (IS_ERR(device))
return NULL; return NULL;
list_add(&device->dev_list,
&fs_devices->devices); list_add(&device->dev_list, &fs_devices->devices);
device->devid = devid;
device->work.func = pending_bios_fn;
device->fs_devices = fs_devices; device->fs_devices = fs_devices;
device->missing = 1;
fs_devices->num_devices++; fs_devices->num_devices++;
device->missing = 1;
fs_devices->missing_devices++; fs_devices->missing_devices++;
spin_lock_init(&device->io_lock);
INIT_LIST_HEAD(&device->dev_alloc_list);
memcpy(device->uuid, dev_uuid, BTRFS_UUID_SIZE);
return device; return device;
} }
/**
* btrfs_alloc_device - allocate struct btrfs_device
* @fs_info: used only for generating a new devid, can be NULL if
* devid is provided (i.e. @devid != NULL).
* @devid: a pointer to devid for this device. If NULL a new devid
* is generated.
* @uuid: a pointer to UUID for this device. If NULL a new UUID
* is generated.
*
* Return: a pointer to a new &struct btrfs_device on success; ERR_PTR()
* on error. Returned struct is not linked onto any lists and can be
* destroyed with kfree() right away.
*/
struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
const u64 *devid,
const u8 *uuid)
{
struct btrfs_device *dev;
u64 tmp;
if (!devid && !fs_info) {
WARN_ON(1);
return ERR_PTR(-EINVAL);
}
dev = __alloc_device();
if (IS_ERR(dev))
return dev;
if (devid)
tmp = *devid;
else {
int ret;
ret = find_next_devid(fs_info, &tmp);
if (ret) {
kfree(dev);
return ERR_PTR(ret);
}
}
dev->devid = tmp;
if (uuid)
memcpy(dev->uuid, uuid, BTRFS_UUID_SIZE);
else
generate_random_uuid(dev->uuid);
dev->work.func = pending_bios_fn;
return dev;
}
static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
struct extent_buffer *leaf, struct extent_buffer *leaf,
struct btrfs_chunk *chunk) struct btrfs_chunk *chunk)
......
...@@ -305,6 +305,9 @@ void btrfs_close_extra_devices(struct btrfs_fs_info *fs_info, ...@@ -305,6 +305,9 @@ void btrfs_close_extra_devices(struct btrfs_fs_info *fs_info,
int btrfs_find_device_missing_or_by_path(struct btrfs_root *root, int btrfs_find_device_missing_or_by_path(struct btrfs_root *root,
char *device_path, char *device_path,
struct btrfs_device **device); struct btrfs_device **device);
struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
const u64 *devid,
const u8 *uuid);
int btrfs_rm_device(struct btrfs_root *root, char *device_path); int btrfs_rm_device(struct btrfs_root *root, char *device_path);
void btrfs_cleanup_fs_uuids(void); void btrfs_cleanup_fs_uuids(void);
int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len); int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment