Skip to content

Commit

Permalink
Btrfs: handle enospc accounting for free space inodes
Browse files Browse the repository at this point in the history
Since free space inodes now use normal checksumming we need to make sure to
account for their metadata use.  So reserve metadata space, and then if we fail
to write out the metadata we can just release it, otherwise it will be freed up
when the io completes.  Thanks,

Signed-off-by: Josef Bacik <josef@redhat.com>
  • Loading branch information
Josef Bacik committed Oct 19, 2011
1 parent 300e4f8 commit c09544e
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 23 deletions.
18 changes: 13 additions & 5 deletions fs/btrfs/extent-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -2755,16 +2755,20 @@ static int cache_save_setup(struct btrfs_block_group_cache *block_group,
num_pages *= 16;
num_pages *= PAGE_CACHE_SIZE;

ret = btrfs_check_data_free_space(inode, num_pages);
ret = btrfs_delalloc_reserve_space(inode, num_pages);
if (ret)
goto out_put;

ret = btrfs_prealloc_file_range_trans(inode, trans, 0, 0, num_pages,
num_pages, num_pages,
&alloc_hint);
if (!ret)
if (!ret) {
dcs = BTRFS_DC_SETUP;
btrfs_free_reserved_data_space(inode, num_pages);
btrfs_free_reserved_data_space(inode, num_pages);
} else {
btrfs_delalloc_release_space(inode, num_pages);
}

out_put:
iput(inode);
out_free:
Expand Down Expand Up @@ -4002,9 +4006,13 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
struct btrfs_block_rsv *block_rsv = &root->fs_info->delalloc_block_rsv;
u64 to_reserve = 0;
unsigned nr_extents = 0;
int flush = 1;
int ret;

if (btrfs_transaction_in_commit(root->fs_info))
if (btrfs_is_free_space_inode(root, inode))
flush = 0;

if (flush && btrfs_transaction_in_commit(root->fs_info))
schedule_timeout(1);

num_bytes = ALIGN(num_bytes, root->sectorsize);
Expand All @@ -4023,7 +4031,7 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
to_reserve += calc_csum_metadata_size(inode, num_bytes, 1);
spin_unlock(&BTRFS_I(inode)->lock);

ret = reserve_metadata_bytes(NULL, root, block_rsv, to_reserve, 1);
ret = reserve_metadata_bytes(NULL, root, block_rsv, to_reserve, flush);
if (ret) {
u64 to_free = 0;
unsigned dropped;
Expand Down
44 changes: 29 additions & 15 deletions fs/btrfs/free-space-cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,19 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,
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.
*/
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,
Expand All @@ -555,15 +568,16 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
int index = 0, num_pages = 0;
int entries = 0;
int bitmaps = 0;
int ret = -1;
int ret;
int err = -1;
bool next_page = false;
bool out_of_space = false;

INIT_LIST_HEAD(&bitmap_list);

node = rb_first(&ctl->free_space_offset);
if (!node)
return 0;
return -1;

if (!i_size_read(inode))
return -1;
Expand Down Expand Up @@ -767,7 +781,6 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0,
i_size_read(inode) - 1, &cached_state,
GFP_NOFS);
ret = 0;
goto out;
}

Expand All @@ -789,10 +802,8 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0,
i_size_read(inode) - 1, &cached_state, GFP_NOFS);

if (ret) {
ret = 0;
if (ret)
goto out;
}

BTRFS_I(inode)->generation = trans->transid;

Expand All @@ -804,7 +815,6 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,

ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
if (ret < 0) {
ret = -1;
clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, bytes - 1,
EXTENT_DIRTY | EXTENT_DELALLOC |
EXTENT_DO_ACCOUNTING, 0, 0, NULL, GFP_NOFS);
Expand All @@ -818,7 +828,6 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
if (found_key.objectid != BTRFS_FREE_SPACE_OBJECTID ||
found_key.offset != offset) {
ret = -1;
clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, bytes - 1,
EXTENT_DIRTY | EXTENT_DELALLOC |
EXTENT_DO_ACCOUNTING, 0, 0, NULL,
Expand All @@ -835,16 +844,15 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
btrfs_mark_buffer_dirty(leaf);
btrfs_release_path(path);

ret = 1;

err = 0;
out:
kfree(pages);
if (ret != 1) {
if (err) {
invalidate_inode_pages2_range(inode->i_mapping, 0, index);
BTRFS_I(inode)->generation = 0;
}
btrfs_update_inode(trans, root, inode);
return ret;
return err;
}

int btrfs_write_out_cache(struct btrfs_root *root,
Expand All @@ -871,14 +879,16 @@ int btrfs_write_out_cache(struct btrfs_root *root,

ret = __btrfs_write_out_cache(root, inode, ctl, block_group, trans,
path, block_group->key.objectid);
if (ret < 0) {
if (ret) {
btrfs_delalloc_release_metadata(inode, inode->i_size);
spin_lock(&block_group->lock);
block_group->disk_cache_state = BTRFS_DC_ERROR;
spin_unlock(&block_group->lock);
ret = 0;

#ifdef DEBUG
printk(KERN_ERR "btrfs: failed to write free space cace "
"for block group %llu\n", block_group->key.objectid);
#endif
}

iput(inode);
Expand Down Expand Up @@ -2662,9 +2672,13 @@ int btrfs_write_out_ino_cache(struct btrfs_root *root,
return 0;

ret = __btrfs_write_out_cache(root, inode, ctl, NULL, trans, path, 0);
if (ret < 0)
if (ret) {
btrfs_delalloc_release_metadata(inode, inode->i_size);
#ifdef DEBUG
printk(KERN_ERR "btrfs: failed to write free ino cache "
"for root %llu\n", root->root_key.objectid);
#endif
}

iput(inode);
return ret;
Expand Down
6 changes: 4 additions & 2 deletions fs/btrfs/inode-map.c
Original file line number Diff line number Diff line change
Expand Up @@ -465,14 +465,16 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
/* Just to make sure we have enough space */
prealloc += 8 * PAGE_CACHE_SIZE;

ret = btrfs_check_data_free_space(inode, prealloc);
ret = btrfs_delalloc_reserve_space(inode, prealloc);
if (ret)
goto out_put;

ret = btrfs_prealloc_file_range_trans(inode, trans, 0, 0, prealloc,
prealloc, prealloc, &alloc_hint);
if (ret)
if (ret) {
btrfs_delalloc_release_space(inode, prealloc);
goto out_put;
}
btrfs_free_reserved_data_space(inode, prealloc);

out_put:
Expand Down
2 changes: 1 addition & 1 deletion fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1792,11 +1792,11 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
}
ret = 0;
out:
btrfs_delalloc_release_metadata(inode, ordered_extent->len);
if (nolock) {
if (trans)
btrfs_end_transaction_nolock(trans, root);
} else {
btrfs_delalloc_release_metadata(inode, ordered_extent->len);
if (trans)
btrfs_end_transaction(trans, root);
}
Expand Down

0 comments on commit c09544e

Please sign in to comment.