Commit ccae4a19 authored by Filipe Manana's avatar Filipe Manana Committed by David Sterba
Browse files

btrfs: remove no longer needed logic for replaying directory deletes



Now that we log only dir index keys when logging a directory, we no longer
need to deal with dir item keys in the log replay code for replaying
directory deletes. This is also true for the case when we replay a log
tree created by a kernel that still logs dir items.

So remove the remaining code of the replay of directory deletes algorithm
that deals with dir item keys.

Reviewed-by: default avatarJosef Bacik <josef@toxicpanda.com>
Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 339d0354
Loading
Loading
Loading
Loading
+69 −89
Original line number Diff line number Diff line
@@ -2203,7 +2203,7 @@ static noinline int replay_one_dir_item(struct btrfs_trans_handle *trans,
 */
static noinline int find_dir_range(struct btrfs_root *root,
				   struct btrfs_path *path,
				   u64 dirid, int key_type,
				   u64 dirid,
				   u64 *start_ret, u64 *end_ret)
{
	struct btrfs_key key;
@@ -2216,7 +2216,7 @@ static noinline int find_dir_range(struct btrfs_root *root,
		return 1;

	key.objectid = dirid;
	key.type = key_type;
	key.type = BTRFS_DIR_LOG_INDEX_KEY;
	key.offset = *start_ret;

	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
@@ -2230,7 +2230,7 @@ static noinline int find_dir_range(struct btrfs_root *root,
	if (ret != 0)
		btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);

	if (key.type != key_type || key.objectid != dirid) {
	if (key.type != BTRFS_DIR_LOG_INDEX_KEY || key.objectid != dirid) {
		ret = 1;
		goto next;
	}
@@ -2257,7 +2257,7 @@ static noinline int find_dir_range(struct btrfs_root *root,

	btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);

	if (key.type != key_type || key.objectid != dirid) {
	if (key.type != BTRFS_DIR_LOG_INDEX_KEY || key.objectid != dirid) {
		ret = 1;
		goto out;
	}
@@ -2288,95 +2288,82 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans,
	int ret;
	struct extent_buffer *eb;
	int slot;
	u32 item_size;
	struct btrfs_dir_item *di;
	struct btrfs_dir_item *log_di;
	int name_len;
	unsigned long ptr;
	unsigned long ptr_end;
	char *name;
	struct inode *inode;
	struct inode *inode = NULL;
	struct btrfs_key location;

again:
	/*
	 * Currenly we only log dir index keys. Even if we replay a log created
	 * by an older kernel that logged both dir index and dir item keys, all
	 * we need to do is process the dir index keys, we (and our caller) can
	 * safely ignore dir item keys (key type BTRFS_DIR_ITEM_KEY).
	 */
	ASSERT(dir_key->type == BTRFS_DIR_INDEX_KEY);

	eb = path->nodes[0];
	slot = path->slots[0];
	item_size = btrfs_item_size_nr(eb, slot);
	ptr = btrfs_item_ptr_offset(eb, slot);
	ptr_end = ptr + item_size;
	while (ptr < ptr_end) {
		di = (struct btrfs_dir_item *)ptr;
	di = btrfs_item_ptr(eb, slot, struct btrfs_dir_item);
	name_len = btrfs_dir_name_len(eb, di);
	name = kmalloc(name_len, GFP_NOFS);
	if (!name) {
		ret = -ENOMEM;
		goto out;
	}
		read_extent_buffer(eb, name, (unsigned long)(di + 1),
				  name_len);
		log_di = NULL;
		if (log && dir_key->type == BTRFS_DIR_ITEM_KEY) {
			log_di = btrfs_lookup_dir_item(trans, log, log_path,
						       dir_key->objectid,
						       name, name_len, 0);
		} else if (log && dir_key->type == BTRFS_DIR_INDEX_KEY) {
			log_di = btrfs_lookup_dir_index_item(trans, log,
						     log_path,

	read_extent_buffer(eb, name, (unsigned long)(di + 1), name_len);

	if (log) {
		struct btrfs_dir_item *log_di;

		log_di = btrfs_lookup_dir_index_item(trans, log, log_path,
						     dir_key->objectid,
						     dir_key->offset,
						     name, name_len, 0);
		if (IS_ERR(log_di)) {
			ret = PTR_ERR(log_di);
			goto out;
		} else if (log_di) {
			/* The dentry exists in the log, we have nothing to do. */
			ret = 0;
			goto out;
		}
		if (!log_di) {
	}

	btrfs_dir_item_key_to_cpu(eb, di, &location);
	btrfs_release_path(path);
	btrfs_release_path(log_path);
	inode = read_one_inode(root, location.objectid);
	if (!inode) {
				kfree(name);
				return -EIO;
		ret = -EIO;
		goto out;
	}

			ret = link_to_fixup_dir(trans, root,
						path, location.objectid);
			if (ret) {
				kfree(name);
				iput(inode);
	ret = link_to_fixup_dir(trans, root, path, location.objectid);
	if (ret)
		goto out;
			}

	inc_nlink(inode);
			ret = btrfs_unlink_inode(trans, BTRFS_I(dir),
					BTRFS_I(inode), name, name_len);
			if (!ret)
				ret = btrfs_run_delayed_items(trans);
			kfree(name);
			iput(inode);
	ret = btrfs_unlink_inode(trans, BTRFS_I(dir), BTRFS_I(inode), name,
				 name_len);
	if (ret)
		goto out;

			/* there might still be more names under this key
			 * check and repeat if required
			 */
			ret = btrfs_search_slot(NULL, root, dir_key, path,
						0, 0);
			if (ret == 0)
				goto again;
			ret = 0;
	ret = btrfs_run_delayed_items(trans);
	if (ret)
		goto out;
		} else if (IS_ERR(log_di)) {
			kfree(name);
			return PTR_ERR(log_di);
		}
		btrfs_release_path(log_path);
		kfree(name);

		ptr = (unsigned long)(di + 1);
		ptr += name_len;
	}
	ret = 0;
	/*
	 * Unlike dir item keys, dir index keys can only have one name (entry) in
	 * them, as there are no key collisions since each key has a unique offset
	 * (an index number), so we're done.
	 */
out:
	btrfs_release_path(path);
	btrfs_release_path(log_path);
	kfree(name);
	iput(inode);
	return ret;
}

@@ -2496,7 +2483,6 @@ static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans,
{
	u64 range_start;
	u64 range_end;
	int key_type = BTRFS_DIR_LOG_ITEM_KEY;
	int ret = 0;
	struct btrfs_key dir_key;
	struct btrfs_key found_key;
@@ -2504,7 +2490,7 @@ static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans,
	struct inode *dir;

	dir_key.objectid = dirid;
	dir_key.type = BTRFS_DIR_ITEM_KEY;
	dir_key.type = BTRFS_DIR_INDEX_KEY;
	log_path = btrfs_alloc_path();
	if (!log_path)
		return -ENOMEM;
@@ -2518,14 +2504,14 @@ static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans,
		btrfs_free_path(log_path);
		return 0;
	}
again:

	range_start = 0;
	range_end = 0;
	while (1) {
		if (del_all)
			range_end = (u64)-1;
		else {
			ret = find_dir_range(log, path, dirid, key_type,
			ret = find_dir_range(log, path, dirid,
					     &range_start, &range_end);
			if (ret < 0)
				goto out;
@@ -2552,8 +2538,10 @@ static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans,
			btrfs_item_key_to_cpu(path->nodes[0], &found_key,
					      path->slots[0]);
			if (found_key.objectid != dirid ||
			    found_key.type != dir_key.type)
				goto next_type;
			    found_key.type != dir_key.type) {
				ret = 0;
				goto out;
			}

			if (found_key.offset > range_end)
				break;
@@ -2572,15 +2560,7 @@ static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans,
			break;
		range_start = range_end + 1;
	}

next_type:
	ret = 0;
	if (key_type == BTRFS_DIR_LOG_ITEM_KEY) {
		key_type = BTRFS_DIR_LOG_INDEX_KEY;
		dir_key.type = BTRFS_DIR_INDEX_KEY;
		btrfs_release_path(path);
		goto again;
	}
out:
	btrfs_release_path(path);
	btrfs_free_path(log_path);
+3 −1
Original line number Diff line number Diff line
@@ -146,7 +146,9 @@

/*
 * dir items are the name -> inode pointers in a directory.  There is one
 * for every name in a directory.
 * for every name in a directory.  BTRFS_DIR_LOG_ITEM_KEY is no longer used
 * but it's still defined here for documentation purposes and to help avoid
 * having its numerical value reused in the future.
 */
#define BTRFS_DIR_LOG_ITEM_KEY  60
#define BTRFS_DIR_LOG_INDEX_KEY 72