提交 3326d1b0 编写于 作者: C Chris Mason

Btrfs: Allow tails larger than one page

Signed-off-by: NChris Mason <chris.mason@oracle.com>
上级 4dc11904
...@@ -1766,8 +1766,9 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -1766,8 +1766,9 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
/* first try to make some room by pushing left and right */ /* first try to make some room by pushing left and right */
wret = push_leaf_left(trans, root, path, data_size); wret = push_leaf_left(trans, root, path, data_size);
if (wret < 0) if (wret < 0) {
return wret; return wret;
}
if (wret) { if (wret) {
wret = push_leaf_right(trans, root, path, data_size); wret = push_leaf_right(trans, root, path, data_size);
if (wret < 0) if (wret < 0)
...@@ -1777,8 +1778,9 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -1777,8 +1778,9 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
/* did the pushes work? */ /* did the pushes work? */
if (btrfs_leaf_free_space(root, l) >= if (btrfs_leaf_free_space(root, l) >=
sizeof(struct btrfs_item) + data_size) sizeof(struct btrfs_item) + data_size) {
return 0; return 0;
}
if (!path->nodes[1]) { if (!path->nodes[1]) {
ret = insert_new_root(trans, root, path, 1); ret = insert_new_root(trans, root, path, 1);
...@@ -1822,7 +1824,11 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -1822,7 +1824,11 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
return ret; return ret;
} }
mid = slot; mid = slot;
double_split = 1; if (mid != nritems &&
leaf_space_used(l, mid, nritems - mid) +
space_needed > BTRFS_LEAF_DATA_SIZE(root)) {
double_split = 1;
}
} }
} else { } else {
if (leaf_space_used(l, 0, mid + 1) + space_needed > if (leaf_space_used(l, 0, mid + 1) + space_needed >
...@@ -1910,8 +1916,9 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -1910,8 +1916,9 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
BUG_ON(path->slots[0] < 0); BUG_ON(path->slots[0] < 0);
if (!double_split) if (!double_split) {
return ret; return ret;
}
right = btrfs_alloc_free_block(trans, root, root->leafsize, right = btrfs_alloc_free_block(trans, root, root->leafsize,
l->start, 0); l->start, 0);
...@@ -2048,7 +2055,11 @@ int btrfs_extend_item(struct btrfs_trans_handle *trans, ...@@ -2048,7 +2055,11 @@ int btrfs_extend_item(struct btrfs_trans_handle *trans,
old_data = btrfs_item_end_nr(leaf, slot); old_data = btrfs_item_end_nr(leaf, slot);
BUG_ON(slot < 0); BUG_ON(slot < 0);
BUG_ON(slot >= nritems); if (slot >= nritems) {
btrfs_print_leaf(root, leaf);
printk("slot %d too large, nritems %d\n", slot, nritems);
BUG_ON(1);
}
/* /*
* item0..itemN ... dataN.offset..dataN.size .. data0.size * item0..itemN ... dataN.offset..dataN.size .. data0.size
...@@ -2132,6 +2143,9 @@ int btrfs_insert_empty_item(struct btrfs_trans_handle *trans, ...@@ -2132,6 +2143,9 @@ int btrfs_insert_empty_item(struct btrfs_trans_handle *trans,
if (btrfs_leaf_free_space(root, leaf) < if (btrfs_leaf_free_space(root, leaf) <
sizeof(struct btrfs_item) + data_size) { sizeof(struct btrfs_item) + data_size) {
btrfs_print_leaf(root, leaf);
printk("not enough freespace need %u have %d\n",
data_size, btrfs_leaf_free_space(root, leaf));
BUG(); BUG();
} }
......
...@@ -1137,7 +1137,7 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end); ...@@ -1137,7 +1137,7 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end);
extern struct file_operations btrfs_file_operations; extern struct file_operations btrfs_file_operations;
int btrfs_drop_extents(struct btrfs_trans_handle *trans, int btrfs_drop_extents(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct inode *inode, struct btrfs_root *root, struct inode *inode,
u64 start, u64 end, u64 *hint_block); u64 start, u64 end, u64 inline_end, u64 *hint_block);
/* tree-defrag.c */ /* tree-defrag.c */
int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
struct btrfs_root *root, int cache_only); struct btrfs_root *root, int cache_only);
......
...@@ -82,8 +82,9 @@ static void btrfs_drop_pages(struct page **pages, size_t num_pages) ...@@ -82,8 +82,9 @@ static void btrfs_drop_pages(struct page **pages, size_t num_pages)
static int insert_inline_extent(struct btrfs_trans_handle *trans, static int insert_inline_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct inode *inode, struct btrfs_root *root, struct inode *inode,
u64 offset, ssize_t size, u64 offset, size_t size,
struct page *page, size_t page_offset) struct page **pages, size_t page_offset,
int num_pages)
{ {
struct btrfs_key key; struct btrfs_key key;
struct btrfs_path *path; struct btrfs_path *path;
...@@ -91,9 +92,12 @@ static int insert_inline_extent(struct btrfs_trans_handle *trans, ...@@ -91,9 +92,12 @@ static int insert_inline_extent(struct btrfs_trans_handle *trans,
char *kaddr; char *kaddr;
unsigned long ptr; unsigned long ptr;
struct btrfs_file_extent_item *ei; struct btrfs_file_extent_item *ei;
struct page *page;
u32 datasize; u32 datasize;
int err = 0; int err = 0;
int ret; int ret;
int i;
ssize_t cur_size;
path = btrfs_alloc_path(); path = btrfs_alloc_path();
if (!path) if (!path)
...@@ -104,25 +108,97 @@ static int insert_inline_extent(struct btrfs_trans_handle *trans, ...@@ -104,25 +108,97 @@ static int insert_inline_extent(struct btrfs_trans_handle *trans,
key.objectid = inode->i_ino; key.objectid = inode->i_ino;
key.offset = offset; key.offset = offset;
btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY); btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY);
BUG_ON(size >= PAGE_CACHE_SIZE); datasize = btrfs_file_extent_calc_inline_size(offset + size);
datasize = btrfs_file_extent_calc_inline_size(size);
ret = btrfs_insert_empty_item(trans, root, path, &key, ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
datasize); if (ret < 0) {
if (ret) {
err = ret; err = ret;
goto fail; goto fail;
} }
leaf = path->nodes[0]; if (ret == 1) {
ei = btrfs_item_ptr(leaf, path->slots[0], path->slots[0]--;
struct btrfs_file_extent_item); leaf = path->nodes[0];
btrfs_set_file_extent_generation(leaf, ei, trans->transid); ei = btrfs_item_ptr(leaf, path->slots[0],
btrfs_set_file_extent_type(leaf, ei, BTRFS_FILE_EXTENT_INLINE); struct btrfs_file_extent_item);
ptr = btrfs_file_extent_inline_start(ei);
if (btrfs_file_extent_type(leaf, ei) !=
kaddr = kmap_atomic(page, KM_USER1); BTRFS_FILE_EXTENT_INLINE) {
write_extent_buffer(leaf, kaddr + page_offset, ptr, size); goto insert;
kunmap_atomic(kaddr, KM_USER1); }
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
ret = 0;
}
if (ret == 0) {
u32 found_size;
u64 found_start;
leaf = path->nodes[0];
ei = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_file_extent_item);
if (btrfs_file_extent_type(leaf, ei) !=
BTRFS_FILE_EXTENT_INLINE) {
err = ret;
btrfs_print_leaf(root, leaf);
printk("found wasn't inline offset %Lu inode %lu\n",
offset, inode->i_ino);
goto fail;
}
found_start = key.offset;
found_size = btrfs_file_extent_inline_len(leaf,
btrfs_item_nr(leaf, path->slots[0]));
if (found_size < offset + size) {
btrfs_release_path(root, path);
ret = btrfs_search_slot(trans, root, &key, path,
offset + size - found_size -
found_start, 1);
BUG_ON(ret != 0);
ret = btrfs_extend_item(trans, root, path,
offset + size - found_size -
found_start);
if (ret) {
err = ret;
goto fail;
}
leaf = path->nodes[0];
ei = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_file_extent_item);
}
} else {
insert:
btrfs_release_path(root, path);
ret = btrfs_insert_empty_item(trans, root, path, &key,
datasize);
if (ret) {
err = ret;
printk("got bad ret %d\n", ret);
goto fail;
}
leaf = path->nodes[0];
ei = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_file_extent_item);
btrfs_set_file_extent_generation(leaf, ei, trans->transid);
btrfs_set_file_extent_type(leaf, ei, BTRFS_FILE_EXTENT_INLINE);
}
ptr = btrfs_file_extent_inline_start(ei) + offset;
cur_size = size;
i = 0;
while (size > 0) {
page = pages[i];
kaddr = kmap_atomic(page, KM_USER0);
cur_size = min(PAGE_CACHE_SIZE - page_offset, size);
write_extent_buffer(leaf, kaddr + page_offset, ptr, cur_size);
kunmap_atomic(kaddr, KM_USER0);
page_offset = 0;
ptr += cur_size;
size -= cur_size;
if (i >= num_pages) {
printk("i %d num_pages %d\n", i, num_pages);
}
i++;
}
btrfs_mark_buffer_dirty(leaf); btrfs_mark_buffer_dirty(leaf);
fail: fail:
btrfs_free_path(path); btrfs_free_path(path);
...@@ -193,6 +269,7 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans, ...@@ -193,6 +269,7 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
err = btrfs_drop_extents(trans, root, inode, err = btrfs_drop_extents(trans, root, inode,
last_pos_in_file, last_pos_in_file,
last_pos_in_file + hole_size, last_pos_in_file + hole_size,
last_pos_in_file,
&hint_byte); &hint_byte);
if (err) if (err)
goto failed; goto failed;
...@@ -210,11 +287,12 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans, ...@@ -210,11 +287,12 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
* either allocate an extent for the new bytes or setup the key * either allocate an extent for the new bytes or setup the key
* to show we are doing inline data in the extent * to show we are doing inline data in the extent
*/ */
inline_size = end_pos - start_pos; inline_size = end_pos;
if (isize >= PAGE_CACHE_SIZE || pos + write_bytes < inode->i_size || if (isize >= BTRFS_MAX_INLINE_DATA_SIZE(root) ||
inline_size >= BTRFS_MAX_INLINE_DATA_SIZE(root) || inline_size > 16384 ||
inline_size >= PAGE_CACHE_SIZE) { inline_size >= BTRFS_MAX_INLINE_DATA_SIZE(root)) {
u64 last_end; u64 last_end;
for (i = 0; i < num_pages; i++) { for (i = 0; i < num_pages; i++) {
struct page *p = pages[i]; struct page *p = pages[i];
SetPageUptodate(p); SetPageUptodate(p);
...@@ -225,22 +303,18 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans, ...@@ -225,22 +303,18 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
set_extent_delalloc(em_tree, start_pos, end_of_last_block, set_extent_delalloc(em_tree, start_pos, end_of_last_block,
GFP_NOFS); GFP_NOFS);
} else { } else {
struct page *p = pages[0]; u64 aligned_end;
/* step one, delete the existing extents in this range */ /* step one, delete the existing extents in this range */
aligned_end = (pos + write_bytes + root->sectorsize - 1) &
~((u64)root->sectorsize - 1);
err = btrfs_drop_extents(trans, root, inode, start_pos, err = btrfs_drop_extents(trans, root, inode, start_pos,
(pos + write_bytes + root->sectorsize -1) & aligned_end, end_pos, &hint_byte);
~((u64)root->sectorsize - 1), &hint_byte);
if (err) if (err)
goto failed; goto failed;
err = insert_inline_extent(trans, root, inode, start_pos, err = insert_inline_extent(trans, root, inode, start_pos,
end_pos - start_pos, p, 0); end_pos - start_pos, pages, 0,
num_pages);
BUG_ON(err); BUG_ON(err);
em->start = start_pos;
em->end = end_pos - 1;
em->block_start = EXTENT_MAP_INLINE;
em->block_end = EXTENT_MAP_INLINE;
add_extent_mapping(em_tree, em);
} }
if (end_pos > isize) { if (end_pos > isize) {
i_size_write(inode, end_pos); i_size_write(inode, end_pos);
...@@ -285,7 +359,7 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end) ...@@ -285,7 +359,7 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end)
*/ */
int btrfs_drop_extents(struct btrfs_trans_handle *trans, int btrfs_drop_extents(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct inode *inode, struct btrfs_root *root, struct inode *inode,
u64 start, u64 end, u64 *hint_byte) u64 start, u64 end, u64 inline_end, u64 *hint_byte)
{ {
int ret; int ret;
struct btrfs_key key; struct btrfs_key key;
...@@ -401,8 +475,8 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans, ...@@ -401,8 +475,8 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans,
BUG_ON(ret); BUG_ON(ret);
} }
} }
WARN_ON(found_inline); if (!found_inline)
bookend = 1; bookend = 1;
} }
/* truncate existing extent */ /* truncate existing extent */
if (start > key.offset) { if (start > key.offset) {
...@@ -425,8 +499,14 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans, ...@@ -425,8 +499,14 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans,
btrfs_set_file_extent_num_bytes(leaf, extent, btrfs_set_file_extent_num_bytes(leaf, extent,
new_num); new_num);
btrfs_mark_buffer_dirty(leaf); btrfs_mark_buffer_dirty(leaf);
} else { } else if (end > extent_end &&
WARN_ON(1); key.offset < inline_end &&
inline_end < extent_end) {
u32 new_size;
new_size = btrfs_file_extent_calc_inline_size(
inline_end - key.offset);
btrfs_truncate_item(trans, root, path,
new_size);
} }
} }
/* delete the entire extent */ /* delete the entire extent */
......
...@@ -87,7 +87,7 @@ static int run_delalloc_range(struct inode *inode, u64 start, u64 end) ...@@ -87,7 +87,7 @@ static int run_delalloc_range(struct inode *inode, u64 start, u64 end)
BUG_ON(!trans); BUG_ON(!trans);
num_bytes = (end - start + blocksize) & ~(blocksize - 1); num_bytes = (end - start + blocksize) & ~(blocksize - 1);
ret = btrfs_drop_extents(trans, root, inode, ret = btrfs_drop_extents(trans, root, inode,
start, start + num_bytes, &alloc_hint); start, start + num_bytes, start, &alloc_hint);
ret = btrfs_alloc_extent(trans, root, inode->i_ino, num_bytes, 0, ret = btrfs_alloc_extent(trans, root, inode->i_ino, num_bytes, 0,
alloc_hint, (u64)-1, &ins, 1); alloc_hint, (u64)-1, &ins, 1);
...@@ -776,7 +776,8 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -776,7 +776,8 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
trans = btrfs_start_transaction(root, 1); trans = btrfs_start_transaction(root, 1);
btrfs_set_trans_block_group(trans, inode); btrfs_set_trans_block_group(trans, inode);
err = btrfs_drop_extents(trans, root, inode, err = btrfs_drop_extents(trans, root, inode,
pos, pos + hole_size, &alloc_hint); pos, pos + hole_size, pos,
&alloc_hint);
err = btrfs_insert_file_extent(trans, root, inode->i_ino, err = btrfs_insert_file_extent(trans, root, inode->i_ino,
pos, 0, 0, hole_size); pos, 0, 0, hole_size);
...@@ -1581,7 +1582,9 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page, ...@@ -1581,7 +1582,9 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
} else if (found_type == BTRFS_FILE_EXTENT_INLINE) { } else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
unsigned long ptr; unsigned long ptr;
char *map; char *map;
u32 size; size_t size;
size_t extent_offset;
size_t copy_size;
size = btrfs_file_extent_inline_len(leaf, btrfs_item_nr(leaf, size = btrfs_file_extent_inline_len(leaf, btrfs_item_nr(leaf,
path->slots[0])); path->slots[0]));
...@@ -1600,26 +1603,31 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page, ...@@ -1600,26 +1603,31 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
goto not_found_em; goto not_found_em;
} }
extent_offset = (page->index << PAGE_CACHE_SHIFT) -
extent_start;
ptr = btrfs_file_extent_inline_start(item) + extent_offset;
map = kmap(page);
copy_size = min(PAGE_CACHE_SIZE - page_offset,
size - extent_offset);
em->block_start = EXTENT_MAP_INLINE; em->block_start = EXTENT_MAP_INLINE;
em->block_end = EXTENT_MAP_INLINE; em->block_end = EXTENT_MAP_INLINE;
em->start = extent_start; em->start = extent_start + extent_offset;
em->end = extent_end; em->end = (em->start + copy_size -1) |
((u64)root->sectorsize -1);
if (!page) { if (!page) {
goto insert; goto insert;
} }
ptr = btrfs_file_extent_inline_start(item); read_extent_buffer(leaf, map + page_offset, ptr, copy_size);
map = kmap(page);
read_extent_buffer(leaf, map + page_offset, ptr, size);
/* /*
memset(map + page_offset + size, 0, memset(map + page_offset + copy_size, 0,
root->sectorsize - (page_offset + size)); PAGE_CACHE_SIZE - copy_size - page_offset);
*/ */
flush_dcache_page(page); flush_dcache_page(page);
kunmap(page); kunmap(page);
set_extent_uptodate(em_tree, extent_start, set_extent_uptodate(em_tree, em->start, em->end, GFP_NOFS);
extent_end, GFP_NOFS);
goto insert; goto insert;
} else { } else {
printk("unkknown found_type %d\n", found_type); printk("unkknown found_type %d\n", found_type);
......
...@@ -280,7 +280,6 @@ int btrfs_get_sb_bdev(struct file_system_type *fs_type, ...@@ -280,7 +280,6 @@ int btrfs_get_sb_bdev(struct file_system_type *fs_type,
error_bdev: error_bdev:
close_bdev_excl(bdev); close_bdev_excl(bdev);
error: error:
printk("get_sb failed\n");
return error; return error;
} }
/* end copy & paste */ /* end copy & paste */
...@@ -295,7 +294,6 @@ static int btrfs_get_sb(struct file_system_type *fs_type, ...@@ -295,7 +294,6 @@ static int btrfs_get_sb(struct file_system_type *fs_type,
ret = btrfs_get_sb_bdev(fs_type, flags, dev_name, data, ret = btrfs_get_sb_bdev(fs_type, flags, dev_name, data,
btrfs_fill_super, mnt, btrfs_fill_super, mnt,
subvol_name ? subvol_name : "default"); subvol_name ? subvol_name : "default");
printk("btrfs_get_sb returns %d\n", ret);
return ret; return ret;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册