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: Ilya Dryomov idryo...@gmail.com
---
fs/btrfs/volumes.c | 150
fs/btrfs/volumes.h |3 ++
2 files changed, 96 insertions(+), 57 deletions(-)
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index ae1bcb0..fe52704 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -101,6 +101,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,
u64 devid, u8 *uuid)
{
@@ -414,17 +435,12 @@ static noinline int device_list_add(const char *path,
if (fs_devices-opened)
return -EBUSY;
- device = kzalloc(sizeof(*device), GFP_NOFS);
- if (!device) {
+ device = btrfs_alloc_device(NULL, devid,
+ disk_super-dev_item.uuid);
+ if (IS_ERR(device)) {
/* 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);
if (!name) {
@@ -432,15 +448,6 @@ static noinline int device_list_add(const char *path,
return -ENOMEM;
}
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);
list_add_rcu(device-dev_list, fs_devices-devices);
@@ -491,8 +498,9 @@ static struct btrfs_fs_devices *clone_fs_devices(struct
btrfs_fs_devices *orig)
list_for_each_entry(orig_dev, orig-devices, dev_list) {
struct rcu_string *name;
- device = kzalloc(sizeof(*device), GFP_NOFS);
- if (!device)
+ device = btrfs_alloc_device(NULL, orig_dev-devid,
+ orig_dev-uuid);
+ if (IS_ERR(device))
goto error;
/*
@@ -506,13 +514,6 @@ static struct btrfs_fs_devices *clone_fs_devices(struct
btrfs_fs_devices *orig)
}
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);
device-fs_devices = fs_devices;
fs_devices-num_devices++;
@@ -1956,10 +1957,10 @@ int btrfs_init_new_device(struct btrfs_root *root, char
*device_path)
}
mutex_unlock(root-fs_info-fs_devices-device_list_mutex);
- device = kzalloc(sizeof(*device), GFP_NOFS);
- if (!device) {
+ device = btrfs_alloc_device(root-fs_info, NULL, NULL);
+ if (IS_ERR(device)) {
/* we can safely leave the fs_devices entry around */
- ret = -ENOMEM;
+ ret = PTR_ERR(device);
goto