diff options
Diffstat (limited to 'fs/btrfs/tree-log.c')
| -rw-r--r-- | fs/btrfs/tree-log.c | 47 | 
1 files changed, 31 insertions, 16 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index fb52aa060093..d43261545264 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -2980,7 +2980,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,  		ret = 0;  	if (ret) {  		blk_finish_plug(&plug); -		btrfs_abort_transaction(trans, ret);  		btrfs_set_log_full_commit(trans);  		mutex_unlock(&root->log_mutex);  		goto out; @@ -3045,15 +3044,12 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,  		blk_finish_plug(&plug);  		btrfs_set_log_full_commit(trans); - -		if (ret != -ENOSPC) { -			btrfs_abort_transaction(trans, ret); -			mutex_unlock(&log_root_tree->log_mutex); -			goto out; -		} +		if (ret != -ENOSPC) +			btrfs_err(fs_info, +				  "failed to update log for root %llu ret %d", +				  root->root_key.objectid, ret);  		btrfs_wait_tree_log_extents(log, mark);  		mutex_unlock(&log_root_tree->log_mutex); -		ret = BTRFS_LOG_FORCE_COMMIT;  		goto out;  	} @@ -3112,7 +3108,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,  		goto out_wake_log_root;  	} else if (ret) {  		btrfs_set_log_full_commit(trans); -		btrfs_abort_transaction(trans, ret);  		mutex_unlock(&log_root_tree->log_mutex);  		goto out_wake_log_root;  	} @@ -3826,7 +3821,10 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,  					      path->slots[0]);  			if (tmp.type == BTRFS_DIR_INDEX_KEY)  				last_old_dentry_offset = tmp.offset; +		} else if (ret < 0) { +			err = ret;  		} +  		goto done;  	} @@ -3846,19 +3844,34 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,  		 */  		if (tmp.type == BTRFS_DIR_INDEX_KEY)  			last_old_dentry_offset = tmp.offset; +	} else if (ret < 0) { +		err = ret; +		goto done;  	} +  	btrfs_release_path(path);  	/* -	 * Find the first key from this transaction again.  See the note for -	 * log_new_dir_dentries, if we're logging a directory recursively we -	 * won't be holding its i_mutex, which means we can modify the directory -	 * while we're logging it.  If we remove an entry between our first -	 * search and this search we'll not find the key again and can just -	 * bail. +	 * Find the first key from this transaction again or the one we were at +	 * in the loop below in case we had to reschedule. We may be logging the +	 * directory without holding its VFS lock, which happen when logging new +	 * dentries (through log_new_dir_dentries()) or in some cases when we +	 * need to log the parent directory of an inode. This means a dir index +	 * key might be deleted from the inode's root, and therefore we may not +	 * find it anymore. If we can't find it, just move to the next key. We +	 * can not bail out and ignore, because if we do that we will simply +	 * not log dir index keys that come after the one that was just deleted +	 * and we can end up logging a dir index range that ends at (u64)-1 +	 * (@last_offset is initialized to that), resulting in removing dir +	 * entries we should not remove at log replay time.  	 */  search:  	ret = btrfs_search_slot(NULL, root, &min_key, path, 0, 0); +	if (ret > 0) +		ret = btrfs_next_item(root, path); +	if (ret < 0) +		err = ret; +	/* If ret is 1, there are no more keys in the inode's root. */  	if (ret != 0)  		goto done; @@ -5580,8 +5593,10 @@ static int add_conflicting_inode(struct btrfs_trans_handle *trans,  	 * LOG_INODE_EXISTS mode) and slow down other fsyncs or transaction  	 * commits.  	 */ -	if (ctx->num_conflict_inodes >= MAX_CONFLICT_INODES) +	if (ctx->num_conflict_inodes >= MAX_CONFLICT_INODES) { +		btrfs_set_log_full_commit(trans);  		return BTRFS_LOG_FORCE_COMMIT; +	}  	inode = btrfs_iget(root->fs_info->sb, ino, root);  	/*  | 
