Btrfs: break up __btrfs_write_out_cache to cut down stack usage

__btrfs_write_out_cache was one of our stack pigs.  This breaks it
up into helper functions and slims it down to 194 bytes.

Signed-off-by: Chris Mason <clm@fb.com>
This commit is contained in:
Chris Mason 2014-05-19 20:47:56 -07:00
parent 2a10840945
commit d4452bc526
1 changed files with 194 additions and 120 deletions

View File

@ -851,90 +851,44 @@ out:
return ret;
}
/**
* __btrfs_write_out_cache - write out cached info to an inode
* @root - the root the inode belongs to
* @ctl - the free space cache we are going to write out
* @block_group - the block_group for this cache if it belongs to a block_group
* @trans - the trans handle
* @path - the path to use
* @offset - the offset for the key we'll insert
*
* This function writes out a free space cache struct to disk for quick recovery
* on mount. This will return 0 if it was successfull in writing the cache out,
* and -1 if it was not.
*/
static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
struct btrfs_free_space_ctl *ctl,
struct btrfs_block_group_cache *block_group,
struct btrfs_trans_handle *trans,
struct btrfs_path *path, u64 offset)
static noinline_for_stack
int write_cache_extent_entries(struct io_ctl *io_ctl,
struct btrfs_free_space_ctl *ctl,
struct btrfs_block_group_cache *block_group,
int *entries, int *bitmaps,
struct list_head *bitmap_list)
{
struct btrfs_free_space_header *header;
struct extent_buffer *leaf;
struct rb_node *node;
struct list_head *pos, *n;
struct extent_state *cached_state = NULL;
struct btrfs_free_cluster *cluster = NULL;
struct extent_io_tree *unpin = NULL;
struct io_ctl io_ctl;
struct list_head bitmap_list;
struct btrfs_key key;
u64 start, extent_start, extent_end, len;
int entries = 0;
int bitmaps = 0;
int ret;
int err = -1;
INIT_LIST_HEAD(&bitmap_list);
if (!i_size_read(inode))
return -1;
ret = io_ctl_init(&io_ctl, inode, root);
if (ret)
return -1;
struct btrfs_free_cluster *cluster = NULL;
struct rb_node *node = rb_first(&ctl->free_space_offset);
/* Get the cluster for this block_group if it exists */
if (block_group && !list_empty(&block_group->cluster_list))
if (block_group && !list_empty(&block_group->cluster_list)) {
cluster = list_entry(block_group->cluster_list.next,
struct btrfs_free_cluster,
block_group_list);
}
/* Lock all pages first so we can lock the extent safely. */
io_ctl_prepare_pages(&io_ctl, inode, 0);
lock_extent_bits(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1,
0, &cached_state);
node = rb_first(&ctl->free_space_offset);
if (!node && cluster) {
node = rb_first(&cluster->root);
cluster = NULL;
}
/* Make sure we can fit our crcs into the first page */
if (io_ctl.check_crcs &&
(io_ctl.num_pages * sizeof(u32)) >= PAGE_CACHE_SIZE)
goto out_nospc;
io_ctl_set_generation(&io_ctl, trans->transid);
/* Write out the extent entries */
while (node) {
struct btrfs_free_space *e;
e = rb_entry(node, struct btrfs_free_space, offset_index);
entries++;
*entries += 1;
ret = io_ctl_add_entry(&io_ctl, e->offset, e->bytes,
ret = io_ctl_add_entry(io_ctl, e->offset, e->bytes,
e->bitmap);
if (ret)
goto out_nospc;
goto fail;
if (e->bitmap) {
list_add_tail(&e->list, &bitmap_list);
bitmaps++;
list_add_tail(&e->list, bitmap_list);
*bitmaps += 1;
}
node = rb_next(node);
if (!node && cluster) {
@ -942,13 +896,84 @@ static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
cluster = NULL;
}
}
return 0;
fail:
return -ENOSPC;
}
static noinline_for_stack int
update_cache_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct inode *inode,
struct btrfs_path *path, u64 offset,
int entries, int bitmaps)
{
struct btrfs_key key;
struct btrfs_free_space_header *header;
struct extent_buffer *leaf;
int ret;
key.objectid = BTRFS_FREE_SPACE_OBJECTID;
key.offset = offset;
key.type = 0;
ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
if (ret < 0) {
clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, inode->i_size - 1,
EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0, NULL,
GFP_NOFS);
goto fail;
}
leaf = path->nodes[0];
if (ret > 0) {
struct btrfs_key found_key;
ASSERT(path->slots[0]);
path->slots[0]--;
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
if (found_key.objectid != BTRFS_FREE_SPACE_OBJECTID ||
found_key.offset != offset) {
clear_extent_bit(&BTRFS_I(inode)->io_tree, 0,
inode->i_size - 1,
EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0,
NULL, GFP_NOFS);
btrfs_release_path(path);
goto fail;
}
}
BTRFS_I(inode)->generation = trans->transid;
header = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_free_space_header);
btrfs_set_free_space_entries(leaf, header, entries);
btrfs_set_free_space_bitmaps(leaf, header, bitmaps);
btrfs_set_free_space_generation(leaf, header, trans->transid);
btrfs_mark_buffer_dirty(leaf);
btrfs_release_path(path);
return 0;
fail:
return -1;
}
static noinline_for_stack int
add_ioctl_entries(struct btrfs_root *root,
struct inode *inode,
struct btrfs_block_group_cache *block_group,
struct io_ctl *io_ctl,
struct extent_state **cached_state,
struct list_head *bitmap_list,
int *entries)
{
u64 start, extent_start, extent_end, len;
struct list_head *pos, *n;
struct extent_io_tree *unpin = NULL;
int ret;
/*
* We want to add any pinned extents to our free space cache
* so we don't leak the space
*/
/*
*
* We shouldn't have switched the pinned extents yet so this is the
* right one
*/
@ -977,8 +1002,8 @@ static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
block_group->key.offset, extent_end + 1);
len = extent_end - extent_start;
entries++;
ret = io_ctl_add_entry(&io_ctl, extent_start, len, NULL);
*entries += 1;
ret = io_ctl_add_entry(io_ctl, extent_start, len, NULL);
if (ret)
goto out_nospc;
@ -986,74 +1011,129 @@ static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
}
/* Write out the bitmaps */
list_for_each_safe(pos, n, &bitmap_list) {
list_for_each_safe(pos, n, bitmap_list) {
struct btrfs_free_space *entry =
list_entry(pos, struct btrfs_free_space, list);
ret = io_ctl_add_bitmap(&io_ctl, entry->bitmap);
ret = io_ctl_add_bitmap(io_ctl, entry->bitmap);
if (ret)
goto out_nospc;
list_del_init(&entry->list);
}
/* Zero out the rest of the pages just to make sure */
io_ctl_zero_remaining_pages(&io_ctl);
io_ctl_zero_remaining_pages(io_ctl);
ret = btrfs_dirty_pages(root, inode, io_ctl.pages, io_ctl.num_pages,
0, i_size_read(inode), &cached_state);
io_ctl_drop_pages(&io_ctl);
ret = btrfs_dirty_pages(root, inode, io_ctl->pages, io_ctl->num_pages,
0, i_size_read(inode), cached_state);
io_ctl_drop_pages(io_ctl);
unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0,
i_size_read(inode) - 1, &cached_state, GFP_NOFS);
i_size_read(inode) - 1, cached_state, GFP_NOFS);
if (ret)
goto out;
goto fail;
ret = btrfs_wait_ordered_range(inode, 0, (u64)-1);
if (ret) {
clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, inode->i_size - 1,
EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0, NULL,
GFP_NOFS);
goto fail;
}
return 0;
fail:
return -1;
out_nospc:
return -ENOSPC;
}
static void noinline_for_stack
cleanup_write_cache_enospc(struct inode *inode,
struct io_ctl *io_ctl,
struct extent_state **cached_state,
struct list_head *bitmap_list)
{
struct list_head *pos, *n;
list_for_each_safe(pos, n, bitmap_list) {
struct btrfs_free_space *entry =
list_entry(pos, struct btrfs_free_space, list);
list_del_init(&entry->list);
}
io_ctl_drop_pages(io_ctl);
unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0,
i_size_read(inode) - 1, cached_state,
GFP_NOFS);
}
/**
* __btrfs_write_out_cache - write out cached info to an inode
* @root - the root the inode belongs to
* @ctl - the free space cache we are going to write out
* @block_group - the block_group for this cache if it belongs to a block_group
* @trans - the trans handle
* @path - the path to use
* @offset - the offset for the key we'll insert
*
* This function writes out a free space cache struct to disk for quick recovery
* on mount. This will return 0 if it was successfull in writing the cache out,
* and -1 if it was not.
*/
static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
struct btrfs_free_space_ctl *ctl,
struct btrfs_block_group_cache *block_group,
struct btrfs_trans_handle *trans,
struct btrfs_path *path, u64 offset)
{
struct extent_state *cached_state = NULL;
struct io_ctl io_ctl;
struct list_head bitmap_list;
int entries = 0;
int bitmaps = 0;
int ret;
int err = -1;
INIT_LIST_HEAD(&bitmap_list);
if (!i_size_read(inode))
return -1;
ret = io_ctl_init(&io_ctl, inode, root);
if (ret)
return -1;
/* Lock all pages first so we can lock the extent safely. */
io_ctl_prepare_pages(&io_ctl, inode, 0);
lock_extent_bits(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1,
0, &cached_state);
/* Make sure we can fit our crcs into the first page */
if (io_ctl.check_crcs &&
(io_ctl.num_pages * sizeof(u32)) >= PAGE_CACHE_SIZE)
goto out_nospc;
io_ctl_set_generation(&io_ctl, trans->transid);
ret = write_cache_extent_entries(&io_ctl, ctl,
block_group, &entries, &bitmaps,
&bitmap_list);
if (ret)
goto out_nospc;
ret = add_ioctl_entries(root, inode, block_group, &io_ctl,
&cached_state, &bitmap_list, &entries);
if (ret == -ENOSPC)
goto out_nospc;
else if (ret)
goto out;
}
key.objectid = BTRFS_FREE_SPACE_OBJECTID;
key.offset = offset;
key.type = 0;
err = update_cache_item(trans, root, inode, path, offset,
entries, bitmaps);
ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
if (ret < 0) {
clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, inode->i_size - 1,
EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0, NULL,
GFP_NOFS);
goto out;
}
leaf = path->nodes[0];
if (ret > 0) {
struct btrfs_key found_key;
ASSERT(path->slots[0]);
path->slots[0]--;
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
if (found_key.objectid != BTRFS_FREE_SPACE_OBJECTID ||
found_key.offset != offset) {
clear_extent_bit(&BTRFS_I(inode)->io_tree, 0,
inode->i_size - 1,
EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0,
NULL, GFP_NOFS);
btrfs_release_path(path);
goto out;
}
}
BTRFS_I(inode)->generation = trans->transid;
header = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_free_space_header);
btrfs_set_free_space_entries(leaf, header, entries);
btrfs_set_free_space_bitmaps(leaf, header, bitmaps);
btrfs_set_free_space_generation(leaf, header, trans->transid);
btrfs_mark_buffer_dirty(leaf);
btrfs_release_path(path);
err = 0;
out:
io_ctl_free(&io_ctl);
if (err) {
@ -1064,14 +1144,8 @@ out:
return err;
out_nospc:
list_for_each_safe(pos, n, &bitmap_list) {
struct btrfs_free_space *entry =
list_entry(pos, struct btrfs_free_space, list);
list_del_init(&entry->list);
}
io_ctl_drop_pages(&io_ctl);
unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0,
i_size_read(inode) - 1, &cached_state, GFP_NOFS);
cleanup_write_cache_enospc(inode, &io_ctl, &cached_state, &bitmap_list);
goto out;
}