[Ocfs2-devel] [patch 15/25] ocfs2: extend transaction for ocfs2_remove_rightmost_path() and ocfs2_update_edge_lengths() before to avoid inconsistency between inode and et

Joseph Qi joseph.qi at huawei.com
Wed Mar 23 17:18:38 PDT 2016


On 2016/3/24 4:12, akpm at linux-foundation.org wrote:
> From: Xue jiufei <xuejiufei at huawei.com>
> Subject: ocfs2: extend transaction for ocfs2_remove_rightmost_path() and ocfs2_update_edge_lengths() before to avoid inconsistency between inode and et
> 
> I found that jbd2_journal_restart() is called in some places without
> keeping things consistently before.  However, jbd2_journal_restart() may
> commit the handle's transaction and restart another one.  If the first
> transaction is committed successfully while another not, it may cause
> filesystem inconsistency or read only.  This is an effort to fix this kind
> of problems.
> 
> 
> This patch (of 3):
> 
> The following functions will be called while truncating an extent:
> ocfs2_remove_btree_range
>   -> ocfs2_start_trans
>   -> ocfs2_remove_extent
>      -> ocfs2_truncate_rec
>        -> ocfs2_extend_rotate_transaction
>          -> jbd2_journal_restart if jbd2_journal_extend fail
>        -> ocfs2_rotate_tree_left
>          -> ocfs2_remove_rightmost_path
>              -> ocfs2_extend_rotate_transaction
>                -> ocfs2_unlink_subtree
>                 -> ocfs2_update_edge_lengths
>                   -> ocfs2_extend_trans
>                     -> jbd2_journal_restart if jbd2_journal_extend fail
>   -> ocfs2_et_update_clusters
>   -> ocfs2_commit_trans
> 
> jbd2_journal_restart() may be called and it may happened that the buffers
> dirtied in ocfs2_truncate_rec() are committed while buffers dirtied in
> ocfs2_et_update_clusters() are not, the total clusters on extent tree and
> i_clusters in ocfs2_dinode is inconsistency.  So the clusters got from
> ocfs2_dinode is incorrect, and it also cause read-only problem when call
> ocfs2_commit_truncate() with the error message: "Inode %llu has empty
> extent block at %llu".
> 
> We should extend enough credits for function ocfs2_remove_rightmost_path
> and ocfs2_update_edge_lengths to avoid this inconsistency.
> 
> Signed-off-by: joyce.xue <xuejiufei at huawei.com>
Acked-by: Joseph Qi <joseph.qi at huawei.com>

> Cc: Mark Fasheh <mfasheh at suse.com>
> Cc: Joel Becker <jlbec at evilplan.org>
> Signed-off-by: Andrew Morton <akpm at linux-foundation.org>
> ---
> 
>  fs/ocfs2/alloc.c |   82 +++++++++++++++++++++++++++++----------------
>  1 file changed, 54 insertions(+), 28 deletions(-)
> 
> diff -puN fs/ocfs2/alloc.c~ocfs2-extend-transaction-for-ocfs2_remove_rightmost_path-and-ocfs2_update_edge_lengths-before-to-avoid-inconsistency-between-inode-and-et fs/ocfs2/alloc.c
> --- a/fs/ocfs2/alloc.c~ocfs2-extend-transaction-for-ocfs2_remove_rightmost_path-and-ocfs2_update_edge_lengths-before-to-avoid-inconsistency-between-inode-and-et
> +++ a/fs/ocfs2/alloc.c
> @@ -2516,21 +2516,6 @@ static int ocfs2_update_edge_lengths(han
>  	struct ocfs2_extent_block *eb;
>  	u32 range;
>  
> -	/*
> -	 * In normal tree rotation process, we will never touch the
> -	 * tree branch above subtree_index and ocfs2_extend_rotate_transaction
> -	 * doesn't reserve the credits for them either.
> -	 *
> -	 * But we do have a special case here which will update the rightmost
> -	 * records for all the bh in the path.
> -	 * So we have to allocate extra credits and access them.
> -	 */
> -	ret = ocfs2_extend_trans(handle, subtree_index);
> -	if (ret) {
> -		mlog_errno(ret);
> -		goto out;
> -	}
> -
>  	ret = ocfs2_journal_access_path(et->et_ci, handle, path);
>  	if (ret) {
>  		mlog_errno(ret);
> @@ -2956,7 +2941,7 @@ static int __ocfs2_rotate_tree_left(hand
>  		     right_path->p_node[subtree_root].bh->b_blocknr,
>  		     right_path->p_tree_depth);
>  
> -		ret = ocfs2_extend_rotate_transaction(handle, subtree_root,
> +		ret = ocfs2_extend_rotate_transaction(handle, 0,
>  						      orig_credits, left_path);
>  		if (ret) {
>  			mlog_errno(ret);
> @@ -3029,21 +3014,9 @@ static int ocfs2_remove_rightmost_path(h
>  	struct ocfs2_extent_block *eb;
>  	struct ocfs2_extent_list *el;
>  
> -
>  	ret = ocfs2_et_sanity_check(et);
>  	if (ret)
>  		goto out;
> -	/*
> -	 * There's two ways we handle this depending on
> -	 * whether path is the only existing one.
> -	 */
> -	ret = ocfs2_extend_rotate_transaction(handle, 0,
> -					      handle->h_buffer_credits,
> -					      path);
> -	if (ret) {
> -		mlog_errno(ret);
> -		goto out;
> -	}
>  
>  	ret = ocfs2_journal_access_path(et->et_ci, handle, path);
>  	if (ret) {
> @@ -3641,6 +3614,14 @@ static int ocfs2_merge_rec_left(struct o
>  		 */
>  		if (le16_to_cpu(right_rec->e_leaf_clusters) == 0 &&
>  		    le16_to_cpu(el->l_next_free_rec) == 1) {
> +			/* extend credit for ocfs2_remove_rightmost_path */
> +			ret = ocfs2_extend_rotate_transaction(handle, 0,
> +					handle->h_buffer_credits,
> +					right_path);
> +			if (ret) {
> +				mlog_errno(ret);
> +				goto out;
> +			}
>  
>  			ret = ocfs2_remove_rightmost_path(handle, et,
>  							  right_path,
> @@ -3679,6 +3660,14 @@ static int ocfs2_try_to_merge_extent(han
>  	BUG_ON(ctxt->c_contig_type == CONTIG_NONE);
>  
>  	if (ctxt->c_split_covers_rec && ctxt->c_has_empty_extent) {
> +		/* extend credit for ocfs2_remove_rightmost_path */
> +		ret = ocfs2_extend_rotate_transaction(handle, 0,
> +				handle->h_buffer_credits,
> +				path);
> +		if (ret) {
> +			mlog_errno(ret);
> +			goto out;
> +		}
>  		/*
>  		 * The merge code will need to create an empty
>  		 * extent to take the place of the newly
> @@ -3727,6 +3716,15 @@ static int ocfs2_try_to_merge_extent(han
>  		 */
>  		BUG_ON(!ocfs2_is_empty_extent(&el->l_recs[0]));
>  
> +		/* extend credit for ocfs2_remove_rightmost_path */
> +		ret = ocfs2_extend_rotate_transaction(handle, 0,
> +					handle->h_buffer_credits,
> +					path);
> +		if (ret) {
> +			mlog_errno(ret);
> +			goto out;
> +		}
> +
>  		/* The merge left us with an empty extent, remove it. */
>  		ret = ocfs2_rotate_tree_left(handle, et, path, dealloc);
>  		if (ret) {
> @@ -3748,6 +3746,15 @@ static int ocfs2_try_to_merge_extent(han
>  			goto out;
>  		}
>  
> +		/* extend credit for ocfs2_remove_rightmost_path */
> +		ret = ocfs2_extend_rotate_transaction(handle, 0,
> +				handle->h_buffer_credits,
> +				path);
> +		if (ret) {
> +			mlog_errno(ret);
> +			goto out;
> +		}
> +
>  		ret = ocfs2_rotate_tree_left(handle, et, path, dealloc);
>  		/*
>  		 * Error from this last rotate is not critical, so
> @@ -3783,6 +3790,16 @@ static int ocfs2_try_to_merge_extent(han
>  		}
>  
>  		if (ctxt->c_split_covers_rec) {
> +			/* extend credit for ocfs2_remove_rightmost_path */
> +			ret = ocfs2_extend_rotate_transaction(handle, 0,
> +					handle->h_buffer_credits,
> +					path);
> +			if (ret) {
> +				mlog_errno(ret);
> +				ret = 0;
> +				goto out;
> +			}
> +
>  			/*
>  			 * The merge may have left an empty extent in
>  			 * our leaf. Try to rotate it away.
> @@ -5342,6 +5359,15 @@ static int ocfs2_truncate_rec(handle_t *
>  	struct ocfs2_extent_block *eb;
>  
>  	if (ocfs2_is_empty_extent(&el->l_recs[0]) && index > 0) {
> +		/* extend credit for ocfs2_remove_rightmost_path */
> +		ret = ocfs2_extend_rotate_transaction(handle, 0,
> +				handle->h_buffer_credits,
> +				path);
> +		if (ret) {
> +			mlog_errno(ret);
> +			goto out;
> +		}
> +
>  		ret = ocfs2_rotate_tree_left(handle, et, path, dealloc);
>  		if (ret) {
>  			mlog_errno(ret);
> _
> 
> .
> 





More information about the Ocfs2-devel mailing list