Commit 4a500fd1 authored by Yan, Zheng's avatar Yan, Zheng Committed by Chris Mason

Btrfs: Metadata ENOSPC handling for tree log

Previous patches make the allocater return -ENOSPC if there is no
unreserved free metadata space. This patch updates tree log code
and various other places to propagate/handle the ENOSPC error.
Signed-off-by: default avatarYan Zheng <zheng.yan@oracle.com>
Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent d68fc57b
...@@ -972,42 +972,6 @@ static int find_and_setup_root(struct btrfs_root *tree_root, ...@@ -972,42 +972,6 @@ static int find_and_setup_root(struct btrfs_root *tree_root,
return 0; return 0;
} }
int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info)
{
struct extent_buffer *eb;
struct btrfs_root *log_root_tree = fs_info->log_root_tree;
u64 start = 0;
u64 end = 0;
int ret;
if (!log_root_tree)
return 0;
while (1) {
ret = find_first_extent_bit(&log_root_tree->dirty_log_pages,
0, &start, &end, EXTENT_DIRTY | EXTENT_NEW);
if (ret)
break;
clear_extent_bits(&log_root_tree->dirty_log_pages, start, end,
EXTENT_DIRTY | EXTENT_NEW, GFP_NOFS);
}
eb = fs_info->log_root_tree->node;
WARN_ON(btrfs_header_level(eb) != 0);
WARN_ON(btrfs_header_nritems(eb) != 0);
ret = btrfs_free_reserved_extent(fs_info->tree_root,
eb->start, eb->len);
BUG_ON(ret);
free_extent_buffer(eb);
kfree(fs_info->log_root_tree);
fs_info->log_root_tree = NULL;
return 0;
}
static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans, static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info) struct btrfs_fs_info *fs_info)
{ {
......
...@@ -95,8 +95,6 @@ int btrfs_congested_async(struct btrfs_fs_info *info, int iodone); ...@@ -95,8 +95,6 @@ int btrfs_congested_async(struct btrfs_fs_info *info, int iodone);
unsigned long btrfs_async_submit_limit(struct btrfs_fs_info *info); unsigned long btrfs_async_submit_limit(struct btrfs_fs_info *info);
int btrfs_write_tree_block(struct extent_buffer *buf); int btrfs_write_tree_block(struct extent_buffer *buf);
int btrfs_wait_tree_block_writeback(struct extent_buffer *buf); int btrfs_wait_tree_block_writeback(struct extent_buffer *buf);
int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info);
int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans, int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info); struct btrfs_fs_info *fs_info);
int btrfs_add_log_tree(struct btrfs_trans_handle *trans, int btrfs_add_log_tree(struct btrfs_trans_handle *trans,
......
...@@ -657,6 +657,9 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, ...@@ -657,6 +657,9 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
goto found; goto found;
} }
ret = PTR_ERR(item); ret = PTR_ERR(item);
if (ret != -EFBIG && ret != -ENOENT)
goto fail_unlock;
if (ret == -EFBIG) { if (ret == -EFBIG) {
u32 item_size; u32 item_size;
/* we found one, but it isn't big enough yet */ /* we found one, but it isn't big enough yet */
......
...@@ -135,6 +135,7 @@ static int start_log_trans(struct btrfs_trans_handle *trans, ...@@ -135,6 +135,7 @@ static int start_log_trans(struct btrfs_trans_handle *trans,
struct btrfs_root *root) struct btrfs_root *root)
{ {
int ret; int ret;
int err = 0;
mutex_lock(&root->log_mutex); mutex_lock(&root->log_mutex);
if (root->log_root) { if (root->log_root) {
...@@ -155,17 +156,19 @@ static int start_log_trans(struct btrfs_trans_handle *trans, ...@@ -155,17 +156,19 @@ static int start_log_trans(struct btrfs_trans_handle *trans,
mutex_lock(&root->fs_info->tree_log_mutex); mutex_lock(&root->fs_info->tree_log_mutex);
if (!root->fs_info->log_root_tree) { if (!root->fs_info->log_root_tree) {
ret = btrfs_init_log_root_tree(trans, root->fs_info); ret = btrfs_init_log_root_tree(trans, root->fs_info);
BUG_ON(ret); if (ret)
err = ret;
} }
if (!root->log_root) { if (err == 0 && !root->log_root) {
ret = btrfs_add_log_tree(trans, root); ret = btrfs_add_log_tree(trans, root);
BUG_ON(ret); if (ret)
err = ret;
} }
mutex_unlock(&root->fs_info->tree_log_mutex); mutex_unlock(&root->fs_info->tree_log_mutex);
root->log_batch++; root->log_batch++;
atomic_inc(&root->log_writers); atomic_inc(&root->log_writers);
mutex_unlock(&root->log_mutex); mutex_unlock(&root->log_mutex);
return 0; return err;
} }
/* /*
...@@ -376,7 +379,7 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans, ...@@ -376,7 +379,7 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans,
BUG_ON(ret); BUG_ON(ret);
} }
} else if (ret) { } else if (ret) {
BUG(); return ret;
} }
dst_ptr = btrfs_item_ptr_offset(path->nodes[0], dst_ptr = btrfs_item_ptr_offset(path->nodes[0],
path->slots[0]); path->slots[0]);
...@@ -1699,9 +1702,9 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans, ...@@ -1699,9 +1702,9 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
next = btrfs_find_create_tree_block(root, bytenr, blocksize); next = btrfs_find_create_tree_block(root, bytenr, blocksize);
if (*level == 1) {
wc->process_func(root, next, wc, ptr_gen); wc->process_func(root, next, wc, ptr_gen);
if (*level == 1) {
path->slots[*level]++; path->slots[*level]++;
if (wc->free) { if (wc->free) {
btrfs_read_buffer(next, ptr_gen); btrfs_read_buffer(next, ptr_gen);
...@@ -1734,35 +1737,7 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans, ...@@ -1734,35 +1737,7 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
WARN_ON(*level < 0); WARN_ON(*level < 0);
WARN_ON(*level >= BTRFS_MAX_LEVEL); WARN_ON(*level >= BTRFS_MAX_LEVEL);
if (path->nodes[*level] == root->node) path->slots[*level] = btrfs_header_nritems(path->nodes[*level]);
parent = path->nodes[*level];
else
parent = path->nodes[*level + 1];
bytenr = path->nodes[*level]->start;
blocksize = btrfs_level_size(root, *level);
root_owner = btrfs_header_owner(parent);
root_gen = btrfs_header_generation(parent);
wc->process_func(root, path->nodes[*level], wc,
btrfs_header_generation(path->nodes[*level]));
if (wc->free) {
next = path->nodes[*level];
btrfs_tree_lock(next);
clean_tree_block(trans, root, next);
btrfs_set_lock_blocking(next);
btrfs_wait_tree_block_writeback(next);
btrfs_tree_unlock(next);
WARN_ON(root_owner != BTRFS_TREE_LOG_OBJECTID);
ret = btrfs_free_reserved_extent(root, bytenr, blocksize);
BUG_ON(ret);
}
free_extent_buffer(path->nodes[*level]);
path->nodes[*level] = NULL;
*level += 1;
cond_resched(); cond_resched();
return 0; return 0;
...@@ -1781,7 +1756,7 @@ static noinline int walk_up_log_tree(struct btrfs_trans_handle *trans, ...@@ -1781,7 +1756,7 @@ static noinline int walk_up_log_tree(struct btrfs_trans_handle *trans,
for (i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) { for (i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) {
slot = path->slots[i]; slot = path->slots[i];
if (slot < btrfs_header_nritems(path->nodes[i]) - 1) { if (slot + 1 < btrfs_header_nritems(path->nodes[i])) {
struct extent_buffer *node; struct extent_buffer *node;
node = path->nodes[i]; node = path->nodes[i];
path->slots[i]++; path->slots[i]++;
...@@ -2047,7 +2022,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, ...@@ -2047,7 +2022,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
mutex_unlock(&log_root_tree->log_mutex); mutex_unlock(&log_root_tree->log_mutex);
ret = update_log_root(trans, log); ret = update_log_root(trans, log);
BUG_ON(ret);
mutex_lock(&log_root_tree->log_mutex); mutex_lock(&log_root_tree->log_mutex);
if (atomic_dec_and_test(&log_root_tree->log_writers)) { if (atomic_dec_and_test(&log_root_tree->log_writers)) {
...@@ -2056,6 +2030,15 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, ...@@ -2056,6 +2030,15 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
wake_up(&log_root_tree->log_writer_wait); wake_up(&log_root_tree->log_writer_wait);
} }
if (ret) {
BUG_ON(ret != -ENOSPC);
root->fs_info->last_trans_log_full_commit = trans->transid;
btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
mutex_unlock(&log_root_tree->log_mutex);
ret = -EAGAIN;
goto out;
}
index2 = log_root_tree->log_transid % 2; index2 = log_root_tree->log_transid % 2;
if (atomic_read(&log_root_tree->log_commit[index2])) { if (atomic_read(&log_root_tree->log_commit[index2])) {
btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
...@@ -2129,15 +2112,10 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, ...@@ -2129,15 +2112,10 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
return 0; return 0;
} }
/* static void free_log_tree(struct btrfs_trans_handle *trans,
* free all the extents used by the tree log. This should be called struct btrfs_root *log)
* at commit time of the full transaction
*/
int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root)
{ {
int ret; int ret;
struct btrfs_root *log;
struct key;
u64 start; u64 start;
u64 end; u64 end;
struct walk_control wc = { struct walk_control wc = {
...@@ -2145,10 +2123,6 @@ int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root) ...@@ -2145,10 +2123,6 @@ int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root)
.process_func = process_one_buffer .process_func = process_one_buffer
}; };
if (!root->log_root || root->fs_info->log_root_recovering)
return 0;
log = root->log_root;
ret = walk_log_tree(trans, log, &wc); ret = walk_log_tree(trans, log, &wc);
BUG_ON(ret); BUG_ON(ret);
...@@ -2162,14 +2136,30 @@ int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root) ...@@ -2162,14 +2136,30 @@ int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root)
EXTENT_DIRTY | EXTENT_NEW, GFP_NOFS); EXTENT_DIRTY | EXTENT_NEW, GFP_NOFS);
} }
if (log->log_transid > 0) {
ret = btrfs_del_root(trans, root->fs_info->log_root_tree,
&log->root_key);
BUG_ON(ret);
}
root->log_root = NULL;
free_extent_buffer(log->node); free_extent_buffer(log->node);
kfree(log); kfree(log);
}
/*
* free all the extents used by the tree log. This should be called
* at commit time of the full transaction
*/
int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root)
{
if (root->log_root) {
free_log_tree(trans, root->log_root);
root->log_root = NULL;
}
return 0;
}
int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info)
{
if (fs_info->log_root_tree) {
free_log_tree(trans, fs_info->log_root_tree);
fs_info->log_root_tree = NULL;
}
return 0; return 0;
} }
...@@ -2203,6 +2193,7 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, ...@@ -2203,6 +2193,7 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
struct btrfs_dir_item *di; struct btrfs_dir_item *di;
struct btrfs_path *path; struct btrfs_path *path;
int ret; int ret;
int err = 0;
int bytes_del = 0; int bytes_del = 0;
if (BTRFS_I(dir)->logged_trans < trans->transid) if (BTRFS_I(dir)->logged_trans < trans->transid)
...@@ -2218,7 +2209,11 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, ...@@ -2218,7 +2209,11 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
path = btrfs_alloc_path(); path = btrfs_alloc_path();
di = btrfs_lookup_dir_item(trans, log, path, dir->i_ino, di = btrfs_lookup_dir_item(trans, log, path, dir->i_ino,
name, name_len, -1); name, name_len, -1);
if (di && !IS_ERR(di)) { if (IS_ERR(di)) {
err = PTR_ERR(di);
goto fail;
}
if (di) {
ret = btrfs_delete_one_dir_name(trans, log, path, di); ret = btrfs_delete_one_dir_name(trans, log, path, di);
bytes_del += name_len; bytes_del += name_len;
BUG_ON(ret); BUG_ON(ret);
...@@ -2226,7 +2221,11 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, ...@@ -2226,7 +2221,11 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
btrfs_release_path(log, path); btrfs_release_path(log, path);
di = btrfs_lookup_dir_index_item(trans, log, path, dir->i_ino, di = btrfs_lookup_dir_index_item(trans, log, path, dir->i_ino,
index, name, name_len, -1); index, name, name_len, -1);
if (di && !IS_ERR(di)) { if (IS_ERR(di)) {
err = PTR_ERR(di);
goto fail;
}
if (di) {
ret = btrfs_delete_one_dir_name(trans, log, path, di); ret = btrfs_delete_one_dir_name(trans, log, path, di);
bytes_del += name_len; bytes_del += name_len;
BUG_ON(ret); BUG_ON(ret);
...@@ -2244,6 +2243,10 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, ...@@ -2244,6 +2243,10 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
btrfs_release_path(log, path); btrfs_release_path(log, path);
ret = btrfs_search_slot(trans, log, &key, path, 0, 1); ret = btrfs_search_slot(trans, log, &key, path, 0, 1);
if (ret < 0) {
err = ret;
goto fail;
}
if (ret == 0) { if (ret == 0) {
struct btrfs_inode_item *item; struct btrfs_inode_item *item;
u64 i_size; u64 i_size;
...@@ -2261,9 +2264,13 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, ...@@ -2261,9 +2264,13 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
ret = 0; ret = 0;
btrfs_release_path(log, path); btrfs_release_path(log, path);
} }
fail:
btrfs_free_path(path); btrfs_free_path(path);
mutex_unlock(&BTRFS_I(dir)->log_mutex); mutex_unlock(&BTRFS_I(dir)->log_mutex);
if (ret == -ENOSPC) {
root->fs_info->last_trans_log_full_commit = trans->transid;
ret = 0;
}
btrfs_end_log_trans(root); btrfs_end_log_trans(root);
return 0; return 0;
...@@ -2291,6 +2298,10 @@ int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans, ...@@ -2291,6 +2298,10 @@ int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,
ret = btrfs_del_inode_ref(trans, log, name, name_len, inode->i_ino, ret = btrfs_del_inode_ref(trans, log, name, name_len, inode->i_ino,
dirid, &index); dirid, &index);
mutex_unlock(&BTRFS_I(inode)->log_mutex); mutex_unlock(&BTRFS_I(inode)->log_mutex);
if (ret == -ENOSPC) {
root->fs_info->last_trans_log_full_commit = trans->transid;
ret = 0;
}
btrfs_end_log_trans(root); btrfs_end_log_trans(root);
return ret; return ret;
...@@ -2318,7 +2329,8 @@ static noinline int insert_dir_log_key(struct btrfs_trans_handle *trans, ...@@ -2318,7 +2329,8 @@ static noinline int insert_dir_log_key(struct btrfs_trans_handle *trans,
else else
key.type = BTRFS_DIR_LOG_INDEX_KEY; key.type = BTRFS_DIR_LOG_INDEX_KEY;
ret = btrfs_insert_empty_item(trans, log, path, &key, sizeof(*item)); ret = btrfs_insert_empty_item(trans, log, path, &key, sizeof(*item));
BUG_ON(ret); if (ret)
return ret;
item = btrfs_item_ptr(path->nodes[0], path->slots[0], item = btrfs_item_ptr(path->nodes[0], path->slots[0],
struct btrfs_dir_log_item); struct btrfs_dir_log_item);
...@@ -2343,6 +2355,7 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans, ...@@ -2343,6 +2355,7 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
struct btrfs_key max_key; struct btrfs_key max_key;
struct btrfs_root *log = root->log_root; struct btrfs_root *log = root->log_root;
struct extent_buffer *src; struct extent_buffer *src;
int err = 0;
int ret; int ret;
int i; int i;
int nritems; int nritems;
...@@ -2405,6 +2418,10 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans, ...@@ -2405,6 +2418,10 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
ret = overwrite_item(trans, log, dst_path, ret = overwrite_item(trans, log, dst_path,
path->nodes[0], path->slots[0], path->nodes[0], path->slots[0],
&tmp); &tmp);
if (ret) {
err = ret;
goto done;
}
} }
} }
btrfs_release_path(root, path); btrfs_release_path(root, path);
...@@ -2432,7 +2449,10 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans, ...@@ -2432,7 +2449,10 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
goto done; goto done;
ret = overwrite_item(trans, log, dst_path, src, i, ret = overwrite_item(trans, log, dst_path, src, i,
&min_key); &min_key);
BUG_ON(ret); if (ret) {
err = ret;
goto done;
}
} }
path->slots[0] = nritems; path->slots[0] = nritems;
...@@ -2454,22 +2474,30 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans, ...@@ -2454,22 +2474,30 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
ret = overwrite_item(trans, log, dst_path, ret = overwrite_item(trans, log, dst_path,
path->nodes[0], path->slots[0], path->nodes[0], path->slots[0],
&tmp); &tmp);
if (ret)
BUG_ON(ret); err = ret;
else
last_offset = tmp.offset; last_offset = tmp.offset;
goto done; goto done;
} }
} }
done: done:
*last_offset_ret = last_offset;
btrfs_release_path(root, path); btrfs_release_path(root, path);
btrfs_release_path(log, dst_path); btrfs_release_path(log, dst_path);
/* insert the log range keys to indicate where the log is valid */ if (err == 0) {
ret = insert_dir_log_key(trans, log, path, key_type, inode->i_ino, *last_offset_ret = last_offset;
first_offset, last_offset); /*
BUG_ON(ret); * insert the log range keys to indicate where the log
return 0; * is valid
*/
ret = insert_dir_log_key(trans, log, path, key_type,
inode->i_ino, first_offset,
last_offset);
if (ret)
err = ret;
}
return err;
} }
/* /*
...@@ -2501,7 +2529,8 @@ static noinline int log_directory_changes(struct btrfs_trans_handle *trans, ...@@ -2501,7 +2529,8 @@ static noinline int log_directory_changes(struct btrfs_trans_handle *trans,
ret = log_dir_items(trans, root, inode, path, ret = log_dir_items(trans, root, inode, path,
dst_path, key_type, min_key, dst_path, key_type, min_key,
&max_key); &max_key);
BUG_ON(ret); if (ret)
return ret;
if (max_key == (u64)-1) if (max_key == (u64)-1)
break; break;
min_key = max_key + 1; min_key = max_key + 1;
...@@ -2535,8 +2564,8 @@ static int drop_objectid_items(struct btrfs_trans_handle *trans, ...@@ -2535,8 +2564,8 @@ static int drop_objectid_items(struct btrfs_trans_handle *trans,
while (1) { while (1) {
ret = btrfs_search_slot(trans, log, &key, path, -1, 1); ret = btrfs_search_slot(trans, log, &key, path, -1, 1);
BUG_ON(ret == 0);
if (ret != 1) if (ret < 0)
break; break;
if (path->slots[0] == 0) if (path->slots[0] == 0)
...@@ -2554,7 +2583,7 @@ static int drop_objectid_items(struct btrfs_trans_handle *trans, ...@@ -2554,7 +2583,7 @@ static int drop_objectid_items(struct btrfs_trans_handle *trans,
btrfs_release_path(log, path); btrfs_release_path(log, path);
} }
btrfs_release_path(log, path); btrfs_release_path(log, path);
return 0; return ret;
} }
static noinline int copy_items(struct btrfs_trans_handle *trans, static noinline int copy_items(struct btrfs_trans_handle *trans,
...@@ -2587,7 +2616,10 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, ...@@ -2587,7 +2616,10 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
} }
ret = btrfs_insert_empty_items(trans, log, dst_path, ret = btrfs_insert_empty_items(trans, log, dst_path,
ins_keys, ins_sizes, nr); ins_keys, ins_sizes, nr);
BUG_ON(ret); if (ret) {
kfree(ins_data);
return ret;
}
for (i = 0; i < nr; i++, dst_path->slots[0]++) { for (i = 0; i < nr; i++, dst_path->slots[0]++) {
dst_offset = btrfs_item_ptr_offset(dst_path->nodes[0], dst_offset = btrfs_item_ptr_offset(dst_path->nodes[0],
...@@ -2660,16 +2692,17 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, ...@@ -2660,16 +2692,17 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
* we have to do this after the loop above to avoid changing the * we have to do this after the loop above to avoid changing the
* log tree while trying to change the log tree. * log tree while trying to change the log tree.
*/ */
ret = 0;
while (!list_empty(&ordered_sums)) { while (!list_empty(&ordered_sums)) {
struct btrfs_ordered_sum *sums = list_entry(ordered_sums.next, struct btrfs_ordered_sum *sums = list_entry(ordered_sums.next,
struct btrfs_ordered_sum, struct btrfs_ordered_sum,
list); list);
if (!ret)
ret = btrfs_csum_file_blocks(trans, log, sums); ret = btrfs_csum_file_blocks(trans, log, sums);
BUG_ON(ret);
list_del(&sums->list); list_del(&sums->list);
kfree(sums); kfree(sums);
} }
return 0; return ret;
} }
/* log a single inode in the tree log. /* log a single inode in the tree log.
...@@ -2697,6 +2730,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, ...@@ -2697,6 +2730,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
struct btrfs_root *log = root->log_root; struct btrfs_root *log = root->log_root;
struct extent_buffer *src = NULL; struct extent_buffer *src = NULL;
u32 size; u32 size;
int err = 0;
int ret; int ret;
int nritems; int nritems;
int ins_start_slot = 0; int ins_start_slot = 0;
...@@ -2739,7 +2773,10 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, ...@@ -2739,7 +2773,10 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
} else { } else {
ret = btrfs_truncate_inode_items(trans, log, inode, 0, 0); ret = btrfs_truncate_inode_items(trans, log, inode, 0, 0);
} }
BUG_ON(ret); if (ret) {
err = ret;
goto out_unlock;
}
path->keep_locks = 1; path->keep_locks = 1;
while (1) { while (1) {
...@@ -2768,7 +2805,10 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, ...@@ -2768,7 +2805,10 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
ret = copy_items(trans, log, dst_path, src, ins_start_slot, ret = copy_items(trans, log, dst_path, src, ins_start_slot,
ins_nr, inode_only); ins_nr, inode_only);
BUG_ON(ret); if (ret) {
err = ret;
goto out_unlock;
}
ins_nr = 1; ins_nr = 1;
ins_start_slot = path->slots[0]; ins_start_slot = path->slots[0];
next_slot: next_slot:
...@@ -2784,7 +2824,10 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, ...@@ -2784,7 +2824,10 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
ret = copy_items(trans, log, dst_path, src, ret = copy_items(trans, log, dst_path, src,
ins_start_slot, ins_start_slot,
ins_nr, inode_only); ins_nr, inode_only);
BUG_ON(ret); if (ret) {
err = ret;
goto out_unlock;
}
ins_nr = 0; ins_nr = 0;
} }
btrfs_release_path(root, path); btrfs_release_path(root, path);
...@@ -2802,7 +2845,10 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, ...@@ -2802,7 +2845,10 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
ret = copy_items(trans, log, dst_path, src, ret = copy_items(trans, log, dst_path, src,
ins_start_slot, ins_start_slot,
ins_nr, inode_only); ins_nr, inode_only);
BUG_ON(ret); if (ret) {
err = ret;
goto out_unlock;
}
ins_nr = 0; ins_nr = 0;
} }
WARN_ON(ins_nr); WARN_ON(ins_nr);
...@@ -2810,14 +2856,18 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, ...@@ -2810,14 +2856,18 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
btrfs_release_path(root, path); btrfs_release_path(root, path);
btrfs_release_path(log, dst_path); btrfs_release_path(log, dst_path);
ret = log_directory_changes(trans, root, inode, path, dst_path); ret = log_directory_changes(trans, root, inode, path, dst_path);
BUG_ON(ret); if (ret) {
err = ret;
goto out_unlock;
}
} }
BTRFS_I(inode)->logged_trans = trans->transid; BTRFS_I(inode)->logged_trans = trans->transid;
out_unlock:
mutex_unlock(&BTRFS_I(inode)->log_mutex); mutex_unlock(&BTRFS_I(inode)->log_mutex);
btrfs_free_path(path); btrfs_free_path(path);
btrfs_free_path(dst_path); btrfs_free_path(dst_path);
return 0; return err;
} }
/* /*
...@@ -2942,10 +2992,13 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, ...@@ -2942,10 +2992,13 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
goto end_no_trans; goto end_no_trans;
} }
start_log_trans(trans, root); ret = start_log_trans(trans, root);
if (ret)
goto end_trans;
ret = btrfs_log_inode(trans, root, inode, inode_only); ret = btrfs_log_inode(trans, root, inode, inode_only);
BUG_ON(ret); if (ret)
goto end_trans;
/* /*
* for regular files, if its inode is already on disk, we don't * for regular files, if its inode is already on disk, we don't
...@@ -2955,8 +3008,10 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, ...@@ -2955,8 +3008,10 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
*/ */
if (S_ISREG(inode->i_mode) && if (S_ISREG(inode->i_mode) &&
BTRFS_I(inode)->generation <= last_committed && BTRFS_I(inode)->generation <= last_committed &&
BTRFS_I(inode)->last_unlink_trans <= last_committed) BTRFS_I(inode)->last_unlink_trans <= last_committed) {
goto no_parent; ret = 0;
goto end_trans;
}
inode_only = LOG_INODE_EXISTS; inode_only = LOG_INODE_EXISTS;
while (1) { while (1) {
...@@ -2970,15 +3025,21 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, ...@@ -2970,15 +3025,21 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
if (BTRFS_I(inode)->generation > if (BTRFS_I(inode)->generation >
root->fs_info->last_trans_committed) { root->fs_info->last_trans_committed) {
ret = btrfs_log_inode(trans, root, inode, inode_only); ret = btrfs_log_inode(trans, root, inode, inode_only);
BUG_ON(ret); if (ret)
goto end_trans;
} }
if (IS_ROOT(parent)) if (IS_ROOT(parent))
break; break;
parent = parent->d_parent; parent = parent->d_parent;
} }
no_parent:
ret = 0; ret = 0;
end_trans:
if (ret < 0) {
BUG_ON(ret != -ENOSPC);
root->fs_info->last_trans_log_full_commit = trans->transid;
ret = 1;
}
btrfs_end_log_trans(root); btrfs_end_log_trans(root);
end_no_trans: end_no_trans:
return ret; return ret;
...@@ -3020,7 +3081,7 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree) ...@@ -3020,7 +3081,7 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
path = btrfs_alloc_path(); path = btrfs_alloc_path();
BUG_ON(!path); BUG_ON(!path);
trans = btrfs_start_transaction(fs_info->tree_root, 1); trans = btrfs_start_transaction(fs_info->tree_root, 0);
wc.trans = trans; wc.trans = trans;
wc.pin = 1; wc.pin = 1;
......
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
int btrfs_sync_log(struct btrfs_trans_handle *trans, int btrfs_sync_log(struct btrfs_trans_handle *trans,
struct btrfs_root *root); struct btrfs_root *root);
int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root); int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root);
int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info);
int btrfs_recover_log_trees(struct btrfs_root *tree_root); int btrfs_recover_log_trees(struct btrfs_root *tree_root);
int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans, int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct dentry *dentry); struct btrfs_root *root, struct dentry *dentry);
......
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