int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, u64 parent_transid) { int ret; struct extent_buffer *eb; u64 length; struct btrfs_multi_bio *multi = NULL; struct btrfs_device *device; eb = btrfs_find_tree_block(root, bytenr, blocksize); if (eb && btrfs_buffer_uptodate(eb, parent_transid)) { free_extent_buffer(eb); return 0; } length = blocksize; ret = btrfs_map_block(&root->fs_info->mapping_tree, READ, bytenr, &length, &multi, 0, NULL); BUG_ON(ret); device = multi->stripes[0].dev; device->total_ios++; blocksize = min(blocksize, (u32)(64 * 1024)); readahead(device->fd, multi->stripes[0].physical, blocksize); kfree(multi); return 0; }
int write_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *eb) { int ret; int dev_nr; u64 length; struct btrfs_multi_bio *multi = NULL; if (check_tree_block(root, eb)) BUG(); if (!btrfs_buffer_uptodate(eb, trans->transid)) BUG(); btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN); csum_tree_block(root, eb, 0); dev_nr = 0; length = eb->len; ret = btrfs_map_block(&root->fs_info->mapping_tree, WRITE, eb->start, &length, &multi, 0); while(dev_nr < multi->num_stripes) { BUG_ON(ret); eb->fd = multi->stripes[dev_nr].dev->fd; eb->dev_bytenr = multi->stripes[dev_nr].physical; multi->stripes[dev_nr].dev->total_ios++; dev_nr++; ret = write_extent_to_disk(eb); BUG_ON(ret); } kfree(multi); return 0; }
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; }
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; }
static int read_whole_eb(struct btrfs_fs_info *info, struct extent_buffer *eb, int mirror) { unsigned long offset = 0; struct btrfs_multi_bio *multi = NULL; struct btrfs_device *device; int ret = 0; u64 read_len; unsigned long bytes_left = eb->len; while (bytes_left) { read_len = bytes_left; ret = btrfs_map_block(&info->mapping_tree, READ, eb->start + offset, &read_len, &multi, mirror, NULL); if (ret) { printk("Couldn't map the block %Lu\n", eb->start + offset); kfree(multi); return -EIO; } device = multi->stripes[0].dev; if (device->fd == 0) { kfree(multi); return -EIO; } eb->fd = device->fd; device->total_ios++; eb->dev_bytenr = multi->stripes[0].physical; kfree(multi); multi = NULL; if (read_len > bytes_left) read_len = bytes_left; ret = read_extent_from_disk(eb, offset, read_len); if (ret) return -EIO; offset += read_len; bytes_left -= read_len; } return 0; }
static int __print_mapping_info(struct btrfs_fs_info *fs_info, u64 logical, u64 len, int mirror_num) { struct btrfs_multi_bio *multi = NULL; u64 cur_offset = 0; u64 cur_len; int ret = 0; while (cur_offset < len) { struct btrfs_device *device; int i; cur_len = len - cur_offset; ret = btrfs_map_block(&fs_info->mapping_tree, READ, logical + cur_offset, &cur_len, &multi, mirror_num, NULL); if (ret) { fprintf(info_file, "Error: fails to map mirror%d logical %llu: %s\n", mirror_num, logical, strerror(-ret)); return ret; } for (i = 0; i < multi->num_stripes; i++) { device = multi->stripes[i].dev; fprintf(info_file, "mirror %d logical %Lu physical %Lu device %s\n", mirror_num, logical + cur_offset, multi->stripes[0].physical, device->name); } kfree(multi); multi = NULL; cur_offset += cur_len; } return ret; }
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; }
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 length; u64 size_left; u64 dev_bytenr; u64 count = 0; int compress; int ret; int dev_fd; 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); size_left = disk_size; /* we found a hole */ if (disk_size == 0) return 0; inbuf = malloc(disk_size); if (!inbuf) { fprintf(stderr, "No memory\n"); return -1; } if (compress != BTRFS_COMPRESS_NONE) { outbuf = malloc(ram_size); if (!outbuf) { fprintf(stderr, "No memory\n"); free(inbuf); return -1; } } again: length = size_left; ret = btrfs_map_block(&root->fs_info->mapping_tree, READ, bytenr, &length, &multi, 0); if (ret) { free(inbuf); free(outbuf); fprintf(stderr, "Error mapping block %d\n", ret); return ret; } 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; size_left -= length; done = pread(dev_fd, inbuf+count, length, dev_bytenr); if (done < length) { free(inbuf); free(outbuf); fprintf(stderr, "Short read %d\n", errno); return -1; } count += length; bytenr += length; if (size_left) goto again; if (compress == BTRFS_COMPRESS_NONE) { while (total < ram_size) { done = pwrite(fd, inbuf+total, ram_size-total, pos+total); if (done < 0) { free(inbuf); fprintf(stderr, "Error writing: %d %s\n", errno, strerror(errno)); return -1; } total += done; } free(inbuf); return 0; } ret = decompress(inbuf, outbuf, disk_size, ram_size); free(inbuf); if (ret) { free(outbuf); return ret; } while (total < ram_size) { done = pwrite(fd, outbuf+total, ram_size-total, pos+total); if (done < 0) { free(outbuf); fprintf(stderr, "Error writing: %d %s\n", errno, strerror(errno)); return -1; } total += done; } free(outbuf); return 0; }