static void print_file_extent_item(struct extent_buffer *eb, struct btrfs_item *item, struct btrfs_file_extent_item *fi) { int extent_type = btrfs_file_extent_type(eb, fi); if (extent_type == BTRFS_FILE_EXTENT_INLINE) { printf("\t\tinline extent data size %u " "ram %u compress %d\n", btrfs_file_extent_inline_item_len(eb, item), btrfs_file_extent_inline_len(eb, fi), btrfs_file_extent_compression(eb, fi)); return; } if (extent_type == BTRFS_FILE_EXTENT_PREALLOC) { printf("\t\tprealloc data disk byte %llu nr %llu\n", (unsigned long long)btrfs_file_extent_disk_bytenr(eb, fi), (unsigned long long)btrfs_file_extent_disk_num_bytes(eb, fi)); printf("\t\tprealloc data offset %llu nr %llu\n", (unsigned long long)btrfs_file_extent_offset(eb, fi), (unsigned long long)btrfs_file_extent_num_bytes(eb, fi)); return; } printf("\t\textent data disk byte %llu nr %llu\n", (unsigned long long)btrfs_file_extent_disk_bytenr(eb, fi), (unsigned long long)btrfs_file_extent_disk_num_bytes(eb, fi)); printf("\t\textent data offset %llu nr %llu ram %llu\n", (unsigned long long)btrfs_file_extent_offset(eb, fi), (unsigned long long)btrfs_file_extent_num_bytes(eb, fi), (unsigned long long)btrfs_file_extent_ram_bytes(eb, fi)); printf("\t\textent compression %d\n", btrfs_file_extent_compression(eb, fi)); }
static int check_extent_in_eb(struct btrfs_key *key, struct extent_buffer *eb, struct btrfs_file_extent_item *fi, u64 extent_item_pos, struct extent_inode_elem **eie) { u64 offset = 0; struct extent_inode_elem *e; if (!btrfs_file_extent_compression(eb, fi) && !btrfs_file_extent_encryption(eb, fi) && !btrfs_file_extent_other_encoding(eb, fi)) { u64 data_offset; u64 data_len; data_offset = btrfs_file_extent_offset(eb, fi); data_len = btrfs_file_extent_num_bytes(eb, fi); if (extent_item_pos < data_offset || extent_item_pos >= data_offset + data_len) return 1; offset = extent_item_pos - data_offset; } e = kmalloc(sizeof(*e), GFP_NOFS); if (!e) return -ENOMEM; e->next = *eie; e->inum = key->objectid; e->offset = key->offset + offset; *eie = e; return 0; }
static int copy_one_inline(struct btrfs_root *root, int fd, struct btrfs_path *path, u64 pos) { struct extent_buffer *leaf = path->nodes[0]; struct btrfs_file_extent_item *fi; char buf[4096]; char *outbuf; u64 ram_size; ssize_t done; unsigned long ptr; int ret; int len; int inline_item_len; int compress; fi = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_file_extent_item); ptr = btrfs_file_extent_inline_start(fi); len = btrfs_file_extent_ram_bytes(leaf, fi); inline_item_len = btrfs_file_extent_inline_item_len(leaf, btrfs_item_nr(path->slots[0])); read_extent_buffer(leaf, buf, ptr, inline_item_len); compress = btrfs_file_extent_compression(leaf, fi); if (compress == BTRFS_COMPRESS_NONE) { done = pwrite(fd, buf, len, pos); if (done < len) { fprintf(stderr, "Short inline write, wanted %d, did " "%zd: %d\n", len, done, errno); return -1; } return 0; } ram_size = btrfs_file_extent_ram_bytes(leaf, fi); outbuf = calloc(1, ram_size); if (!outbuf) { error("not enough memory"); return -ENOMEM; } ret = decompress(root, buf, outbuf, inline_item_len, &ram_size, compress); if (ret) { free(outbuf); return ret; } done = pwrite(fd, outbuf, ram_size, pos); free(outbuf); if (done < ram_size) { fprintf(stderr, "Short compressed inline write, wanted %Lu, " "did %zd: %d\n", ram_size, done, errno); return -1; } return 0; }
static void print_file_extent_item(struct extent_buffer *eb, struct btrfs_item *item, int slot, struct btrfs_file_extent_item *fi) { int extent_type = btrfs_file_extent_type(eb, fi); char compress_str[16]; compress_type_to_str(btrfs_file_extent_compression(eb, fi), compress_str); printf("\t\tgeneration %llu type %hhu (%s)\n", btrfs_file_extent_generation(eb, fi), extent_type, file_extent_type_to_str(extent_type)); if (extent_type == BTRFS_FILE_EXTENT_INLINE) { printf("\t\tinline extent data size %u ram_bytes %u compression %hhu (%s)\n", btrfs_file_extent_inline_item_len(eb, item), btrfs_file_extent_inline_len(eb, slot, fi), btrfs_file_extent_compression(eb, fi), compress_str); return; } if (extent_type == BTRFS_FILE_EXTENT_PREALLOC) { printf("\t\tprealloc data disk byte %llu nr %llu\n", (unsigned long long)btrfs_file_extent_disk_bytenr(eb, fi), (unsigned long long)btrfs_file_extent_disk_num_bytes(eb, fi)); printf("\t\tprealloc data offset %llu nr %llu\n", (unsigned long long)btrfs_file_extent_offset(eb, fi), (unsigned long long)btrfs_file_extent_num_bytes(eb, fi)); return; } printf("\t\textent data disk byte %llu nr %llu\n", (unsigned long long)btrfs_file_extent_disk_bytenr(eb, fi), (unsigned long long)btrfs_file_extent_disk_num_bytes(eb, fi)); printf("\t\textent data offset %llu nr %llu ram %llu\n", (unsigned long long)btrfs_file_extent_offset(eb, fi), (unsigned long long)btrfs_file_extent_num_bytes(eb, fi), (unsigned long long)btrfs_file_extent_ram_bytes(eb, fi)); printf("\t\textent compression %hhu (%s)\n", btrfs_file_extent_compression(eb, fi), compress_str); }
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; }
/* * this is very complex, but the basic idea is to drop all extents * in the range start - end. hint_block is filled in with a block number * that would be a good hint to the block allocator for this file. * * If an extent intersects the range but is not entirely inside the range * it is either truncated or split. Anything entirely inside the range * is deleted from the tree. * * inline_limit is used to tell this code which offsets in the file to keep * if they contain inline extents. */ noinline int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct inode *inode, u64 start, u64 end, u64 inline_limit, u64 *hint_byte) { u64 extent_end = 0; u64 locked_end = end; u64 search_start = start; u64 leaf_start; u64 ram_bytes = 0; u64 orig_parent = 0; u64 disk_bytenr = 0; u8 compression; u8 encryption; u16 other_encoding = 0; u64 root_gen; u64 root_owner; struct extent_buffer *leaf; struct btrfs_file_extent_item *extent; struct btrfs_path *path; struct btrfs_key key; struct btrfs_file_extent_item old; int keep; int slot; int bookend; int found_type = 0; int found_extent; int found_inline; int recow; int ret; inline_limit = 0; btrfs_drop_extent_cache(inode, start, end - 1, 0); path = btrfs_alloc_path(); if (!path) return -ENOMEM; while (1) { recow = 0; btrfs_release_path(root, path); ret = btrfs_lookup_file_extent(trans, root, path, inode->i_ino, search_start, -1); if (ret < 0) goto out; if (ret > 0) { if (path->slots[0] == 0) { ret = 0; goto out; } path->slots[0]--; } next_slot: keep = 0; bookend = 0; found_extent = 0; found_inline = 0; leaf_start = 0; root_gen = 0; root_owner = 0; compression = 0; encryption = 0; extent = NULL; leaf = path->nodes[0]; slot = path->slots[0]; ret = 0; btrfs_item_key_to_cpu(leaf, &key, slot); if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY && key.offset >= end) { goto out; } if (btrfs_key_type(&key) > BTRFS_EXTENT_DATA_KEY || key.objectid != inode->i_ino) { goto out; } if (recow) { search_start = max(key.offset, start); continue; } if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY) { extent = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); found_type = btrfs_file_extent_type(leaf, extent); compression = btrfs_file_extent_compression(leaf, extent); encryption = btrfs_file_extent_encryption(leaf, extent); other_encoding = btrfs_file_extent_other_encoding(leaf, extent); if (found_type == BTRFS_FILE_EXTENT_REG || found_type == BTRFS_FILE_EXTENT_PREALLOC) { extent_end = btrfs_file_extent_disk_bytenr(leaf, extent); if (extent_end) *hint_byte = extent_end; extent_end = key.offset + btrfs_file_extent_num_bytes(leaf, extent); ram_bytes = btrfs_file_extent_ram_bytes(leaf, extent); found_extent = 1; } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { found_inline = 1; extent_end = key.offset + btrfs_file_extent_inline_len(leaf, extent); } } else {