diff options
Diffstat (limited to 'fs/btrfs/tree-log.c')
| -rw-r--r-- | fs/btrfs/tree-log.c | 96 | 
1 files changed, 70 insertions, 26 deletions
| diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 966cc74f5d6..d017283ae6f 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -212,14 +212,13 @@ int btrfs_pin_log_trans(struct btrfs_root *root)   * indicate we're done making changes to the log tree   * and wake up anyone waiting to do a sync   */ -int btrfs_end_log_trans(struct btrfs_root *root) +void btrfs_end_log_trans(struct btrfs_root *root)  {  	if (atomic_dec_and_test(&root->log_writers)) {  		smp_mb();  		if (waitqueue_active(&root->log_writer_wait))  			wake_up(&root->log_writer_wait);  	} -	return 0;  } @@ -378,12 +377,11 @@ insert:  		u32 found_size;  		found_size = btrfs_item_size_nr(path->nodes[0],  						path->slots[0]); -		if (found_size > item_size) { +		if (found_size > item_size)  			btrfs_truncate_item(trans, root, path, item_size, 1); -		} else if (found_size < item_size) { -			ret = btrfs_extend_item(trans, root, path, -						item_size - found_size); -		} +		else if (found_size < item_size) +			btrfs_extend_item(trans, root, path, +					  item_size - found_size);  	} else if (ret) {  		return ret;  	} @@ -1763,7 +1761,7 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,  					BTRFS_TREE_LOG_OBJECTID);  				ret = btrfs_free_and_pin_reserved_extent(root,  							 bytenr, blocksize); -				BUG_ON(ret); +				BUG_ON(ret); /* -ENOMEM or logic errors */  			}  			free_extent_buffer(next);  			continue; @@ -1871,20 +1869,26 @@ static int walk_log_tree(struct btrfs_trans_handle *trans,  		wret = walk_down_log_tree(trans, log, path, &level, wc);  		if (wret > 0)  			break; -		if (wret < 0) +		if (wret < 0) {  			ret = wret; +			goto out; +		}  		wret = walk_up_log_tree(trans, log, path, &level, wc);  		if (wret > 0)  			break; -		if (wret < 0) +		if (wret < 0) {  			ret = wret; +			goto out; +		}  	}  	/* was the root node processed? if not, catch it here */  	if (path->nodes[orig_level]) { -		wc->process_func(log, path->nodes[orig_level], wc, +		ret = wc->process_func(log, path->nodes[orig_level], wc,  			 btrfs_header_generation(path->nodes[orig_level])); +		if (ret) +			goto out;  		if (wc->free) {  			struct extent_buffer *next; @@ -1900,10 +1904,11 @@ static int walk_log_tree(struct btrfs_trans_handle *trans,  				BTRFS_TREE_LOG_OBJECTID);  			ret = btrfs_free_and_pin_reserved_extent(log, next->start,  							 next->len); -			BUG_ON(ret); +			BUG_ON(ret); /* -ENOMEM or logic errors */  		}  	} +out:  	for (i = 0; i <= orig_level; i++) {  		if (path->nodes[i]) {  			free_extent_buffer(path->nodes[i]); @@ -1963,8 +1968,8 @@ static int wait_log_commit(struct btrfs_trans_handle *trans,  	return 0;  } -static int wait_for_writer(struct btrfs_trans_handle *trans, -			   struct btrfs_root *root) +static void wait_for_writer(struct btrfs_trans_handle *trans, +			    struct btrfs_root *root)  {  	DEFINE_WAIT(wait);  	while (root->fs_info->last_trans_log_full_commit != @@ -1978,7 +1983,6 @@ static int wait_for_writer(struct btrfs_trans_handle *trans,  		mutex_lock(&root->log_mutex);  		finish_wait(&root->log_writer_wait, &wait);  	} -	return 0;  }  /* @@ -2046,7 +2050,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,  	 * wait for them until later.  	 */  	ret = btrfs_write_marked_extents(log, &log->dirty_log_pages, mark); -	BUG_ON(ret); +	if (ret) { +		btrfs_abort_transaction(trans, root, ret); +		mutex_unlock(&root->log_mutex); +		goto out; +	}  	btrfs_set_root_node(&log->root_item, log->node); @@ -2077,7 +2085,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,  	}  	if (ret) { -		BUG_ON(ret != -ENOSPC); +		if (ret != -ENOSPC) { +			btrfs_abort_transaction(trans, root, ret); +			mutex_unlock(&log_root_tree->log_mutex); +			goto out; +		}  		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); @@ -2117,7 +2129,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,  	ret = btrfs_write_and_wait_marked_extents(log_root_tree,  				&log_root_tree->dirty_log_pages,  				EXTENT_DIRTY | EXTENT_NEW); -	BUG_ON(ret); +	if (ret) { +		btrfs_abort_transaction(trans, root, ret); +		mutex_unlock(&log_root_tree->log_mutex); +		goto out_wake_log_root; +	}  	btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);  	btrfs_set_super_log_root(root->fs_info->super_for_commit, @@ -2326,7 +2342,9 @@ out_unlock:  	if (ret == -ENOSPC) {  		root->fs_info->last_trans_log_full_commit = trans->transid;  		ret = 0; -	} +	} else if (ret < 0) +		btrfs_abort_transaction(trans, root, ret); +  	btrfs_end_log_trans(root);  	return err; @@ -2357,7 +2375,8 @@ int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,  	if (ret == -ENOSPC) {  		root->fs_info->last_trans_log_full_commit = trans->transid;  		ret = 0; -	} +	} else if (ret < 0 && ret != -ENOENT) +		btrfs_abort_transaction(trans, root, ret);  	btrfs_end_log_trans(root);  	return ret; @@ -3169,13 +3188,20 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)  	fs_info->log_root_recovering = 1;  	trans = btrfs_start_transaction(fs_info->tree_root, 0); -	BUG_ON(IS_ERR(trans)); +	if (IS_ERR(trans)) { +		ret = PTR_ERR(trans); +		goto error; +	}  	wc.trans = trans;  	wc.pin = 1;  	ret = walk_log_tree(trans, log_root_tree, &wc); -	BUG_ON(ret); +	if (ret) { +		btrfs_error(fs_info, ret, "Failed to pin buffers while " +			    "recovering log root tree."); +		goto error; +	}  again:  	key.objectid = BTRFS_TREE_LOG_OBJECTID; @@ -3184,8 +3210,12 @@ again:  	while (1) {  		ret = btrfs_search_slot(NULL, log_root_tree, &key, path, 0, 0); -		if (ret < 0) -			break; + +		if (ret < 0) { +			btrfs_error(fs_info, ret, +				    "Couldn't find tree log root."); +			goto error; +		}  		if (ret > 0) {  			if (path->slots[0] == 0)  				break; @@ -3199,14 +3229,24 @@ again:  		log = btrfs_read_fs_root_no_radix(log_root_tree,  						  &found_key); -		BUG_ON(IS_ERR(log)); +		if (IS_ERR(log)) { +			ret = PTR_ERR(log); +			btrfs_error(fs_info, ret, +				    "Couldn't read tree log root."); +			goto error; +		}  		tmp_key.objectid = found_key.offset;  		tmp_key.type = BTRFS_ROOT_ITEM_KEY;  		tmp_key.offset = (u64)-1;  		wc.replay_dest = btrfs_read_fs_root_no_name(fs_info, &tmp_key); -		BUG_ON(IS_ERR_OR_NULL(wc.replay_dest)); +		if (IS_ERR(wc.replay_dest)) { +			ret = PTR_ERR(wc.replay_dest); +			btrfs_error(fs_info, ret, "Couldn't read target root " +				    "for tree log recovery."); +			goto error; +		}  		wc.replay_dest->log_root = log;  		btrfs_record_root_in_trans(trans, wc.replay_dest); @@ -3254,6 +3294,10 @@ again:  	kfree(log_root_tree);  	return 0; + +error: +	btrfs_free_path(path); +	return ret;  }  /* | 
