mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	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: Yan Zheng <zheng.yan@oracle.com> Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
		
							parent
							
								
									d68fc57b7e
								
							
						
					
					
						commit
						4a500fd178
					
				
					 5 changed files with 156 additions and 128 deletions
				
			
		| 
						 | 
				
			
			@ -972,42 +972,6 @@ static int find_and_setup_root(struct btrfs_root *tree_root,
 | 
			
		|||
	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,
 | 
			
		||||
					 struct btrfs_fs_info *fs_info)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
int btrfs_write_tree_block(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,
 | 
			
		||||
			     struct btrfs_fs_info *fs_info);
 | 
			
		||||
int btrfs_add_log_tree(struct btrfs_trans_handle *trans,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -657,6 +657,9 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
 | 
			
		|||
		goto found;
 | 
			
		||||
	}
 | 
			
		||||
	ret = PTR_ERR(item);
 | 
			
		||||
	if (ret != -EFBIG && ret != -ENOENT)
 | 
			
		||||
		goto fail_unlock;
 | 
			
		||||
 | 
			
		||||
	if (ret == -EFBIG) {
 | 
			
		||||
		u32 item_size;
 | 
			
		||||
		/* we found one, but it isn't big enough yet */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -135,6 +135,7 @@ static int start_log_trans(struct btrfs_trans_handle *trans,
 | 
			
		|||
			   struct btrfs_root *root)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	int err = 0;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&root->log_mutex);
 | 
			
		||||
	if (root->log_root) {
 | 
			
		||||
| 
						 | 
				
			
			@ -155,17 +156,19 @@ static int start_log_trans(struct btrfs_trans_handle *trans,
 | 
			
		|||
	mutex_lock(&root->fs_info->tree_log_mutex);
 | 
			
		||||
	if (!root->fs_info->log_root_tree) {
 | 
			
		||||
		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);
 | 
			
		||||
		BUG_ON(ret);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			err = ret;
 | 
			
		||||
	}
 | 
			
		||||
	mutex_unlock(&root->fs_info->tree_log_mutex);
 | 
			
		||||
	root->log_batch++;
 | 
			
		||||
	atomic_inc(&root->log_writers);
 | 
			
		||||
	mutex_unlock(&root->log_mutex);
 | 
			
		||||
	return 0;
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			@ -376,7 +379,7 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans,
 | 
			
		|||
			BUG_ON(ret);
 | 
			
		||||
		}
 | 
			
		||||
	} else if (ret) {
 | 
			
		||||
		BUG();
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	dst_ptr = btrfs_item_ptr_offset(path->nodes[0],
 | 
			
		||||
					path->slots[0]);
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
 | 
			
		||||
		wc->process_func(root, next, wc, ptr_gen);
 | 
			
		||||
 | 
			
		||||
		if (*level == 1) {
 | 
			
		||||
			wc->process_func(root, next, wc, ptr_gen);
 | 
			
		||||
 | 
			
		||||
			path->slots[*level]++;
 | 
			
		||||
			if (wc->free) {
 | 
			
		||||
				btrfs_read_buffer(next, ptr_gen);
 | 
			
		||||
| 
						 | 
				
			
			@ -1734,35 +1737,7 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
 | 
			
		|||
	WARN_ON(*level < 0);
 | 
			
		||||
	WARN_ON(*level >= BTRFS_MAX_LEVEL);
 | 
			
		||||
 | 
			
		||||
	if (path->nodes[*level] == root->node)
 | 
			
		||||
		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;
 | 
			
		||||
	path->slots[*level] = btrfs_header_nritems(path->nodes[*level]);
 | 
			
		||||
 | 
			
		||||
	cond_resched();
 | 
			
		||||
	return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -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++) {
 | 
			
		||||
		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;
 | 
			
		||||
			node = path->nodes[i];
 | 
			
		||||
			path->slots[i]++;
 | 
			
		||||
| 
						 | 
				
			
			@ -2047,7 +2022,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
 | 
			
		|||
	mutex_unlock(&log_root_tree->log_mutex);
 | 
			
		||||
 | 
			
		||||
	ret = update_log_root(trans, log);
 | 
			
		||||
	BUG_ON(ret);
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&log_root_tree->log_mutex);
 | 
			
		||||
	if (atomic_dec_and_test(&log_root_tree->log_writers)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2056,6 +2030,15 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
 | 
			
		|||
			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;
 | 
			
		||||
	if (atomic_read(&log_root_tree->log_commit[index2])) {
 | 
			
		||||
		btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
 | 
			
		||||
| 
						 | 
				
			
			@ -2129,15 +2112,10 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * 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)
 | 
			
		||||
static void free_log_tree(struct btrfs_trans_handle *trans,
 | 
			
		||||
			  struct btrfs_root *log)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	struct btrfs_root *log;
 | 
			
		||||
	struct key;
 | 
			
		||||
	u64 start;
 | 
			
		||||
	u64 end;
 | 
			
		||||
	struct walk_control wc = {
 | 
			
		||||
| 
						 | 
				
			
			@ -2145,10 +2123,6 @@ int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root)
 | 
			
		|||
		.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);
 | 
			
		||||
	BUG_ON(ret);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2162,14 +2136,30 @@ int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root)
 | 
			
		|||
				  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);
 | 
			
		||||
	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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2203,6 +2193,7 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
 | 
			
		|||
	struct btrfs_dir_item *di;
 | 
			
		||||
	struct btrfs_path *path;
 | 
			
		||||
	int ret;
 | 
			
		||||
	int err = 0;
 | 
			
		||||
	int bytes_del = 0;
 | 
			
		||||
 | 
			
		||||
	if (BTRFS_I(dir)->logged_trans < trans->transid)
 | 
			
		||||
| 
						 | 
				
			
			@ -2218,7 +2209,11 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
 | 
			
		|||
	path = btrfs_alloc_path();
 | 
			
		||||
	di = btrfs_lookup_dir_item(trans, log, path, dir->i_ino,
 | 
			
		||||
				   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);
 | 
			
		||||
		bytes_del += name_len;
 | 
			
		||||
		BUG_ON(ret);
 | 
			
		||||
| 
						 | 
				
			
			@ -2226,7 +2221,11 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
 | 
			
		|||
	btrfs_release_path(log, path);
 | 
			
		||||
	di = btrfs_lookup_dir_index_item(trans, log, path, dir->i_ino,
 | 
			
		||||
					 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);
 | 
			
		||||
		bytes_del += name_len;
 | 
			
		||||
		BUG_ON(ret);
 | 
			
		||||
| 
						 | 
				
			
			@ -2244,6 +2243,10 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
 | 
			
		|||
		btrfs_release_path(log, path);
 | 
			
		||||
 | 
			
		||||
		ret = btrfs_search_slot(trans, log, &key, path, 0, 1);
 | 
			
		||||
		if (ret < 0) {
 | 
			
		||||
			err = ret;
 | 
			
		||||
			goto fail;
 | 
			
		||||
		}
 | 
			
		||||
		if (ret == 0) {
 | 
			
		||||
			struct btrfs_inode_item *item;
 | 
			
		||||
			u64 i_size;
 | 
			
		||||
| 
						 | 
				
			
			@ -2261,9 +2264,13 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
 | 
			
		|||
			ret = 0;
 | 
			
		||||
		btrfs_release_path(log, path);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
	btrfs_free_path(path);
 | 
			
		||||
	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);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
				  dirid, &index);
 | 
			
		||||
	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);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -2318,7 +2329,8 @@ static noinline int insert_dir_log_key(struct btrfs_trans_handle *trans,
 | 
			
		|||
	else
 | 
			
		||||
		key.type = BTRFS_DIR_LOG_INDEX_KEY;
 | 
			
		||||
	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],
 | 
			
		||||
			      struct btrfs_dir_log_item);
 | 
			
		||||
| 
						 | 
				
			
			@ -2343,6 +2355,7 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
 | 
			
		|||
	struct btrfs_key max_key;
 | 
			
		||||
	struct btrfs_root *log = root->log_root;
 | 
			
		||||
	struct extent_buffer *src;
 | 
			
		||||
	int err = 0;
 | 
			
		||||
	int ret;
 | 
			
		||||
	int i;
 | 
			
		||||
	int nritems;
 | 
			
		||||
| 
						 | 
				
			
			@ -2405,6 +2418,10 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
 | 
			
		|||
			ret = overwrite_item(trans, log, dst_path,
 | 
			
		||||
					     path->nodes[0], path->slots[0],
 | 
			
		||||
					     &tmp);
 | 
			
		||||
			if (ret) {
 | 
			
		||||
				err = ret;
 | 
			
		||||
				goto done;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	btrfs_release_path(root, path);
 | 
			
		||||
| 
						 | 
				
			
			@ -2432,7 +2449,10 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
 | 
			
		|||
				goto done;
 | 
			
		||||
			ret = overwrite_item(trans, log, dst_path, src, i,
 | 
			
		||||
					     &min_key);
 | 
			
		||||
			BUG_ON(ret);
 | 
			
		||||
			if (ret) {
 | 
			
		||||
				err = ret;
 | 
			
		||||
				goto done;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		path->slots[0] = nritems;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2454,22 +2474,30 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
 | 
			
		|||
			ret = overwrite_item(trans, log, dst_path,
 | 
			
		||||
					     path->nodes[0], path->slots[0],
 | 
			
		||||
					     &tmp);
 | 
			
		||||
 | 
			
		||||
			BUG_ON(ret);
 | 
			
		||||
			last_offset = tmp.offset;
 | 
			
		||||
			if (ret)
 | 
			
		||||
				err = ret;
 | 
			
		||||
			else
 | 
			
		||||
				last_offset = tmp.offset;
 | 
			
		||||
			goto done;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
done:
 | 
			
		||||
	*last_offset_ret = last_offset;
 | 
			
		||||
	btrfs_release_path(root, path);
 | 
			
		||||
	btrfs_release_path(log, dst_path);
 | 
			
		||||
 | 
			
		||||
	/* insert the log range keys to indicate where the log is valid */
 | 
			
		||||
	ret = insert_dir_log_key(trans, log, path, key_type, inode->i_ino,
 | 
			
		||||
				 first_offset, last_offset);
 | 
			
		||||
	BUG_ON(ret);
 | 
			
		||||
	return 0;
 | 
			
		||||
	if (err == 0) {
 | 
			
		||||
		*last_offset_ret = last_offset;
 | 
			
		||||
		/*
 | 
			
		||||
		 * insert the log range keys to indicate where the log
 | 
			
		||||
		 * 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,
 | 
			
		|||
		ret = log_dir_items(trans, root, inode, path,
 | 
			
		||||
				    dst_path, key_type, min_key,
 | 
			
		||||
				    &max_key);
 | 
			
		||||
		BUG_ON(ret);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
		if (max_key == (u64)-1)
 | 
			
		||||
			break;
 | 
			
		||||
		min_key = max_key + 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -2535,8 +2564,8 @@ static int drop_objectid_items(struct btrfs_trans_handle *trans,
 | 
			
		|||
 | 
			
		||||
	while (1) {
 | 
			
		||||
		ret = btrfs_search_slot(trans, log, &key, path, -1, 1);
 | 
			
		||||
 | 
			
		||||
		if (ret != 1)
 | 
			
		||||
		BUG_ON(ret == 0);
 | 
			
		||||
		if (ret < 0)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		if (path->slots[0] == 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -2554,7 +2583,7 @@ static int drop_objectid_items(struct btrfs_trans_handle *trans,
 | 
			
		|||
		btrfs_release_path(log, path);
 | 
			
		||||
	}
 | 
			
		||||
	btrfs_release_path(log, path);
 | 
			
		||||
	return 0;
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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,
 | 
			
		||||
				       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]++) {
 | 
			
		||||
		dst_offset = btrfs_item_ptr_offset(dst_path->nodes[0],
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
	 * log tree while trying to change the log tree.
 | 
			
		||||
	 */
 | 
			
		||||
	ret = 0;
 | 
			
		||||
	while (!list_empty(&ordered_sums)) {
 | 
			
		||||
		struct btrfs_ordered_sum *sums = list_entry(ordered_sums.next,
 | 
			
		||||
						   struct btrfs_ordered_sum,
 | 
			
		||||
						   list);
 | 
			
		||||
		ret = btrfs_csum_file_blocks(trans, log, sums);
 | 
			
		||||
		BUG_ON(ret);
 | 
			
		||||
		if (!ret)
 | 
			
		||||
			ret = btrfs_csum_file_blocks(trans, log, sums);
 | 
			
		||||
		list_del(&sums->list);
 | 
			
		||||
		kfree(sums);
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* log a single inode in the tree log.
 | 
			
		||||
| 
						 | 
				
			
			@ -2697,6 +2730,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
 | 
			
		|||
	struct btrfs_root *log = root->log_root;
 | 
			
		||||
	struct extent_buffer *src = NULL;
 | 
			
		||||
	u32 size;
 | 
			
		||||
	int err = 0;
 | 
			
		||||
	int ret;
 | 
			
		||||
	int nritems;
 | 
			
		||||
	int ins_start_slot = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -2739,7 +2773,10 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
 | 
			
		|||
	} else {
 | 
			
		||||
		ret = btrfs_truncate_inode_items(trans, log, inode, 0, 0);
 | 
			
		||||
	}
 | 
			
		||||
	BUG_ON(ret);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		err = ret;
 | 
			
		||||
		goto out_unlock;
 | 
			
		||||
	}
 | 
			
		||||
	path->keep_locks = 1;
 | 
			
		||||
 | 
			
		||||
	while (1) {
 | 
			
		||||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
				 ins_nr, inode_only);
 | 
			
		||||
		BUG_ON(ret);
 | 
			
		||||
		if (ret) {
 | 
			
		||||
			err = ret;
 | 
			
		||||
			goto out_unlock;
 | 
			
		||||
		}
 | 
			
		||||
		ins_nr = 1;
 | 
			
		||||
		ins_start_slot = path->slots[0];
 | 
			
		||||
next_slot:
 | 
			
		||||
| 
						 | 
				
			
			@ -2784,7 +2824,10 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
 | 
			
		|||
			ret = copy_items(trans, log, dst_path, src,
 | 
			
		||||
					 ins_start_slot,
 | 
			
		||||
					 ins_nr, inode_only);
 | 
			
		||||
			BUG_ON(ret);
 | 
			
		||||
			if (ret) {
 | 
			
		||||
				err = ret;
 | 
			
		||||
				goto out_unlock;
 | 
			
		||||
			}
 | 
			
		||||
			ins_nr = 0;
 | 
			
		||||
		}
 | 
			
		||||
		btrfs_release_path(root, path);
 | 
			
		||||
| 
						 | 
				
			
			@ -2802,7 +2845,10 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
 | 
			
		|||
		ret = copy_items(trans, log, dst_path, src,
 | 
			
		||||
				 ins_start_slot,
 | 
			
		||||
				 ins_nr, inode_only);
 | 
			
		||||
		BUG_ON(ret);
 | 
			
		||||
		if (ret) {
 | 
			
		||||
			err = ret;
 | 
			
		||||
			goto out_unlock;
 | 
			
		||||
		}
 | 
			
		||||
		ins_nr = 0;
 | 
			
		||||
	}
 | 
			
		||||
	WARN_ON(ins_nr);
 | 
			
		||||
| 
						 | 
				
			
			@ -2810,14 +2856,18 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
 | 
			
		|||
		btrfs_release_path(root, path);
 | 
			
		||||
		btrfs_release_path(log, 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;
 | 
			
		||||
out_unlock:
 | 
			
		||||
	mutex_unlock(&BTRFS_I(inode)->log_mutex);
 | 
			
		||||
 | 
			
		||||
	btrfs_free_path(path);
 | 
			
		||||
	btrfs_free_path(dst_path);
 | 
			
		||||
	return 0;
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			@ -2942,10 +2992,13 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *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);
 | 
			
		||||
	BUG_ON(ret);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		goto end_trans;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * 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,
 | 
			
		|||
	 */
 | 
			
		||||
	if (S_ISREG(inode->i_mode) &&
 | 
			
		||||
	    BTRFS_I(inode)->generation <= last_committed &&
 | 
			
		||||
	    BTRFS_I(inode)->last_unlink_trans <= last_committed)
 | 
			
		||||
			goto no_parent;
 | 
			
		||||
	    BTRFS_I(inode)->last_unlink_trans <= last_committed) {
 | 
			
		||||
		ret = 0;
 | 
			
		||||
		goto end_trans;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inode_only = LOG_INODE_EXISTS;
 | 
			
		||||
	while (1) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2970,15 +3025,21 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
 | 
			
		|||
		if (BTRFS_I(inode)->generation >
 | 
			
		||||
		    root->fs_info->last_trans_committed) {
 | 
			
		||||
			ret = btrfs_log_inode(trans, root, inode, inode_only);
 | 
			
		||||
			BUG_ON(ret);
 | 
			
		||||
			if (ret)
 | 
			
		||||
				goto end_trans;
 | 
			
		||||
		}
 | 
			
		||||
		if (IS_ROOT(parent))
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		parent = parent->d_parent;
 | 
			
		||||
	}
 | 
			
		||||
no_parent:
 | 
			
		||||
	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);
 | 
			
		||||
end_no_trans:
 | 
			
		||||
	return ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -3020,7 +3081,7 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
 | 
			
		|||
	path = btrfs_alloc_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.pin = 1;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,6 +25,8 @@
 | 
			
		|||
int btrfs_sync_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_log_dentry_safe(struct btrfs_trans_handle *trans,
 | 
			
		||||
			  struct btrfs_root *root, struct dentry *dentry);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue