diff options
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r-- | fs/btrfs/volumes.c | 107 |
1 files changed, 87 insertions, 20 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 2049d179ccd5..a79b3cc09e94 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -423,15 +423,11 @@ int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices, | |||
423 | } | 423 | } |
424 | set_blocksize(bdev, 4096); | 424 | set_blocksize(bdev, 4096); |
425 | 425 | ||
426 | bh = __bread(bdev, BTRFS_SUPER_INFO_OFFSET / 4096, 4096); | 426 | bh = btrfs_read_dev_super(bdev); |
427 | if (!bh) | 427 | if (!bh) |
428 | goto error_close; | 428 | goto error_close; |
429 | 429 | ||
430 | disk_super = (struct btrfs_super_block *)bh->b_data; | 430 | disk_super = (struct btrfs_super_block *)bh->b_data; |
431 | if (strncmp((char *)(&disk_super->magic), BTRFS_MAGIC, | ||
432 | sizeof(disk_super->magic))) | ||
433 | goto error_brelse; | ||
434 | |||
435 | devid = le64_to_cpu(disk_super->dev_item.devid); | 431 | devid = le64_to_cpu(disk_super->dev_item.devid); |
436 | if (devid != device->devid) | 432 | if (devid != device->devid) |
437 | goto error_brelse; | 433 | goto error_brelse; |
@@ -529,17 +525,12 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, | |||
529 | ret = set_blocksize(bdev, 4096); | 525 | ret = set_blocksize(bdev, 4096); |
530 | if (ret) | 526 | if (ret) |
531 | goto error_close; | 527 | goto error_close; |
532 | bh = __bread(bdev, BTRFS_SUPER_INFO_OFFSET / 4096, 4096); | 528 | bh = btrfs_read_dev_super(bdev); |
533 | if (!bh) { | 529 | if (!bh) { |
534 | ret = -EIO; | 530 | ret = -EIO; |
535 | goto error_close; | 531 | goto error_close; |
536 | } | 532 | } |
537 | disk_super = (struct btrfs_super_block *)bh->b_data; | 533 | disk_super = (struct btrfs_super_block *)bh->b_data; |
538 | if (strncmp((char *)(&disk_super->magic), BTRFS_MAGIC, | ||
539 | sizeof(disk_super->magic))) { | ||
540 | ret = -EINVAL; | ||
541 | goto error_brelse; | ||
542 | } | ||
543 | devid = le64_to_cpu(disk_super->dev_item.devid); | 534 | devid = le64_to_cpu(disk_super->dev_item.devid); |
544 | transid = btrfs_super_generation(disk_super); | 535 | transid = btrfs_super_generation(disk_super); |
545 | if (disk_super->label[0]) | 536 | if (disk_super->label[0]) |
@@ -553,7 +544,6 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, | |||
553 | printk("devid %Lu transid %Lu %s\n", devid, transid, path); | 544 | printk("devid %Lu transid %Lu %s\n", devid, transid, path); |
554 | ret = device_list_add(path, disk_super, devid, fs_devices_ret); | 545 | ret = device_list_add(path, disk_super, devid, fs_devices_ret); |
555 | 546 | ||
556 | error_brelse: | ||
557 | brelse(bh); | 547 | brelse(bh); |
558 | error_close: | 548 | error_close: |
559 | close_bdev_exclusive(bdev, flags); | 549 | close_bdev_exclusive(bdev, flags); |
@@ -1016,17 +1006,12 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) | |||
1016 | } | 1006 | } |
1017 | 1007 | ||
1018 | set_blocksize(bdev, 4096); | 1008 | set_blocksize(bdev, 4096); |
1019 | bh = __bread(bdev, BTRFS_SUPER_INFO_OFFSET / 4096, 4096); | 1009 | bh = btrfs_read_dev_super(bdev); |
1020 | if (!bh) { | 1010 | if (!bh) { |
1021 | ret = -EIO; | 1011 | ret = -EIO; |
1022 | goto error_close; | 1012 | goto error_close; |
1023 | } | 1013 | } |
1024 | disk_super = (struct btrfs_super_block *)bh->b_data; | 1014 | disk_super = (struct btrfs_super_block *)bh->b_data; |
1025 | if (strncmp((char *)(&disk_super->magic), BTRFS_MAGIC, | ||
1026 | sizeof(disk_super->magic))) { | ||
1027 | ret = -ENOENT; | ||
1028 | goto error_brelse; | ||
1029 | } | ||
1030 | devid = le64_to_cpu(disk_super->dev_item.devid); | 1015 | devid = le64_to_cpu(disk_super->dev_item.devid); |
1031 | dev_uuid = disk_super->dev_item.uuid; | 1016 | dev_uuid = disk_super->dev_item.uuid; |
1032 | device = btrfs_find_device(root, devid, dev_uuid, | 1017 | device = btrfs_find_device(root, devid, dev_uuid, |
@@ -2563,6 +2548,88 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, | |||
2563 | mirror_num, NULL); | 2548 | mirror_num, NULL); |
2564 | } | 2549 | } |
2565 | 2550 | ||
2551 | int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree, | ||
2552 | u64 chunk_start, u64 physical, u64 devid, | ||
2553 | u64 **logical, int *naddrs, int *stripe_len) | ||
2554 | { | ||
2555 | struct extent_map_tree *em_tree = &map_tree->map_tree; | ||
2556 | struct extent_map *em; | ||
2557 | struct map_lookup *map; | ||
2558 | u64 *buf; | ||
2559 | u64 bytenr; | ||
2560 | u64 length; | ||
2561 | u64 stripe_nr; | ||
2562 | int i, j, nr = 0; | ||
2563 | |||
2564 | spin_lock(&em_tree->lock); | ||
2565 | em = lookup_extent_mapping(em_tree, chunk_start, 1); | ||
2566 | spin_unlock(&em_tree->lock); | ||
2567 | |||
2568 | BUG_ON(!em || em->start != chunk_start); | ||
2569 | map = (struct map_lookup *)em->bdev; | ||
2570 | |||
2571 | length = em->len; | ||
2572 | if (map->type & BTRFS_BLOCK_GROUP_RAID10) | ||
2573 | do_div(length, map->num_stripes / map->sub_stripes); | ||
2574 | else if (map->type & BTRFS_BLOCK_GROUP_RAID0) | ||
2575 | do_div(length, map->num_stripes); | ||
2576 | |||
2577 | buf = kzalloc(sizeof(u64) * map->num_stripes, GFP_NOFS); | ||
2578 | BUG_ON(!buf); | ||
2579 | |||
2580 | for (i = 0; i < map->num_stripes; i++) { | ||
2581 | if (devid && map->stripes[i].dev->devid != devid) | ||
2582 | continue; | ||
2583 | if (map->stripes[i].physical > physical || | ||
2584 | map->stripes[i].physical + length <= physical) | ||
2585 | continue; | ||
2586 | |||
2587 | stripe_nr = physical - map->stripes[i].physical; | ||
2588 | do_div(stripe_nr, map->stripe_len); | ||
2589 | |||
2590 | if (map->type & BTRFS_BLOCK_GROUP_RAID10) { | ||
2591 | stripe_nr = stripe_nr * map->num_stripes + i; | ||
2592 | do_div(stripe_nr, map->sub_stripes); | ||
2593 | } else if (map->type & BTRFS_BLOCK_GROUP_RAID0) { | ||
2594 | stripe_nr = stripe_nr * map->num_stripes + i; | ||
2595 | } | ||
2596 | bytenr = chunk_start + stripe_nr * map->stripe_len; | ||
2597 | for (j = 0; j < nr; j++) { | ||
2598 | if (buf[j] == bytenr) | ||
2599 | break; | ||
2600 | } | ||
2601 | if (j == nr) | ||
2602 | buf[nr++] = bytenr; | ||
2603 | } | ||
2604 | |||
2605 | for (i = 0; i > nr; i++) { | ||
2606 | struct btrfs_multi_bio *multi; | ||
2607 | struct btrfs_bio_stripe *stripe; | ||
2608 | int ret; | ||
2609 | |||
2610 | length = 1; | ||
2611 | ret = btrfs_map_block(map_tree, WRITE, buf[i], | ||
2612 | &length, &multi, 0); | ||
2613 | BUG_ON(ret); | ||
2614 | |||
2615 | stripe = multi->stripes; | ||
2616 | for (j = 0; j < multi->num_stripes; j++) { | ||
2617 | if (stripe->physical >= physical && | ||
2618 | physical < stripe->physical + length) | ||
2619 | break; | ||
2620 | } | ||
2621 | BUG_ON(j >= multi->num_stripes); | ||
2622 | kfree(multi); | ||
2623 | } | ||
2624 | |||
2625 | *logical = buf; | ||
2626 | *naddrs = nr; | ||
2627 | *stripe_len = map->stripe_len; | ||
2628 | |||
2629 | free_extent_map(em); | ||
2630 | return 0; | ||
2631 | } | ||
2632 | |||
2566 | int btrfs_unplug_page(struct btrfs_mapping_tree *map_tree, | 2633 | int btrfs_unplug_page(struct btrfs_mapping_tree *map_tree, |
2567 | u64 logical, struct page *page) | 2634 | u64 logical, struct page *page) |
2568 | { | 2635 | { |
@@ -3003,7 +3070,7 @@ int btrfs_read_super_device(struct btrfs_root *root, struct extent_buffer *buf) | |||
3003 | return read_one_dev(root, buf, dev_item); | 3070 | return read_one_dev(root, buf, dev_item); |
3004 | } | 3071 | } |
3005 | 3072 | ||
3006 | int btrfs_read_sys_array(struct btrfs_root *root) | 3073 | int btrfs_read_sys_array(struct btrfs_root *root, u64 sb_bytenr) |
3007 | { | 3074 | { |
3008 | struct btrfs_super_block *super_copy = &root->fs_info->super_copy; | 3075 | struct btrfs_super_block *super_copy = &root->fs_info->super_copy; |
3009 | struct extent_buffer *sb; | 3076 | struct extent_buffer *sb; |
@@ -3018,7 +3085,7 @@ int btrfs_read_sys_array(struct btrfs_root *root) | |||
3018 | u32 cur; | 3085 | u32 cur; |
3019 | struct btrfs_key key; | 3086 | struct btrfs_key key; |
3020 | 3087 | ||
3021 | sb = btrfs_find_create_tree_block(root, BTRFS_SUPER_INFO_OFFSET, | 3088 | sb = btrfs_find_create_tree_block(root, sb_bytenr, |
3022 | BTRFS_SUPER_INFO_SIZE); | 3089 | BTRFS_SUPER_INFO_SIZE); |
3023 | if (!sb) | 3090 | if (!sb) |
3024 | return -ENOMEM; | 3091 | return -ENOMEM; |