diff options
Diffstat (limited to 'fs/btrfs/tree-log.c')
| -rw-r--r-- | fs/btrfs/tree-log.c | 79 | 
1 files changed, 48 insertions, 31 deletions
| diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index f7efc26aa82a..b415c5ec03ea 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -939,9 +939,11 @@ out:  }  /* - * helper function to see if a given name and sequence number found - * in an inode back reference are already in a directory and correctly - * point to this inode + * See if a given name and sequence number found in an inode back reference are + * already in a directory and correctly point to this inode. + * + * Returns: < 0 on error, 0 if the directory entry does not exists and 1 if it + * exists.   */  static noinline int inode_in_dir(struct btrfs_root *root,  				 struct btrfs_path *path, @@ -950,29 +952,34 @@ static noinline int inode_in_dir(struct btrfs_root *root,  {  	struct btrfs_dir_item *di;  	struct btrfs_key location; -	int match = 0; +	int ret = 0;  	di = btrfs_lookup_dir_index_item(NULL, root, path, dirid,  					 index, name, name_len, 0); -	if (di && !IS_ERR(di)) { +	if (IS_ERR(di)) { +		ret = PTR_ERR(di); +		goto out; +	} else if (di) {  		btrfs_dir_item_key_to_cpu(path->nodes[0], di, &location);  		if (location.objectid != objectid)  			goto out; -	} else +	} else {  		goto out; -	btrfs_release_path(path); +	} +	btrfs_release_path(path);  	di = btrfs_lookup_dir_item(NULL, root, path, dirid, name, name_len, 0); -	if (di && !IS_ERR(di)) { -		btrfs_dir_item_key_to_cpu(path->nodes[0], di, &location); -		if (location.objectid != objectid) -			goto out; -	} else +	if (IS_ERR(di)) { +		ret = PTR_ERR(di);  		goto out; -	match = 1; +	} else if (di) { +		btrfs_dir_item_key_to_cpu(path->nodes[0], di, &location); +		if (location.objectid == objectid) +			ret = 1; +	}  out:  	btrfs_release_path(path); -	return match; +	return ret;  }  /* @@ -1182,7 +1189,9 @@ next:  	/* look for a conflicting sequence number */  	di = btrfs_lookup_dir_index_item(trans, root, path, btrfs_ino(dir),  					 ref_index, name, namelen, 0); -	if (di && !IS_ERR(di)) { +	if (IS_ERR(di)) { +		return PTR_ERR(di); +	} else if (di) {  		ret = drop_one_dir_item(trans, root, path, dir, di);  		if (ret)  			return ret; @@ -1192,7 +1201,9 @@ next:  	/* look for a conflicting name */  	di = btrfs_lookup_dir_item(trans, root, path, btrfs_ino(dir),  				   name, namelen, 0); -	if (di && !IS_ERR(di)) { +	if (IS_ERR(di)) { +		return PTR_ERR(di); +	} else if (di) {  		ret = drop_one_dir_item(trans, root, path, dir, di);  		if (ret)  			return ret; @@ -1517,10 +1528,12 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,  		if (ret)  			goto out; -		/* if we already have a perfect match, we're done */ -		if (!inode_in_dir(root, path, btrfs_ino(BTRFS_I(dir)), -					btrfs_ino(BTRFS_I(inode)), ref_index, -					name, namelen)) { +		ret = inode_in_dir(root, path, btrfs_ino(BTRFS_I(dir)), +				   btrfs_ino(BTRFS_I(inode)), ref_index, +				   name, namelen); +		if (ret < 0) { +			goto out; +		} else if (ret == 0) {  			/*  			 * look for a conflicting back reference in the  			 * metadata. if we find one we have to unlink that name @@ -1580,6 +1593,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,  			if (ret)  				goto out;  		} +		/* Else, ret == 1, we already have a perfect match, we're done. */  		ref_ptr = (unsigned long)(ref_ptr + ref_struct_size) + namelen;  		kfree(name); @@ -1936,8 +1950,8 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,  	struct btrfs_key log_key;  	struct inode *dir;  	u8 log_type; -	int exists; -	int ret = 0; +	bool exists; +	int ret;  	bool update_size = (key->type == BTRFS_DIR_INDEX_KEY);  	bool name_added = false; @@ -1957,12 +1971,12 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,  		   name_len);  	btrfs_dir_item_key_to_cpu(eb, di, &log_key); -	exists = btrfs_lookup_inode(trans, root, path, &log_key, 0); -	if (exists == 0) -		exists = 1; -	else -		exists = 0; +	ret = btrfs_lookup_inode(trans, root, path, &log_key, 0);  	btrfs_release_path(path); +	if (ret < 0) +		goto out; +	exists = (ret == 0); +	ret = 0;  	if (key->type == BTRFS_DIR_ITEM_KEY) {  		dst_di = btrfs_lookup_dir_item(trans, root, path, key->objectid, @@ -1977,7 +1991,11 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,  		ret = -EINVAL;  		goto out;  	} -	if (IS_ERR_OR_NULL(dst_di)) { + +	if (IS_ERR(dst_di)) { +		ret = PTR_ERR(dst_di); +		goto out; +	} else if (!dst_di) {  		/* we need a sequence number to insert, so we only  		 * do inserts for the BTRFS_DIR_INDEX_KEY types  		 */ @@ -2281,7 +2299,7 @@ again:  						     dir_key->offset,  						     name, name_len, 0);  		} -		if (!log_di || log_di == ERR_PTR(-ENOENT)) { +		if (!log_di) {  			btrfs_dir_item_key_to_cpu(eb, di, &location);  			btrfs_release_path(path);  			btrfs_release_path(log_path); @@ -3540,8 +3558,7 @@ out_unlock:  	if (err == -ENOSPC) {  		btrfs_set_log_full_commit(trans);  		err = 0; -	} else if (err < 0 && err != -ENOENT) { -		/* ENOENT can be returned if the entry hasn't been fsynced yet */ +	} else if (err < 0) {  		btrfs_abort_transaction(trans, err);  	} |