aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/tree-log.c
diff options
context:
space:
mode:
authorJeff Mahoney <jeffm@suse.com>2012-03-12 11:03:00 -0400
committerDavid Sterba <dsterba@suse.cz>2012-03-22 06:52:54 -0400
commit79787eaab46121d4713ed03c8fc63b9ec3eaec76 (patch)
treeee6b17d0811ee54ab74a03aa4e0bb92769d2f12a /fs/btrfs/tree-log.c
parent49b25e0540904be0bf558b84475c69d72e4de66e (diff)
btrfs: replace many BUG_ONs with proper error handling
btrfs currently handles most errors with BUG_ON. This patch is a work-in- progress but aims to handle most errors other than internal logic errors and ENOMEM more gracefully. This iteration prevents most crashes but can run into lockups with the page lock on occasion when the timing "works out." Signed-off-by: Jeff Mahoney <jeffm@suse.com>
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r--fs/btrfs/tree-log.c79
1 files changed, 63 insertions, 16 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 37b52b8c6727..d017283ae6f5 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -1761,7 +1761,7 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
1761 BTRFS_TREE_LOG_OBJECTID); 1761 BTRFS_TREE_LOG_OBJECTID);
1762 ret = btrfs_free_and_pin_reserved_extent(root, 1762 ret = btrfs_free_and_pin_reserved_extent(root,
1763 bytenr, blocksize); 1763 bytenr, blocksize);
1764 BUG_ON(ret); 1764 BUG_ON(ret); /* -ENOMEM or logic errors */
1765 } 1765 }
1766 free_extent_buffer(next); 1766 free_extent_buffer(next);
1767 continue; 1767 continue;
@@ -1869,20 +1869,26 @@ static int walk_log_tree(struct btrfs_trans_handle *trans,
1869 wret = walk_down_log_tree(trans, log, path, &level, wc); 1869 wret = walk_down_log_tree(trans, log, path, &level, wc);
1870 if (wret > 0) 1870 if (wret > 0)
1871 break; 1871 break;
1872 if (wret < 0) 1872 if (wret < 0) {
1873 ret = wret; 1873 ret = wret;
1874 goto out;
1875 }
1874 1876
1875 wret = walk_up_log_tree(trans, log, path, &level, wc); 1877 wret = walk_up_log_tree(trans, log, path, &level, wc);
1876 if (wret > 0) 1878 if (wret > 0)
1877 break; 1879 break;
1878 if (wret < 0) 1880 if (wret < 0) {
1879 ret = wret; 1881 ret = wret;
1882 goto out;
1883 }
1880 } 1884 }
1881 1885
1882 /* was the root node processed? if not, catch it here */ 1886 /* was the root node processed? if not, catch it here */
1883 if (path->nodes[orig_level]) { 1887 if (path->nodes[orig_level]) {
1884 wc->process_func(log, path->nodes[orig_level], wc, 1888 ret = wc->process_func(log, path->nodes[orig_level], wc,
1885 btrfs_header_generation(path->nodes[orig_level])); 1889 btrfs_header_generation(path->nodes[orig_level]));
1890 if (ret)
1891 goto out;
1886 if (wc->free) { 1892 if (wc->free) {
1887 struct extent_buffer *next; 1893 struct extent_buffer *next;
1888 1894
@@ -1898,10 +1904,11 @@ static int walk_log_tree(struct btrfs_trans_handle *trans,
1898 BTRFS_TREE_LOG_OBJECTID); 1904 BTRFS_TREE_LOG_OBJECTID);
1899 ret = btrfs_free_and_pin_reserved_extent(log, next->start, 1905 ret = btrfs_free_and_pin_reserved_extent(log, next->start,
1900 next->len); 1906 next->len);
1901 BUG_ON(ret); 1907 BUG_ON(ret); /* -ENOMEM or logic errors */
1902 } 1908 }
1903 } 1909 }
1904 1910
1911out:
1905 for (i = 0; i <= orig_level; i++) { 1912 for (i = 0; i <= orig_level; i++) {
1906 if (path->nodes[i]) { 1913 if (path->nodes[i]) {
1907 free_extent_buffer(path->nodes[i]); 1914 free_extent_buffer(path->nodes[i]);
@@ -2043,7 +2050,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
2043 * wait for them until later. 2050 * wait for them until later.
2044 */ 2051 */
2045 ret = btrfs_write_marked_extents(log, &log->dirty_log_pages, mark); 2052 ret = btrfs_write_marked_extents(log, &log->dirty_log_pages, mark);
2046 BUG_ON(ret); 2053 if (ret) {
2054 btrfs_abort_transaction(trans, root, ret);
2055 mutex_unlock(&root->log_mutex);
2056 goto out;
2057 }
2047 2058
2048 btrfs_set_root_node(&log->root_item, log->node); 2059 btrfs_set_root_node(&log->root_item, log->node);
2049 2060
@@ -2074,7 +2085,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
2074 } 2085 }
2075 2086
2076 if (ret) { 2087 if (ret) {
2077 BUG_ON(ret != -ENOSPC); 2088 if (ret != -ENOSPC) {
2089 btrfs_abort_transaction(trans, root, ret);
2090 mutex_unlock(&log_root_tree->log_mutex);
2091 goto out;
2092 }
2078 root->fs_info->last_trans_log_full_commit = trans->transid; 2093 root->fs_info->last_trans_log_full_commit = trans->transid;
2079 btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); 2094 btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
2080 mutex_unlock(&log_root_tree->log_mutex); 2095 mutex_unlock(&log_root_tree->log_mutex);
@@ -2114,7 +2129,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
2114 ret = btrfs_write_and_wait_marked_extents(log_root_tree, 2129 ret = btrfs_write_and_wait_marked_extents(log_root_tree,
2115 &log_root_tree->dirty_log_pages, 2130 &log_root_tree->dirty_log_pages,
2116 EXTENT_DIRTY | EXTENT_NEW); 2131 EXTENT_DIRTY | EXTENT_NEW);
2117 BUG_ON(ret); 2132 if (ret) {
2133 btrfs_abort_transaction(trans, root, ret);
2134 mutex_unlock(&log_root_tree->log_mutex);
2135 goto out_wake_log_root;
2136 }
2118 btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); 2137 btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
2119 2138
2120 btrfs_set_super_log_root(root->fs_info->super_for_commit, 2139 btrfs_set_super_log_root(root->fs_info->super_for_commit,
@@ -2323,7 +2342,9 @@ out_unlock:
2323 if (ret == -ENOSPC) { 2342 if (ret == -ENOSPC) {
2324 root->fs_info->last_trans_log_full_commit = trans->transid; 2343 root->fs_info->last_trans_log_full_commit = trans->transid;
2325 ret = 0; 2344 ret = 0;
2326 } 2345 } else if (ret < 0)
2346 btrfs_abort_transaction(trans, root, ret);
2347
2327 btrfs_end_log_trans(root); 2348 btrfs_end_log_trans(root);
2328 2349
2329 return err; 2350 return err;
@@ -2354,7 +2375,8 @@ int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,
2354 if (ret == -ENOSPC) { 2375 if (ret == -ENOSPC) {
2355 root->fs_info->last_trans_log_full_commit = trans->transid; 2376 root->fs_info->last_trans_log_full_commit = trans->transid;
2356 ret = 0; 2377 ret = 0;
2357 } 2378 } else if (ret < 0 && ret != -ENOENT)
2379 btrfs_abort_transaction(trans, root, ret);
2358 btrfs_end_log_trans(root); 2380 btrfs_end_log_trans(root);
2359 2381
2360 return ret; 2382 return ret;
@@ -3166,13 +3188,20 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
3166 fs_info->log_root_recovering = 1; 3188 fs_info->log_root_recovering = 1;
3167 3189
3168 trans = btrfs_start_transaction(fs_info->tree_root, 0); 3190 trans = btrfs_start_transaction(fs_info->tree_root, 0);
3169 BUG_ON(IS_ERR(trans)); 3191 if (IS_ERR(trans)) {
3192 ret = PTR_ERR(trans);
3193 goto error;
3194 }
3170 3195
3171 wc.trans = trans; 3196 wc.trans = trans;
3172 wc.pin = 1; 3197 wc.pin = 1;
3173 3198
3174 ret = walk_log_tree(trans, log_root_tree, &wc); 3199 ret = walk_log_tree(trans, log_root_tree, &wc);
3175 BUG_ON(ret); 3200 if (ret) {
3201 btrfs_error(fs_info, ret, "Failed to pin buffers while "
3202 "recovering log root tree.");
3203 goto error;
3204 }
3176 3205
3177again: 3206again:
3178 key.objectid = BTRFS_TREE_LOG_OBJECTID; 3207 key.objectid = BTRFS_TREE_LOG_OBJECTID;
@@ -3181,8 +3210,12 @@ again:
3181 3210
3182 while (1) { 3211 while (1) {
3183 ret = btrfs_search_slot(NULL, log_root_tree, &key, path, 0, 0); 3212 ret = btrfs_search_slot(NULL, log_root_tree, &key, path, 0, 0);
3184 if (ret < 0) 3213
3185 break; 3214 if (ret < 0) {
3215 btrfs_error(fs_info, ret,
3216 "Couldn't find tree log root.");
3217 goto error;
3218 }
3186 if (ret > 0) { 3219 if (ret > 0) {
3187 if (path->slots[0] == 0) 3220 if (path->slots[0] == 0)
3188 break; 3221 break;
@@ -3196,14 +3229,24 @@ again:
3196 3229
3197 log = btrfs_read_fs_root_no_radix(log_root_tree, 3230 log = btrfs_read_fs_root_no_radix(log_root_tree,
3198 &found_key); 3231 &found_key);
3199 BUG_ON(IS_ERR(log)); 3232 if (IS_ERR(log)) {
3233 ret = PTR_ERR(log);
3234 btrfs_error(fs_info, ret,
3235 "Couldn't read tree log root.");
3236 goto error;
3237 }
3200 3238
3201 tmp_key.objectid = found_key.offset; 3239 tmp_key.objectid = found_key.offset;
3202 tmp_key.type = BTRFS_ROOT_ITEM_KEY; 3240 tmp_key.type = BTRFS_ROOT_ITEM_KEY;
3203 tmp_key.offset = (u64)-1; 3241 tmp_key.offset = (u64)-1;
3204 3242
3205 wc.replay_dest = btrfs_read_fs_root_no_name(fs_info, &tmp_key); 3243 wc.replay_dest = btrfs_read_fs_root_no_name(fs_info, &tmp_key);
3206 BUG_ON(IS_ERR_OR_NULL(wc.replay_dest)); 3244 if (IS_ERR(wc.replay_dest)) {
3245 ret = PTR_ERR(wc.replay_dest);
3246 btrfs_error(fs_info, ret, "Couldn't read target root "
3247 "for tree log recovery.");
3248 goto error;
3249 }
3207 3250
3208 wc.replay_dest->log_root = log; 3251 wc.replay_dest->log_root = log;
3209 btrfs_record_root_in_trans(trans, wc.replay_dest); 3252 btrfs_record_root_in_trans(trans, wc.replay_dest);
@@ -3251,6 +3294,10 @@ again:
3251 3294
3252 kfree(log_root_tree); 3295 kfree(log_root_tree);
3253 return 0; 3296 return 0;
3297
3298error:
3299 btrfs_free_path(path);
3300 return ret;
3254} 3301}
3255 3302
3256/* 3303/*