summaryrefslogtreecommitdiff
path: root/volumes.c
diff options
context:
space:
mode:
Diffstat (limited to 'volumes.c')
-rw-r--r--volumes.c97
1 files changed, 85 insertions, 12 deletions
diff --git a/volumes.c b/volumes.c
index edad367b..c6e34321 100644
--- a/volumes.c
+++ b/volumes.c
@@ -30,6 +30,72 @@
#include "utils.h"
#include "kernel-lib/raid56.h"
+const struct btrfs_raid_attr btrfs_raid_array[BTRFS_NR_RAID_TYPES] = {
+ [BTRFS_RAID_RAID10] = {
+ .sub_stripes = 2,
+ .dev_stripes = 1,
+ .devs_max = 0, /* 0 == as many as possible */
+ .devs_min = 4,
+ .tolerated_failures = 1,
+ .devs_increment = 2,
+ .ncopies = 2,
+ },
+ [BTRFS_RAID_RAID1] = {
+ .sub_stripes = 1,
+ .dev_stripes = 1,
+ .devs_max = 2,
+ .devs_min = 2,
+ .tolerated_failures = 1,
+ .devs_increment = 2,
+ .ncopies = 2,
+ },
+ [BTRFS_RAID_DUP] = {
+ .sub_stripes = 1,
+ .dev_stripes = 2,
+ .devs_max = 1,
+ .devs_min = 1,
+ .tolerated_failures = 0,
+ .devs_increment = 1,
+ .ncopies = 2,
+ },
+ [BTRFS_RAID_RAID0] = {
+ .sub_stripes = 1,
+ .dev_stripes = 1,
+ .devs_max = 0,
+ .devs_min = 2,
+ .tolerated_failures = 0,
+ .devs_increment = 1,
+ .ncopies = 1,
+ },
+ [BTRFS_RAID_SINGLE] = {
+ .sub_stripes = 1,
+ .dev_stripes = 1,
+ .devs_max = 1,
+ .devs_min = 1,
+ .tolerated_failures = 0,
+ .devs_increment = 1,
+ .ncopies = 1,
+ },
+ [BTRFS_RAID_RAID5] = {
+ .sub_stripes = 1,
+ .dev_stripes = 1,
+ .devs_max = 0,
+ .devs_min = 2,
+ .tolerated_failures = 1,
+ .devs_increment = 1,
+ .ncopies = 2,
+ },
+ [BTRFS_RAID_RAID6] = {
+ .sub_stripes = 1,
+ .dev_stripes = 1,
+ .devs_max = 0,
+ .devs_min = 3,
+ .tolerated_failures = 2,
+ .devs_increment = 1,
+ .ncopies = 3,
+ },
+};
+
struct stripe {
struct btrfs_device *dev;
u64 physical;
@@ -54,14 +120,22 @@ static inline int nr_data_stripes(struct map_lookup *map)
static LIST_HEAD(fs_uuids);
-static struct btrfs_device *__find_device(struct list_head *head, u64 devid,
- u8 *uuid)
+/*
+ * Find a device specified by @devid or @uuid in the list of @fs_devices, or
+ * return NULL.
+ *
+ * If devid and uuid are both specified, the match must be exact, otherwise
+ * only devid is used.
+ */
+static struct btrfs_device *find_device(struct btrfs_fs_devices *fs_devices,
+ u64 devid, u8 *uuid)
{
+ struct list_head *head = &fs_devices->devices;
struct btrfs_device *dev;
list_for_each_entry(dev, head, dev_list) {
if (dev->devid == devid &&
- !memcmp(dev->uuid, uuid, BTRFS_UUID_SIZE)) {
+ (!uuid || !memcmp(dev->uuid, uuid, BTRFS_UUID_SIZE))) {
return dev;
}
}
@@ -100,7 +174,7 @@ static int device_list_add(const char *path,
fs_devices->lowest_devid = (u64)-1;
device = NULL;
} else {
- device = __find_device(&fs_devices->devices, devid,
+ device = find_device(fs_devices, devid,
disk_super->dev_item.uuid);
}
if (!device) {
@@ -450,10 +524,10 @@ out:
}
static int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes,
- u64 *start)
+ u64 *start, u64 *len)
{
/* FIXME use last free of some kind */
- return find_free_dev_extent_start(device, num_bytes, 0, start, NULL);
+ return find_free_dev_extent_start(device, num_bytes, 0, start, len);
}
static int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans,
@@ -477,7 +551,7 @@ static int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans,
* is responsible to make sure it's free.
*/
if (!convert) {
- ret = find_free_dev_extent(device, num_bytes, start);
+ ret = find_free_dev_extent(device, num_bytes, start, NULL);
if (ret)
goto err;
}
@@ -826,7 +900,7 @@ error:
return ret;
}
-#define BTRFS_MAX_DEVS(r) ((BTRFS_LEAF_DATA_SIZE(r->fs_info) \
+#define BTRFS_MAX_DEVS(info) ((BTRFS_LEAF_DATA_SIZE(info) \
- sizeof(struct btrfs_item) \
- sizeof(struct btrfs_chunk)) \
/ sizeof(struct btrfs_stripe) + 1)
@@ -882,12 +956,12 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
calc_size = SZ_1G;
max_chunk_size = 10 * calc_size;
min_stripe_size = SZ_64M;
- max_stripes = BTRFS_MAX_DEVS(chunk_root);
+ max_stripes = BTRFS_MAX_DEVS(info);
} else if (type & BTRFS_BLOCK_GROUP_METADATA) {
calc_size = SZ_1G;
max_chunk_size = 4 * calc_size;
min_stripe_size = SZ_32M;
- max_stripes = BTRFS_MAX_DEVS(chunk_root);
+ max_stripes = BTRFS_MAX_DEVS(info);
}
}
if (type & BTRFS_BLOCK_GROUP_RAID1) {
@@ -1616,8 +1690,7 @@ struct btrfs_device *btrfs_find_device(struct btrfs_fs_info *fs_info, u64 devid,
if (!fsid ||
(!memcmp(cur_devices->fsid, fsid, BTRFS_UUID_SIZE) ||
fs_info->ignore_fsid_mismatch)) {
- device = __find_device(&cur_devices->devices,
- devid, uuid);
+ device = find_device(cur_devices, devid, uuid);
if (device)
return device;
}