Commit 514ac8ad authored by Chris Mason's avatar Chris Mason

Btrfs: don't use ram_bytes for uncompressed inline items

If we truncate an uncompressed inline item, ram_bytes isn't updated to reflect
the new size.  The fixe uses the size directly from the item header when
reading uncompressed inlines, and also fixes truncate to update the
size as it goes.
Reported-by: default avatarJens Axboe <axboe@fb.com>
Signed-off-by: default avatarChris Mason <clm@fb.com>
CC: stable@vger.kernel.org
parent 23c6bf6a
...@@ -2990,15 +2990,6 @@ BTRFS_SETGET_FUNCS(file_extent_encryption, struct btrfs_file_extent_item, ...@@ -2990,15 +2990,6 @@ BTRFS_SETGET_FUNCS(file_extent_encryption, struct btrfs_file_extent_item,
BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item, BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item,
other_encoding, 16); other_encoding, 16);
/* this returns the number of file bytes represented by the inline item.
* If an item is compressed, this is the uncompressed size
*/
static inline u32 btrfs_file_extent_inline_len(struct extent_buffer *eb,
struct btrfs_file_extent_item *e)
{
return btrfs_file_extent_ram_bytes(eb, e);
}
/* /*
* this returns the number of bytes used by the item on disk, minus the * this returns the number of bytes used by the item on disk, minus the
* size of any extent headers. If a file is compressed on disk, this is * size of any extent headers. If a file is compressed on disk, this is
...@@ -3012,6 +3003,32 @@ static inline u32 btrfs_file_extent_inline_item_len(struct extent_buffer *eb, ...@@ -3012,6 +3003,32 @@ static inline u32 btrfs_file_extent_inline_item_len(struct extent_buffer *eb,
return btrfs_item_size(eb, e) - offset; return btrfs_item_size(eb, e) - offset;
} }
/* this returns the number of file bytes represented by the inline item.
* If an item is compressed, this is the uncompressed size
*/
static inline u32 btrfs_file_extent_inline_len(struct extent_buffer *eb,
int slot,
struct btrfs_file_extent_item *fi)
{
struct btrfs_map_token token;
btrfs_init_map_token(&token);
/*
* return the space used on disk if this item isn't
* compressed or encoded
*/
if (btrfs_token_file_extent_compression(eb, fi, &token) == 0 &&
btrfs_token_file_extent_encryption(eb, fi, &token) == 0 &&
btrfs_token_file_extent_other_encoding(eb, fi, &token) == 0) {
return btrfs_file_extent_inline_item_len(eb,
btrfs_item_nr(slot));
}
/* otherwise use the ram bytes field */
return btrfs_token_file_extent_ram_bytes(eb, fi, &token);
}
/* btrfs_dev_stats_item */ /* btrfs_dev_stats_item */
static inline u64 btrfs_dev_stats_value(struct extent_buffer *eb, static inline u64 btrfs_dev_stats_value(struct extent_buffer *eb,
struct btrfs_dev_stats_item *ptr, struct btrfs_dev_stats_item *ptr,
......
...@@ -772,7 +772,8 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, ...@@ -772,7 +772,8 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans,
btrfs_file_extent_num_bytes(leaf, fi); btrfs_file_extent_num_bytes(leaf, fi);
} else if (extent_type == BTRFS_FILE_EXTENT_INLINE) { } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
extent_end = key.offset + extent_end = key.offset +
btrfs_file_extent_inline_len(leaf, fi); btrfs_file_extent_inline_len(leaf,
path->slots[0], fi);
} else { } else {
WARN_ON(1); WARN_ON(1);
extent_end = search_start; extent_end = search_start;
......
...@@ -1281,7 +1281,8 @@ static noinline int run_delalloc_nocow(struct inode *inode, ...@@ -1281,7 +1281,8 @@ static noinline int run_delalloc_nocow(struct inode *inode,
nocow = 1; nocow = 1;
} else if (extent_type == BTRFS_FILE_EXTENT_INLINE) { } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
extent_end = found_key.offset + extent_end = found_key.offset +
btrfs_file_extent_inline_len(leaf, fi); btrfs_file_extent_inline_len(leaf,
path->slots[0], fi);
extent_end = ALIGN(extent_end, root->sectorsize); extent_end = ALIGN(extent_end, root->sectorsize);
} else { } else {
BUG_ON(1); BUG_ON(1);
...@@ -4023,7 +4024,7 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, ...@@ -4023,7 +4024,7 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
btrfs_file_extent_num_bytes(leaf, fi); btrfs_file_extent_num_bytes(leaf, fi);
} else if (extent_type == BTRFS_FILE_EXTENT_INLINE) { } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
item_end += btrfs_file_extent_inline_len(leaf, item_end += btrfs_file_extent_inline_len(leaf,
fi); path->slots[0], fi);
} }
item_end--; item_end--;
} }
...@@ -4093,6 +4094,12 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, ...@@ -4093,6 +4094,12 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
inode_sub_bytes(inode, item_end + 1 - inode_sub_bytes(inode, item_end + 1 -
new_size); new_size);
} }
/*
* update the ram bytes to properly reflect
* the new size of our item
*/
btrfs_set_file_extent_ram_bytes(leaf, fi, size);
size = size =
btrfs_file_extent_calc_inline_size(size); btrfs_file_extent_calc_inline_size(size);
btrfs_truncate_item(root, path, size, 1); btrfs_truncate_item(root, path, size, 1);
...@@ -6162,7 +6169,7 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page, ...@@ -6162,7 +6169,7 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
btrfs_file_extent_num_bytes(leaf, item); btrfs_file_extent_num_bytes(leaf, item);
} else if (found_type == BTRFS_FILE_EXTENT_INLINE) { } else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
size_t size; size_t size;
size = btrfs_file_extent_inline_len(leaf, item); size = btrfs_file_extent_inline_len(leaf, path->slots[0], item);
extent_end = ALIGN(extent_start + size, root->sectorsize); extent_end = ALIGN(extent_start + size, root->sectorsize);
} }
next: next:
...@@ -6231,7 +6238,7 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page, ...@@ -6231,7 +6238,7 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
goto out; goto out;
} }
size = btrfs_file_extent_inline_len(leaf, item); size = btrfs_file_extent_inline_len(leaf, path->slots[0], item);
extent_offset = page_offset(page) + pg_offset - extent_start; extent_offset = page_offset(page) + pg_offset - extent_start;
copy_size = min_t(u64, PAGE_CACHE_SIZE - pg_offset, copy_size = min_t(u64, PAGE_CACHE_SIZE - pg_offset,
size - extent_offset); size - extent_offset);
......
...@@ -249,7 +249,7 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l) ...@@ -249,7 +249,7 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
BTRFS_FILE_EXTENT_INLINE) { BTRFS_FILE_EXTENT_INLINE) {
printk(KERN_INFO "\t\tinline extent data " printk(KERN_INFO "\t\tinline extent data "
"size %u\n", "size %u\n",
btrfs_file_extent_inline_len(l, fi)); btrfs_file_extent_inline_len(l, i, fi));
break; break;
} }
printk(KERN_INFO "\t\textent data disk bytenr %llu " printk(KERN_INFO "\t\textent data disk bytenr %llu "
......
...@@ -1377,7 +1377,7 @@ static int read_symlink(struct btrfs_root *root, ...@@ -1377,7 +1377,7 @@ static int read_symlink(struct btrfs_root *root,
BUG_ON(compression); BUG_ON(compression);
off = btrfs_file_extent_inline_start(ei); off = btrfs_file_extent_inline_start(ei);
len = btrfs_file_extent_inline_len(path->nodes[0], ei); len = btrfs_file_extent_inline_len(path->nodes[0], path->slots[0], ei);
ret = fs_path_add_from_extent_buffer(dest, path->nodes[0], off, len); ret = fs_path_add_from_extent_buffer(dest, path->nodes[0], off, len);
...@@ -4207,7 +4207,8 @@ static int send_write_or_clone(struct send_ctx *sctx, ...@@ -4207,7 +4207,8 @@ static int send_write_or_clone(struct send_ctx *sctx,
struct btrfs_file_extent_item); struct btrfs_file_extent_item);
type = btrfs_file_extent_type(path->nodes[0], ei); type = btrfs_file_extent_type(path->nodes[0], ei);
if (type == BTRFS_FILE_EXTENT_INLINE) { if (type == BTRFS_FILE_EXTENT_INLINE) {
len = btrfs_file_extent_inline_len(path->nodes[0], ei); len = btrfs_file_extent_inline_len(path->nodes[0],
path->slots[0], ei);
/* /*
* it is possible the inline item won't cover the whole page, * it is possible the inline item won't cover the whole page,
* but there may be items after this page. Make * but there may be items after this page. Make
...@@ -4448,7 +4449,8 @@ static int get_last_extent(struct send_ctx *sctx, u64 offset) ...@@ -4448,7 +4449,8 @@ static int get_last_extent(struct send_ctx *sctx, u64 offset)
struct btrfs_file_extent_item); struct btrfs_file_extent_item);
type = btrfs_file_extent_type(path->nodes[0], fi); type = btrfs_file_extent_type(path->nodes[0], fi);
if (type == BTRFS_FILE_EXTENT_INLINE) { if (type == BTRFS_FILE_EXTENT_INLINE) {
u64 size = btrfs_file_extent_inline_len(path->nodes[0], fi); u64 size = btrfs_file_extent_inline_len(path->nodes[0],
path->slots[0], fi);
extent_end = ALIGN(key.offset + size, extent_end = ALIGN(key.offset + size,
sctx->send_root->sectorsize); sctx->send_root->sectorsize);
} else { } else {
...@@ -4482,7 +4484,8 @@ static int maybe_send_hole(struct send_ctx *sctx, struct btrfs_path *path, ...@@ -4482,7 +4484,8 @@ static int maybe_send_hole(struct send_ctx *sctx, struct btrfs_path *path,
struct btrfs_file_extent_item); struct btrfs_file_extent_item);
type = btrfs_file_extent_type(path->nodes[0], fi); type = btrfs_file_extent_type(path->nodes[0], fi);
if (type == BTRFS_FILE_EXTENT_INLINE) { if (type == BTRFS_FILE_EXTENT_INLINE) {
u64 size = btrfs_file_extent_inline_len(path->nodes[0], fi); u64 size = btrfs_file_extent_inline_len(path->nodes[0],
path->slots[0], fi);
extent_end = ALIGN(key->offset + size, extent_end = ALIGN(key->offset + size,
sctx->send_root->sectorsize); sctx->send_root->sectorsize);
} else { } else {
......
...@@ -570,7 +570,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, ...@@ -570,7 +570,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
if (btrfs_file_extent_disk_bytenr(eb, item) == 0) if (btrfs_file_extent_disk_bytenr(eb, item) == 0)
nbytes = 0; nbytes = 0;
} else if (found_type == BTRFS_FILE_EXTENT_INLINE) { } else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
size = btrfs_file_extent_inline_len(eb, item); size = btrfs_file_extent_inline_len(eb, slot, item);
nbytes = btrfs_file_extent_ram_bytes(eb, item); nbytes = btrfs_file_extent_ram_bytes(eb, item);
extent_end = ALIGN(start + size, root->sectorsize); extent_end = ALIGN(start + size, root->sectorsize);
} else { } else {
...@@ -3367,7 +3367,9 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, ...@@ -3367,7 +3367,9 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
struct btrfs_file_extent_item); struct btrfs_file_extent_item);
if (btrfs_file_extent_type(src, extent) == if (btrfs_file_extent_type(src, extent) ==
BTRFS_FILE_EXTENT_INLINE) { BTRFS_FILE_EXTENT_INLINE) {
len = btrfs_file_extent_inline_len(src, extent); len = btrfs_file_extent_inline_len(src,
src_path->slots[0],
extent);
*last_extent = ALIGN(key.offset + len, *last_extent = ALIGN(key.offset + len,
log->sectorsize); log->sectorsize);
} else { } else {
...@@ -3431,7 +3433,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, ...@@ -3431,7 +3433,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
extent = btrfs_item_ptr(src, i, struct btrfs_file_extent_item); extent = btrfs_item_ptr(src, i, struct btrfs_file_extent_item);
if (btrfs_file_extent_type(src, extent) == if (btrfs_file_extent_type(src, extent) ==
BTRFS_FILE_EXTENT_INLINE) { BTRFS_FILE_EXTENT_INLINE) {
len = btrfs_file_extent_inline_len(src, extent); len = btrfs_file_extent_inline_len(src, i, extent);
extent_end = ALIGN(key.offset + len, log->sectorsize); extent_end = ALIGN(key.offset + len, log->sectorsize);
} else { } else {
len = btrfs_file_extent_num_bytes(src, extent); len = btrfs_file_extent_num_bytes(src, extent);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment