Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5a1d7843 authored by Jan Schmidt's avatar Jan Schmidt Committed by Chris Mason
Browse files

btrfs: improved readablity for add_inode_ref



Moved part of the code into a sub function and replaced most of the gotos
by ifs, hoping that it will be easier to read now.

Signed-off-by: default avatarJan Schmidt <list.btrfs@jan-o-sch.net>
Signed-off-by: default avatarMark Fasheh <mfasheh@suse.de>
parent 0aa4a17d
Loading
Loading
Loading
Loading
+97 −81
Original line number Diff line number Diff line
@@ -785,76 +785,18 @@ static noinline int backref_in_log(struct btrfs_root *log,
	return match;
}


/*
 * replay one inode back reference item found in the log tree.
 * eb, slot and key refer to the buffer and key found in the log tree.
 * root is the destination we are replaying into, and path is for temp
 * use by this function.  (it should be released on return).
 */
static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
static inline int __add_inode_ref(struct btrfs_trans_handle *trans,
				  struct btrfs_root *root,
				  struct btrfs_root *log,
				  struct btrfs_path *path,
				  struct extent_buffer *eb, int slot,
				  struct btrfs_key *key)
				  struct btrfs_root *log_root,
				  struct inode *dir, struct inode *inode,
				  struct btrfs_key *key,
				  struct extent_buffer *eb,
				  struct btrfs_inode_ref *ref,
				  char *name, int namelen, int *search_done)
{
	struct btrfs_inode_ref *ref;
	struct btrfs_dir_item *di;
	struct inode *dir;
	struct inode *inode;
	unsigned long ref_ptr;
	unsigned long ref_end;
	char *name;
	int namelen;
	int ret;
	int search_done = 0;

	/*
	 * it is possible that we didn't log all the parent directories
	 * for a given inode.  If we don't find the dir, just don't
	 * copy the back ref in.  The link count fixup code will take
	 * care of the rest
	 */
	dir = read_one_inode(root, key->offset);
	if (!dir)
		return -ENOENT;

	inode = read_one_inode(root, key->objectid);
	if (!inode) {
		iput(dir);
		return -EIO;
	}

	ref_ptr = btrfs_item_ptr_offset(eb, slot);
	ref_end = ref_ptr + btrfs_item_size_nr(eb, slot);

again:
	ref = (struct btrfs_inode_ref *)ref_ptr;

	namelen = btrfs_inode_ref_name_len(eb, ref);
	name = kmalloc(namelen, GFP_NOFS);
	BUG_ON(!name);

	read_extent_buffer(eb, name, (unsigned long)(ref + 1), namelen);

	/* if we already have a perfect match, we're done */
	if (inode_in_dir(root, path, btrfs_ino(dir), btrfs_ino(inode),
			 btrfs_inode_ref_index(eb, ref),
			 name, namelen)) {
		goto out;
	}

	/*
	 * look for a conflicting back reference in the metadata.
	 * if we find one we have to unlink that name of the file
	 * before we add our new link.  Later on, we overwrite any
	 * existing back reference, and we don't want to create
	 * dangling pointers in the directory.
	 */

	if (search_done)
		goto insert;
	struct btrfs_dir_item *di;

	ret = btrfs_search_slot(NULL, root, key, path, 0, 0);
	if (ret == 0) {
@@ -869,7 +811,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
		 * if so, just jump out, we're done
		 */
		if (key->objectid == key->offset)
			goto out_nowrite;
			return 1;

		/* check all the names in this back reference to see
		 * if they are in the log.  if so, we allow them to stay
@@ -888,7 +830,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
					   (unsigned long)(victim_ref + 1),
					   victim_name_len);

			if (!backref_in_log(log, key, victim_name,
			if (!backref_in_log(log_root, key, victim_name,
					    victim_name_len)) {
				btrfs_inc_nlink(inode);
				btrfs_release_path(path);
@@ -907,7 +849,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
		 * NOTE: we have searched root tree and checked the
		 * coresponding ref, it does not need to check again.
		 */
		search_done = 1;
		*search_done = 1;
	}
	btrfs_release_path(path);

@@ -930,25 +872,99 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
	}
	btrfs_release_path(path);

insert:
	return 0;
}

/*
 * replay one inode back reference item found in the log tree.
 * eb, slot and key refer to the buffer and key found in the log tree.
 * root is the destination we are replaying into, and path is for temp
 * use by this function.  (it should be released on return).
 */
static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
				  struct btrfs_root *root,
				  struct btrfs_root *log,
				  struct btrfs_path *path,
				  struct extent_buffer *eb, int slot,
				  struct btrfs_key *key)
{
	struct btrfs_inode_ref *ref;
	struct inode *dir;
	struct inode *inode;
	unsigned long ref_ptr;
	unsigned long ref_end;
	char *name;
	int namelen;
	int ret;
	int search_done = 0;

	/*
	 * it is possible that we didn't log all the parent directories
	 * for a given inode.  If we don't find the dir, just don't
	 * copy the back ref in.  The link count fixup code will take
	 * care of the rest
	 */
	dir = read_one_inode(root, key->offset);
	if (!dir)
		return -ENOENT;

	inode = read_one_inode(root, key->objectid);
	if (!inode) {
		iput(dir);
		return -EIO;
	}

	ref_ptr = btrfs_item_ptr_offset(eb, slot);
	ref_end = ref_ptr + btrfs_item_size_nr(eb, slot);

	while (ref_ptr < ref_end) {
		ref = (struct btrfs_inode_ref *)ref_ptr;

		namelen = btrfs_inode_ref_name_len(eb, ref);
		name = kmalloc(namelen, GFP_NOFS);
		BUG_ON(!name);

		read_extent_buffer(eb, name, (unsigned long)(ref + 1), namelen);

		/* if we already have a perfect match, we're done */
		if (!inode_in_dir(root, path, btrfs_ino(dir), btrfs_ino(inode),
				  btrfs_inode_ref_index(eb, ref),
				  name, namelen)) {
			/*
			 * look for a conflicting back reference in the
			 * metadata. if we find one we have to unlink that name
			 * of the file before we add our new link.  Later on, we
			 * overwrite any existing back reference, and we don't
			 * want to create dangling pointers in the directory.
			 */

			if (!search_done) {
				ret = __add_inode_ref(trans, root, path, log,
						      dir, inode, key, eb, ref,
						      name, namelen,
						      &search_done);
				if (ret == 1)
					goto out;
				BUG_ON(ret);
			}

			/* insert our name */
	ret = btrfs_add_link(trans, dir, inode, name, namelen, 0,
			     btrfs_inode_ref_index(eb, ref));
			ret = btrfs_add_link(trans, dir, inode, name, namelen,
					     0, btrfs_inode_ref_index(eb, ref));
			BUG_ON(ret);

			btrfs_update_inode(trans, root, inode);
		}

out:
		ref_ptr = (unsigned long)(ref + 1) + namelen;
		kfree(name);
	if (ref_ptr < ref_end)
		goto again;
	}

	/* finally write the back reference in the inode */
	ret = overwrite_item(trans, root, path, eb, slot, key);
	BUG_ON(ret);

out_nowrite:
out:
	btrfs_release_path(path);
	iput(dir);
	iput(inode);