diff --git a/kernel-shared/compression.h b/kernel-shared/compression.h index e3f58dd6..788ab75d 100644 --- a/kernel-shared/compression.h +++ b/kernel-shared/compression.h @@ -7,8 +7,10 @@ #define BTRFS_COMPRESSION_H #include "kerncompat.h" +#include "kernel-lib/sizes.h" struct btrfs_inode; +struct btrfs_ordered_extent; struct address_space; struct inode; struct bio; @@ -27,12 +29,16 @@ struct btrfs_bio { }; /* Maximum length of compressed data stored on disk */ #define BTRFS_MAX_COMPRESSED (SZ_128K) +#define BTRFS_MAX_COMPRESSED_PAGES (BTRFS_MAX_COMPRESSED / PAGE_SIZE) +_static_assert((BTRFS_MAX_COMPRESSED % PAGE_SIZE) == 0); /* Maximum size of data before compression */ #define BTRFS_MAX_UNCOMPRESSED (SZ_128K) #define BTRFS_ZLIB_DEFAULT_LEVEL 3 +struct page; + struct compressed_bio { /* Number of compressed pages in the array */ unsigned int nr_pages; @@ -88,17 +94,18 @@ int btrfs_decompress(int type, const u8 *data_in, struct page *dest_page, int btrfs_decompress_buf2page(const char *buf, u32 buf_len, struct compressed_bio *cb, u32 decompressed); -void btrfs_submit_compressed_write(struct btrfs_inode *inode, u64 start, - unsigned int len, u64 disk_start, - unsigned int compressed_len, +void btrfs_submit_compressed_write(struct btrfs_ordered_extent *ordered, struct page **compressed_pages, unsigned int nr_pages, blk_opf_t write_flags, bool writeback); -void btrfs_submit_compressed_read(struct btrfs_bio *bbio, int mirror_num); +void btrfs_submit_compressed_read(struct btrfs_bio *bbio); unsigned int btrfs_compress_str2level(unsigned int type, const char *str); +struct page *btrfs_alloc_compr_page(void); +void btrfs_free_compr_page(struct page *page); + enum btrfs_compression_type { BTRFS_COMPRESS_NONE = 0, BTRFS_COMPRESS_ZLIB = 1, @@ -146,7 +153,7 @@ int zlib_compress_pages(struct list_head *ws, struct address_space *mapping, unsigned long *total_in, unsigned long *total_out); int zlib_decompress_bio(struct list_head *ws, struct compressed_bio *cb); int zlib_decompress(struct list_head *ws, const u8 *data_in, - struct page *dest_page, unsigned long start_byte, size_t srclen, + struct page *dest_page, unsigned long dest_pgoff, size_t srclen, size_t destlen); struct list_head *zlib_alloc_workspace(unsigned int level); void zlib_free_workspace(struct list_head *ws); @@ -157,7 +164,7 @@ int lzo_compress_pages(struct list_head *ws, struct address_space *mapping, unsigned long *total_in, unsigned long *total_out); int lzo_decompress_bio(struct list_head *ws, struct compressed_bio *cb); int lzo_decompress(struct list_head *ws, const u8 *data_in, - struct page *dest_page, unsigned long start_byte, size_t srclen, + struct page *dest_page, unsigned long dest_pgoff, size_t srclen, size_t destlen); struct list_head *lzo_alloc_workspace(unsigned int level); void lzo_free_workspace(struct list_head *ws); diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h index 94463222..444d206e 100644 --- a/kernel-shared/ctree.h +++ b/kernel-shared/ctree.h @@ -1219,7 +1219,7 @@ static inline int is_fstree(u64 rootid) return 0; } -void btrfs_uuid_to_key(const u8 *uuid, struct btrfs_key *key); +void btrfs_uuid_to_key(const u8 *uuid, u8 type, struct btrfs_key *key); /* inode.c */ int check_dir_conflict(struct btrfs_root *root, char *name, int namelen, diff --git a/kernel-shared/delayed-ref.h b/kernel-shared/delayed-ref.h index bb3a771a..95bf62ab 100644 --- a/kernel-shared/delayed-ref.h +++ b/kernel-shared/delayed-ref.h @@ -32,10 +32,16 @@ struct btrfs_trans_handle; struct btrfs_block_rsv; /* these are the possible values of struct btrfs_delayed_ref_node->action */ -#define BTRFS_ADD_DELAYED_REF 1 /* add one backref to the tree */ -#define BTRFS_DROP_DELAYED_REF 2 /* delete one backref from the tree */ -#define BTRFS_ADD_DELAYED_EXTENT 3 /* record a full extent allocation */ -#define BTRFS_UPDATE_DELAYED_HEAD 4 /* not changing ref count on head ref */ +enum btrfs_delayed_ref_action { + /* Add one backref to the tree */ + BTRFS_ADD_DELAYED_REF = 1, + /* Delete one backref from the tree */ + BTRFS_DROP_DELAYED_REF, + /* Record a full extent allocation */ + BTRFS_ADD_DELAYED_EXTENT, + /* Not changing ref count on head ref */ + BTRFS_UPDATE_DELAYED_HEAD, +} __attribute__ ((__packed__)); struct btrfs_delayed_ref_node { struct rb_node ref_node; @@ -210,7 +216,7 @@ enum btrfs_ref_type { BTRFS_REF_DATA, BTRFS_REF_METADATA, BTRFS_REF_LAST, -}; +} __attribute__((__packed__)); struct btrfs_data_ref { /* For EXTENT_DATA_REF */ @@ -250,7 +256,7 @@ struct btrfs_tree_ref { struct btrfs_ref { enum btrfs_ref_type type; - int action; + enum btrfs_delayed_ref_action action; /* * Whether this extent should go through qgroup record. diff --git a/kernel-shared/free-space-tree.c b/kernel-shared/free-space-tree.c index e31854ce..93806ca0 100644 --- a/kernel-shared/free-space-tree.c +++ b/kernel-shared/free-space-tree.c @@ -178,9 +178,10 @@ out: return ret; } -static inline u32 free_space_bitmap_size(u64 size, u32 sectorsize) +static inline u32 free_space_bitmap_size(const struct btrfs_fs_info *fs_info, + u64 size) { - return DIV_ROUND_UP((u32)div_u64(size, sectorsize), BITS_PER_BYTE); + return DIV_ROUND_UP((u32)div_u64(size, fs_info->sectorsize), BITS_PER_BYTE); } static unsigned long *alloc_bitmap(u32 bitmap_size) @@ -241,8 +242,7 @@ static int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans, int done = 0, nr; int ret; - bitmap_size = free_space_bitmap_size(block_group->length, - fs_info->sectorsize); + bitmap_size = free_space_bitmap_size(fs_info, block_group->length); bitmap = alloc_bitmap(bitmap_size); if (!bitmap) { ret = -ENOMEM; @@ -331,8 +331,7 @@ static int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans, u32 data_size; extent_size = min(end - i, bitmap_range); - data_size = free_space_bitmap_size(extent_size, - fs_info->sectorsize); + data_size = free_space_bitmap_size(fs_info, extent_size); key.objectid = i; key.type = BTRFS_FREE_SPACE_BITMAP_KEY; @@ -379,8 +378,7 @@ static int convert_free_space_to_extents(struct btrfs_trans_handle *trans, int done = 0, nr; int ret; - bitmap_size = free_space_bitmap_size(block_group->start, - fs_info->sectorsize); + bitmap_size = free_space_bitmap_size(fs_info, block_group->length); bitmap = alloc_bitmap(bitmap_size); if (!bitmap) { ret = -ENOMEM; @@ -423,8 +421,8 @@ static int convert_free_space_to_extents(struct btrfs_trans_handle *trans, fs_info->sectorsize * BITS_PER_BYTE); bitmap_cursor = ((char *)bitmap) + bitmap_pos; - data_size = free_space_bitmap_size(found_key.offset, - fs_info->sectorsize); + data_size = free_space_bitmap_size(fs_info, + found_key.offset); ptr = btrfs_item_ptr_offset(leaf, path->slots[0] - 1); read_extent_buffer(leaf, bitmap_cursor, ptr, diff --git a/kernel-shared/free-space-tree.h b/kernel-shared/free-space-tree.h index a93ebe21..ec0539c4 100644 --- a/kernel-shared/free-space-tree.h +++ b/kernel-shared/free-space-tree.h @@ -26,6 +26,11 @@ struct btrfs_block_group; struct btrfs_fs_info; struct btrfs_trans_handle; +/* + * The default size for new free space bitmap items. The last bitmap in a block + * group may be truncated, and none of the free space tree code assumes that + * existing bitmaps are this size. + */ #define BTRFS_FREE_SPACE_BITMAP_SIZE 256 #define BTRFS_FREE_SPACE_BITMAP_BITS (BTRFS_FREE_SPACE_BITMAP_SIZE * BITS_PER_BYTE) diff --git a/kernel-shared/inode-item.c b/kernel-shared/inode-item.c index 260d86b7..f3f7286b 100644 --- a/kernel-shared/inode-item.c +++ b/kernel-shared/inode-item.c @@ -29,10 +29,9 @@ struct btrfs_trans_handle; -static int find_name_in_backref(struct btrfs_path *path, const char * name, - int name_len, struct btrfs_inode_ref **ref_ret) +static int find_name_in_backref(struct extent_buffer *leaf, int slot, const char * name, + int name_len, struct btrfs_inode_ref **ref_ret) { - struct extent_buffer *leaf; struct btrfs_inode_ref *ref; unsigned long ptr; unsigned long name_ptr; @@ -40,9 +39,8 @@ static int find_name_in_backref(struct btrfs_path *path, const char * name, u32 cur_offset = 0; int len; - leaf = path->nodes[0]; - item_size = btrfs_item_size(leaf, path->slots[0]); - ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); + item_size = btrfs_item_size(leaf, slot); + ptr = btrfs_item_ptr_offset(leaf, slot); while (cur_offset < item_size) { ref = (struct btrfs_inode_ref *)(ptr + cur_offset); len = btrfs_inode_ref_name_len(leaf, ref); @@ -83,7 +81,7 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, if (ret == -EEXIST) { u32 old_size; - if (find_name_in_backref(path, name, name_len, &ref)) + if (find_name_in_backref(path->nodes[0], path->slots[0], name, name_len, &ref)) goto out; old_size = btrfs_item_size(path->nodes[0], path->slots[0]); @@ -182,7 +180,7 @@ struct btrfs_inode_ref *btrfs_lookup_inode_ref(struct btrfs_trans_handle *trans, if (ret) goto out; - find_name_in_backref(path, name, namelen, &ret_inode_ref); + find_name_in_backref(path->nodes[0], path->slots[0], name, namelen, &ret_inode_ref); out: if (ret < 0) return ERR_PTR(ret); @@ -190,23 +188,20 @@ out: return ret_inode_ref; } -static int btrfs_find_name_in_ext_backref(struct btrfs_path *path, - u64 parent_ino, const char *name, int namelen, - struct btrfs_inode_extref **extref_ret) +static int btrfs_find_name_in_ext_backref(struct extent_buffer *leaf, + int slot, u64 parent_ino, + const char *name, int namelen, + struct btrfs_inode_extref **extref_ret) { - struct extent_buffer *node; struct btrfs_inode_extref *extref; unsigned long ptr; unsigned long name_ptr; u32 item_size; u32 cur_offset = 0; int ref_name_len; - int slot; - node = path->nodes[0]; - slot = path->slots[0]; - item_size = btrfs_item_size(node, slot); - ptr = btrfs_item_ptr_offset(node, slot); + item_size = btrfs_item_size(leaf, slot); + ptr = btrfs_item_ptr_offset(leaf, slot); /* * Search all extended backrefs in this item. We're only looking @@ -217,11 +212,11 @@ static int btrfs_find_name_in_ext_backref(struct btrfs_path *path, while (cur_offset < item_size) { extref = (struct btrfs_inode_extref *) (ptr + cur_offset); name_ptr = (unsigned long)(&extref->name); - ref_name_len = btrfs_inode_extref_name_len(node, extref); + ref_name_len = btrfs_inode_extref_name_len(leaf, extref); if (ref_name_len == namelen && - btrfs_inode_extref_parent(node, extref) == parent_ino && - (memcmp_extent_buffer(node, name, name_ptr, namelen) == 0)) + btrfs_inode_extref_parent(leaf, extref) == parent_ino && + (memcmp_extent_buffer(leaf, name, name_ptr, namelen) == 0)) { if (extref_ret) *extref_ret = extref; @@ -253,7 +248,8 @@ struct btrfs_inode_extref *btrfs_lookup_inode_extref(struct btrfs_trans_handle return ERR_PTR(ret); if (ret > 0) return NULL; - if (!btrfs_find_name_in_ext_backref(path, parent_ino, name, + if (!btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0], + parent_ino, name, namelen, &extref)) return NULL; @@ -294,7 +290,7 @@ int btrfs_del_inode_extref(struct btrfs_trans_handle *trans, * Sanity check - did we find the right item for this name? This * should always succeed so error here will make the FS readonly. */ - if (!btrfs_find_name_in_ext_backref(path, ref_objectid, + if (!btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0], ref_objectid, name, name_len, &extref)) { ret = -ENOENT; goto out; @@ -356,14 +352,14 @@ int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans, ret = btrfs_insert_empty_item(trans, root, path, &key, ins_len); if (ret == -EEXIST) { - if (btrfs_find_name_in_ext_backref(path, ref_objectid, + if (btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0], + ref_objectid, name, name_len, NULL)) goto out; btrfs_extend_item(path, ins_len); ret = 0; } - if (ret < 0) goto out; @@ -382,7 +378,6 @@ int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans, out: btrfs_free_path(path); - return ret; } @@ -418,7 +413,7 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans, } else if (ret < 0) { goto out; } - if (!find_name_in_backref(path, name, name_len, &ref)) { + if (!find_name_in_backref(path->nodes[0], path->slots[0], name, name_len, &ref)) { ret = -ENOENT; search_ext_refs = 1; goto out; diff --git a/kernel-shared/messages.c b/kernel-shared/messages.c index 634f5961..1853ad71 100644 --- a/kernel-shared/messages.c +++ b/kernel-shared/messages.c @@ -269,12 +269,6 @@ void __cold btrfs_assertfail(const char *expr, const char *file, int line) } #endif -void __cold btrfs_print_v0_err(struct btrfs_fs_info *fs_info) -{ - btrfs_err(fs_info, -"Unsupported V0 extent filesystem detected. Aborting. Please re-create your filesystem with a newer kernel"); -} - #if BITS_PER_LONG == 32 && defined(__KERNEL__) void __cold btrfs_warn_32bit_limit(struct btrfs_fs_info *fs_info) { diff --git a/kernel-shared/root-tree.c b/kernel-shared/root-tree.c index 33f9e469..dd2636ec 100644 --- a/kernel-shared/root-tree.c +++ b/kernel-shared/root-tree.c @@ -21,10 +21,12 @@ #include #include "kernel-lib/bitops.h" #include "kernel-shared/accessors.h" +#include "kernel-shared/messages.h" #include "kernel-shared/extent_io.h" #include "kernel-shared/uapi/btrfs_tree.h" #include "kernel-shared/ctree.h" #include "kernel-shared/disk-io.h" +#include "kernel-shared/transaction.h" int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct btrfs_root_item *item, struct btrfs_key *key) @@ -74,6 +76,7 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_key *key, struct btrfs_root_item *item) { + struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_path *path; struct extent_buffer *l; int ret; @@ -88,7 +91,17 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root ret = btrfs_search_slot(trans, root, key, path, 0, 1); if (ret < 0) goto out; - BUG_ON(ret != 0); + + if (ret > 0) { + btrfs_crit(fs_info, + "unable to find root key (%llu %u %llu) in tree %llu", + key->objectid, key->type, key->offset, + root->root_key.objectid); + ret = -EUCLEAN; + btrfs_abort_transaction(trans, ret); + goto out; + } + l = path->nodes[0]; slot = path->slots[0]; ptr = btrfs_item_ptr_offset(l, slot); @@ -104,17 +117,20 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root ret = btrfs_search_slot(trans, root, key, path, -1, 1); if (ret < 0) { + btrfs_abort_transaction(trans, ret); goto out; } ret = btrfs_del_item(trans, root, path); if (ret < 0) { + btrfs_abort_transaction(trans, ret); goto out; } btrfs_release_path(path); ret = btrfs_insert_empty_item(trans, root, path, key, sizeof(*item)); if (ret < 0) { + btrfs_abort_transaction(trans, ret); goto out; } l = path->nodes[0]; diff --git a/kernel-shared/uuid-tree.c b/kernel-shared/uuid-tree.c index e0d3ea09..7adbc11e 100644 --- a/kernel-shared/uuid-tree.c +++ b/kernel-shared/uuid-tree.c @@ -32,12 +32,13 @@ #include "common/messages.h" #include "common/utils.h" -void btrfs_uuid_to_key(const u8 *uuid, struct btrfs_key *key) +void btrfs_uuid_to_key(const u8 *uuid, u8 type, struct btrfs_key *key) { u64 tmp; tmp = get_unaligned_le64(uuid); put_unaligned_64(tmp, &key->objectid); + key->type = type; tmp = get_unaligned_le64(uuid + sizeof(u64)); put_unaligned_64(tmp, &key->offset); } @@ -57,8 +58,7 @@ static int btrfs_uuid_tree_lookup_any(int fd, const u8 *uuid, u8 type, __le64 lesubid; struct btrfs_key key; - key.type = type; - btrfs_uuid_to_key(uuid, &key); + btrfs_uuid_to_key(uuid, type, &key); memset(&search_arg, 0, sizeof(search_arg)); search_arg.key.tree_id = BTRFS_UUID_TREE_OBJECTID; @@ -138,8 +138,7 @@ int btrfs_uuid_tree_remove(struct btrfs_trans_handle *trans, u8 *uuid, u8 type, goto out; } - btrfs_uuid_to_key(uuid, &key); - key.type = type; + btrfs_uuid_to_key(uuid, type, &key); path = btrfs_alloc_path(); if (!path) { diff --git a/mkfs/main.c b/mkfs/main.c index d15f3c9a..c9c8ee5f 100644 --- a/mkfs/main.c +++ b/mkfs/main.c @@ -807,8 +807,7 @@ static int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans, u8 *uuid, unsigned long offset; __le64 subvol_id_le; - key.type = type; - btrfs_uuid_to_key(uuid, &key); + btrfs_uuid_to_key(uuid, type, &key); path = btrfs_alloc_path(); if (!path) {