struct btrfs_device *device;
again:
+ if (!fs_devices)
+ return 0;
while (!list_empty(&fs_devices->devices)) {
device = list_entry(fs_devices->devices.next,
struct btrfs_device, dev_list);
int btrfs_scan_one_device(int fd, const char *path,
struct btrfs_fs_devices **fs_devices_ret,
- u64 *total_devs, u64 super_offset, int super_recover)
+ u64 *total_devs, u64 super_offset, unsigned sbflags)
{
struct btrfs_super_block *disk_super;
char buf[BTRFS_SUPER_INFO_SIZE];
u64 devid;
disk_super = (struct btrfs_super_block *)buf;
- ret = btrfs_read_dev_super(fd, disk_super, super_offset, super_recover);
+ ret = btrfs_read_dev_super(fd, disk_super, super_offset, sbflags);
if (ret < 0)
return -EIO;
devid = btrfs_stack_device_id(&disk_super->dev_item);
goto check_pending;
}
}
- if (btrfs_key_type(&key) != BTRFS_DEV_EXTENT_KEY) {
+ if (key.type != BTRFS_DEV_EXTENT_KEY) {
goto next;
}
struct btrfs_key found_key;
path = btrfs_alloc_path();
- BUG_ON(!path);
+ if (!path)
+ return -ENOMEM;
key.objectid = objectid;
key.offset = (u64)-1;
goto next;
if (key.objectid > device->devid)
break;
- if (btrfs_key_type(&key) != BTRFS_DEV_EXTENT_KEY)
+ if (key.type != BTRFS_DEV_EXTENT_KEY)
goto next;
if (key.offset > search_end)
break;
key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
key.type = BTRFS_CHUNK_ITEM_KEY;
if (convert) {
- BUG_ON(*start != round_down(*start, extent_root->sectorsize));
+ if (*start != round_down(*start, extent_root->sectorsize)) {
+ error("DATA chunk start not sectorsize aligned: %llu",
+ (unsigned long long)*start);
+ return -EINVAL;
+ }
key.offset = *start;
dev_offset = *start;
} else {
+ u64 tmp;
+
ret = find_next_chunk(chunk_root,
BTRFS_FIRST_CHUNK_TREE_OBJECTID,
- &key.offset);
+ &tmp);
+ key.offset = tmp;
if (ret)
return ret;
}
* slot == -1: SYSTEM chunk
* return -EIO on error, otherwise return 0
*/
-static int btrfs_check_chunk_valid(struct btrfs_root *root,
- struct extent_buffer *leaf,
- struct btrfs_chunk *chunk,
- int slot, u64 logical)
+int btrfs_check_chunk_valid(struct btrfs_root *root,
+ struct extent_buffer *leaf,
+ struct btrfs_chunk *chunk,
+ int slot, u64 logical)
{
u64 length;
u64 stripe_len;
return 0;
}
-static void split_eb_for_raid56(struct btrfs_fs_info *info,
- struct extent_buffer *orig_eb,
+static int split_eb_for_raid56(struct btrfs_fs_info *info,
+ struct extent_buffer *orig_eb,
struct extent_buffer **ebs,
u64 stripe_len, u64 *raid_map,
int num_stripes)
{
- struct extent_buffer *eb;
+ struct extent_buffer **tmp_ebs;
u64 start = orig_eb->start;
u64 this_eb_start;
int i;
- int ret;
+ int ret = 0;
+ tmp_ebs = calloc(num_stripes, sizeof(*tmp_ebs));
+ if (!tmp_ebs)
+ return -ENOMEM;
+
+ /* Alloc memory in a row for data stripes */
for (i = 0; i < num_stripes; i++) {
if (raid_map[i] >= BTRFS_RAID5_P_STRIPE)
break;
- eb = calloc(1, sizeof(struct extent_buffer) + stripe_len);
- if (!eb)
- BUG();
+ tmp_ebs[i] = calloc(1, sizeof(**tmp_ebs) + stripe_len);
+ if (!tmp_ebs[i]) {
+ ret = -ENOMEM;
+ goto clean_up;
+ }
+ }
+
+ for (i = 0; i < num_stripes; i++) {
+ struct extent_buffer *eb = tmp_ebs[i];
+
+ if (raid_map[i] >= BTRFS_RAID5_P_STRIPE)
+ break;
eb->start = raid_map[i];
eb->len = stripe_len;
if (start > this_eb_start ||
start + orig_eb->len < this_eb_start + stripe_len) {
ret = rmw_eb(info, eb, orig_eb);
- BUG_ON(ret);
+ if (ret)
+ goto clean_up;
} else {
- memcpy(eb->data, orig_eb->data + eb->start - start, stripe_len);
+ memcpy(eb->data, orig_eb->data + eb->start - start,
+ stripe_len);
}
ebs[i] = eb;
}
+ free(tmp_ebs);
+ return ret;
+clean_up:
+ for (i = 0; i < num_stripes; i++)
+ free(tmp_ebs[i]);
+ free(tmp_ebs);
+ return ret;
}
int write_raid56_with_parity(struct btrfs_fs_info *info,
int j;
int ret;
int alloc_size = eb->len;
+ void **pointers;
- ebs = kmalloc(sizeof(*ebs) * multi->num_stripes, GFP_NOFS);
- BUG_ON(!ebs);
+ ebs = malloc(sizeof(*ebs) * multi->num_stripes);
+ pointers = malloc(sizeof(*pointers) * multi->num_stripes);
+ if (!ebs || !pointers) {
+ free(ebs);
+ free(pointers);
+ return -ENOMEM;
+ }
if (stripe_len > alloc_size)
alloc_size = stripe_len;
- split_eb_for_raid56(info, eb, ebs, stripe_len, raid_map,
- multi->num_stripes);
+ ret = split_eb_for_raid56(info, eb, ebs, stripe_len, raid_map,
+ multi->num_stripes);
+ if (ret)
+ goto out;
for (i = 0; i < multi->num_stripes; i++) {
struct extent_buffer *new_eb;
ebs[i]->dev_bytenr = multi->stripes[i].physical;
ebs[i]->fd = multi->stripes[i].dev->fd;
multi->stripes[i].dev->total_ios++;
- BUG_ON(ebs[i]->start != raid_map[i]);
+ if (ebs[i]->start != raid_map[i]) {
+ ret = -EINVAL;
+ goto out_free_split;
+ }
continue;
}
- new_eb = kmalloc(sizeof(*eb) + alloc_size, GFP_NOFS);
- BUG_ON(!new_eb);
+ new_eb = malloc(sizeof(*eb) + alloc_size);
+ if (!new_eb) {
+ ret = -ENOMEM;
+ goto out_free_split;
+ }
new_eb->dev_bytenr = multi->stripes[i].physical;
new_eb->fd = multi->stripes[i].dev->fd;
multi->stripes[i].dev->total_ios++;
q_eb = new_eb;
}
if (q_eb) {
- void **pointers;
-
- pointers = kmalloc(sizeof(*pointers) * multi->num_stripes,
- GFP_NOFS);
- BUG_ON(!pointers);
-
ebs[multi->num_stripes - 2] = p_eb;
ebs[multi->num_stripes - 1] = q_eb;
pointers[i] = ebs[i]->data;
raid6_gen_syndrome(multi->num_stripes, stripe_len, pointers);
- kfree(pointers);
} else {
ebs[multi->num_stripes - 1] = p_eb;
memcpy(p_eb->data, ebs[0]->data, stripe_len);
for (i = 0; i < multi->num_stripes; i++) {
ret = write_extent_to_disk(ebs[i]);
- BUG_ON(ret);
- if (ebs[i] != eb)
- kfree(ebs[i]);
+ if (ret < 0)
+ goto out_free_split;
}
- kfree(ebs);
+out_free_split:
+ for (i = 0; i < multi->num_stripes; i++) {
+ if (ebs[i] != eb)
+ free(ebs[i]);
+ }
+out:
+ free(ebs);
+ free(pointers);
- return 0;
+ return ret;
}