struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, u64 parent_transid) { int ret; struct extent_buffer *eb; u64 best_transid = 0; int mirror_num = 0; int good_mirror = 0; int num_copies; int ignore = 0; eb = btrfs_find_create_tree_block(root, bytenr, blocksize); if (!eb) return NULL; if (btrfs_buffer_uptodate(eb, parent_transid)) return eb; while (1) { ret = read_whole_eb(root->fs_info, eb, mirror_num); if (ret == 0 && check_tree_block(root, eb) == 0 && csum_tree_block(root, eb, 1) == 0 && verify_parent_transid(eb->tree, eb, parent_transid, ignore) == 0) { btrfs_set_buffer_uptodate(eb); return eb; } if (ignore) { if (check_tree_block(root, eb)) printk("read block failed check_tree_block\n"); else printk("Csum didn't match\n"); break; } num_copies = btrfs_num_copies(&root->fs_info->mapping_tree, eb->start, eb->len); if (num_copies == 1) { ignore = 1; continue; } if (btrfs_header_generation(eb) > best_transid) { best_transid = btrfs_header_generation(eb); good_mirror = mirror_num; } mirror_num++; if (mirror_num > num_copies) { mirror_num = good_mirror; ignore = 1; continue; } } free_extent_buffer(eb); return NULL; }
struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, u64 parent_transid) { int ret; int dev_nr; struct extent_buffer *eb; u64 length; struct btrfs_multi_bio *multi = NULL; struct btrfs_device *device; int mirror_num = 0; int num_copies; eb = btrfs_find_create_tree_block(root, bytenr, blocksize); if (!eb) return NULL; if (btrfs_buffer_uptodate(eb, parent_transid)) return eb; dev_nr = 0; length = blocksize; while (1) { ret = btrfs_map_block(&root->fs_info->mapping_tree, READ, eb->start, &length, &multi, mirror_num); BUG_ON(ret); device = multi->stripes[0].dev; eb->fd = device->fd; device->total_ios++; eb->dev_bytenr = multi->stripes[0].physical; kfree(multi); ret = read_extent_from_disk(eb); if (ret == 0 && check_tree_block(root, eb) == 0 && csum_tree_block(root, eb, 1) == 0 && verify_parent_transid(eb->tree, eb, parent_transid) == 0) { btrfs_set_buffer_uptodate(eb); return eb; } num_copies = btrfs_num_copies(&root->fs_info->mapping_tree, eb->start, eb->len); if (num_copies == 1) { break; } mirror_num++; if (mirror_num > num_copies) { break; } } free_extent_buffer(eb); return NULL; }
/* * Logical and len is the exact value of a extent. * And offset is the offset inside the extent. It's only used for case * where user only want to print part of the extent. * * Caller *MUST* ensure the range [logical,logical+len) are in one extent. * Or we can encounter the following case, causing a -ENOENT error: * |<-----given parameter------>| * |<------ Extent A ----->| */ static int print_mapping_info(struct btrfs_fs_info *fs_info, u64 logical, u64 len) { int num_copies; int mirror_num; int ret = 0; num_copies = btrfs_num_copies(&fs_info->mapping_tree, logical, len); for (mirror_num = 1; mirror_num <= num_copies; mirror_num++) { ret = __print_mapping_info(fs_info, logical, len, mirror_num); if (ret < 0) return ret; } return ret; }
struct extent_buffer *debug_read_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, int copy) { int ret; struct extent_buffer *eb; u64 length; struct btrfs_multi_bio *multi = NULL; struct btrfs_device *device; int num_copies; int mirror_num = 1; eb = btrfs_find_create_tree_block(root, bytenr, blocksize); if (!eb) return NULL; length = blocksize; while (1) { ret = btrfs_map_block(&root->fs_info->mapping_tree, READ, eb->start, &length, &multi, mirror_num); BUG_ON(ret); device = multi->stripes[0].dev; eb->fd = device->fd; device->total_ios++; eb->dev_bytenr = multi->stripes[0].physical; fprintf(info_file, "mirror %d logical %Lu physical %Lu " "device %s\n", mirror_num, (unsigned long long)bytenr, (unsigned long long)eb->dev_bytenr, device->name); kfree(multi); if (!copy || mirror_num == copy) ret = read_extent_from_disk(eb); num_copies = btrfs_num_copies(&root->fs_info->mapping_tree, eb->start, eb->len); if (num_copies == 1) break; mirror_num++; if (mirror_num > num_copies) break; } return eb; }
struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, u64 parent_transid) { int ret; struct extent_buffer *eb; u64 length; u64 best_transid = 0; struct btrfs_multi_bio *multi = NULL; struct btrfs_device *device; int mirror_num = 0; int good_mirror = 0; int num_copies; int ignore = 0; eb = btrfs_find_create_tree_block(root, bytenr, blocksize); if (!eb) return NULL; if (btrfs_buffer_uptodate(eb, parent_transid)) return eb; length = blocksize; while (1) { ret = btrfs_map_block(&root->fs_info->mapping_tree, READ, eb->start, &length, &multi, mirror_num); if (ret) { printk("Couldn't map the block %Lu\n", bytenr); break; } device = multi->stripes[0].dev; eb->fd = device->fd; device->total_ios++; eb->dev_bytenr = multi->stripes[0].physical; kfree(multi); ret = read_extent_from_disk(eb); if (ret == 0 && check_tree_block(root, eb) == 0 && csum_tree_block(root, eb, 1) == 0 && verify_parent_transid(eb->tree, eb, parent_transid, ignore) == 0) { btrfs_set_buffer_uptodate(eb); return eb; } if (ignore) { if (check_tree_block(root, eb)) printk("read block failed check_tree_block\n"); else printk("Csum didn't match\n"); break; } num_copies = btrfs_num_copies(&root->fs_info->mapping_tree, eb->start, eb->len); if (num_copies == 1) { ignore = 1; continue; } if (btrfs_header_generation(eb) > best_transid) { best_transid = btrfs_header_generation(eb); good_mirror = mirror_num; } mirror_num++; if (mirror_num > num_copies) { mirror_num = good_mirror; ignore = 1; continue; } } free_extent_buffer(eb); return NULL; }
static int copy_one_extent(struct btrfs_root *root, int fd, struct extent_buffer *leaf, struct btrfs_file_extent_item *fi, u64 pos) { struct btrfs_multi_bio *multi = NULL; struct btrfs_device *device; char *inbuf, *outbuf = NULL; ssize_t done, total = 0; u64 bytenr; u64 ram_size; u64 disk_size; u64 num_bytes; u64 length; u64 size_left; u64 dev_bytenr; u64 offset; u64 count = 0; int compress; int ret; int dev_fd; int mirror_num = 1; int num_copies; compress = btrfs_file_extent_compression(leaf, fi); bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); disk_size = btrfs_file_extent_disk_num_bytes(leaf, fi); ram_size = btrfs_file_extent_ram_bytes(leaf, fi); offset = btrfs_file_extent_offset(leaf, fi); num_bytes = btrfs_file_extent_num_bytes(leaf, fi); size_left = disk_size; if (compress == BTRFS_COMPRESS_NONE) bytenr += offset; if (verbose && offset) printf("offset is %Lu\n", offset); /* we found a hole */ if (disk_size == 0) return 0; inbuf = malloc(size_left); if (!inbuf) { fprintf(stderr, "No memory\n"); return -ENOMEM; } if (compress != BTRFS_COMPRESS_NONE) { outbuf = calloc(1, ram_size); if (!outbuf) { fprintf(stderr, "No memory\n"); free(inbuf); return -ENOMEM; } } again: length = size_left; ret = btrfs_map_block(&root->fs_info->mapping_tree, READ, bytenr, &length, &multi, mirror_num, NULL); if (ret) { fprintf(stderr, "Error mapping block %d\n", ret); goto out; } device = multi->stripes[0].dev; dev_fd = device->fd; device->total_ios++; dev_bytenr = multi->stripes[0].physical; kfree(multi); if (size_left < length) length = size_left; done = pread(dev_fd, inbuf+count, length, dev_bytenr); /* Need both checks, or we miss negative values due to u64 conversion */ if (done < 0 || done < length) { num_copies = btrfs_num_copies(&root->fs_info->mapping_tree, bytenr, length); mirror_num++; /* mirror_num is 1-indexed, so num_copies is a valid mirror. */ if (mirror_num > num_copies) { ret = -1; fprintf(stderr, "Exhausted mirrors trying to read\n"); goto out; } fprintf(stderr, "Trying another mirror\n"); goto again; } mirror_num = 1; size_left -= length; count += length; bytenr += length; if (size_left) goto again; if (compress == BTRFS_COMPRESS_NONE) { while (total < num_bytes) { done = pwrite(fd, inbuf+total, num_bytes-total, pos+total); if (done < 0) { ret = -1; fprintf(stderr, "Error writing: %d %s\n", errno, strerror(errno)); goto out; } total += done; } ret = 0; goto out; } ret = decompress(inbuf, outbuf, disk_size, &ram_size, compress); if (ret) { num_copies = btrfs_num_copies(&root->fs_info->mapping_tree, bytenr, length); mirror_num++; if (mirror_num >= num_copies) { ret = -1; goto out; } fprintf(stderr, "Trying another mirror\n"); goto again; } while (total < num_bytes) { done = pwrite(fd, outbuf + offset + total, num_bytes - total, pos + total); if (done < 0) { ret = -1; goto out; } total += done; } out: free(inbuf); free(outbuf); return ret; }