for-5.15-rc5-tag
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE8rQSAMVO+zA4DBdWxWXV+ddtWDsFAmFkq/oACgkQxWXV+ddt WDs10g//Qx27foBu0U3ovvsla0t8GgcqgzUyOx3zxed0MbOEQCtK6kqRHQ/I+9ap 1Ec5y4qQqBwfp1NKlYdU/EiKBQIYbJO/nYhVIrFI/EZL/7qJTwyjYjrOjG9zIMvy 2ekxuF/XVnM6p3hyRcuWMCxsossuK4XIkb0bSZrwk/nFA6nt+gbXR1oE94JitM8p 0pwjvSVqpdTmOAIU5+oQldqL/By7un/rv+o6OTD9sJqTdQ1UMlHVDaa9mD8aCsYk XIiCYfkyo9rlbSAB5wmWuiAhske2xh7IXSr4l9mKxGOA0egbQAgmS1Zw3+Km7vFM t+ji/4rTFPFd2yv/sLCEnMinuwvBr3mnEh6pDHR76RNrI4CoK/GHmZSf7XyqzV8W QOftznNA9/nJInTULdhCDvNxbKhKKb+xeSP1L4uytnWc5am+WKOPLNkfczJUh3sq WUORpaUxByDol6BMsdQJqPVJ7CH5YI8lQzuQFoUTXDCgeQUBE2wE1s3q+5Ma+dNZ mamkfQim2R42nPk7RSQlFBeIyDBVBXWfSNvXNovrPFJyRmZqRWzh0nb3PS9VNnUy 6oCOCIT7XlM4Jwh4ZR21OT66RNQQ/2sLUOU/4838TOOdn00UVBrFObHQ+ll8rq74 Va9j0atj6iIn9c8lDQkqTek0pMDcmVGzb2MV6JA4BCbCL/lcGk8= =u3qV -----END PGP SIGNATURE----- Merge tag 'for-5.15-rc5-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux Pull btrfs fixes from David Sterba: "A few more error handling fixes, stemming from code inspection, error injection or fuzzing" * tag 'for-5.15-rc5-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: fix abort logic in btrfs_replace_file_extents btrfs: check for error when looking up inode during dir entry replay btrfs: unify lookup return value when dir entry is missing btrfs: deal with errors when adding inode reference during log replay btrfs: deal with errors when replaying dir entry during log replay btrfs: deal with errors when checking if a dir entry exists during log replay btrfs: update refs for any root except tree log roots btrfs: unlock newly allocated extent buffer after error
This commit is contained in:
commit
1986c10acc
|
@ -3030,7 +3030,7 @@ struct btrfs_dir_item *
|
|||
btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_path *path, u64 dir,
|
||||
u64 objectid, const char *name, int name_len,
|
||||
u64 index, const char *name, int name_len,
|
||||
int mod);
|
||||
struct btrfs_dir_item *
|
||||
btrfs_search_dir_index_item(struct btrfs_root *root,
|
||||
|
|
|
@ -190,9 +190,20 @@ static struct btrfs_dir_item *btrfs_lookup_match_dir(
|
|||
}
|
||||
|
||||
/*
|
||||
* lookup a directory item based on name. 'dir' is the objectid
|
||||
* we're searching in, and 'mod' tells us if you plan on deleting the
|
||||
* item (use mod < 0) or changing the options (use mod > 0)
|
||||
* Lookup for a directory item by name.
|
||||
*
|
||||
* @trans: The transaction handle to use. Can be NULL if @mod is 0.
|
||||
* @root: The root of the target tree.
|
||||
* @path: Path to use for the search.
|
||||
* @dir: The inode number (objectid) of the directory.
|
||||
* @name: The name associated to the directory entry we are looking for.
|
||||
* @name_len: The length of the name.
|
||||
* @mod: Used to indicate if the tree search is meant for a read only
|
||||
* lookup, for a modification lookup or for a deletion lookup, so
|
||||
* its value should be 0, 1 or -1, respectively.
|
||||
*
|
||||
* Returns: NULL if the dir item does not exists, an error pointer if an error
|
||||
* happened, or a pointer to a dir item if a dir item exists for the given name.
|
||||
*/
|
||||
struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
|
@ -273,27 +284,42 @@ out:
|
|||
}
|
||||
|
||||
/*
|
||||
* lookup a directory item based on index. 'dir' is the objectid
|
||||
* we're searching in, and 'mod' tells us if you plan on deleting the
|
||||
* item (use mod < 0) or changing the options (use mod > 0)
|
||||
* Lookup for a directory index item by name and index number.
|
||||
*
|
||||
* The name is used to make sure the index really points to the name you were
|
||||
* looking for.
|
||||
* @trans: The transaction handle to use. Can be NULL if @mod is 0.
|
||||
* @root: The root of the target tree.
|
||||
* @path: Path to use for the search.
|
||||
* @dir: The inode number (objectid) of the directory.
|
||||
* @index: The index number.
|
||||
* @name: The name associated to the directory entry we are looking for.
|
||||
* @name_len: The length of the name.
|
||||
* @mod: Used to indicate if the tree search is meant for a read only
|
||||
* lookup, for a modification lookup or for a deletion lookup, so
|
||||
* its value should be 0, 1 or -1, respectively.
|
||||
*
|
||||
* Returns: NULL if the dir index item does not exists, an error pointer if an
|
||||
* error happened, or a pointer to a dir item if the dir index item exists and
|
||||
* matches the criteria (name and index number).
|
||||
*/
|
||||
struct btrfs_dir_item *
|
||||
btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_path *path, u64 dir,
|
||||
u64 objectid, const char *name, int name_len,
|
||||
u64 index, const char *name, int name_len,
|
||||
int mod)
|
||||
{
|
||||
struct btrfs_dir_item *di;
|
||||
struct btrfs_key key;
|
||||
|
||||
key.objectid = dir;
|
||||
key.type = BTRFS_DIR_INDEX_KEY;
|
||||
key.offset = objectid;
|
||||
key.offset = index;
|
||||
|
||||
return btrfs_lookup_match_dir(trans, root, path, &key, name, name_len, mod);
|
||||
di = btrfs_lookup_match_dir(trans, root, path, &key, name, name_len, mod);
|
||||
if (di == ERR_PTR(-ENOENT))
|
||||
return NULL;
|
||||
|
||||
return di;
|
||||
}
|
||||
|
||||
struct btrfs_dir_item *
|
||||
|
|
|
@ -4859,6 +4859,7 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
|
|||
out_free_delayed:
|
||||
btrfs_free_delayed_extent_op(extent_op);
|
||||
out_free_buf:
|
||||
btrfs_tree_unlock(buf);
|
||||
free_extent_buffer(buf);
|
||||
out_free_reserved:
|
||||
btrfs_free_reserved_extent(fs_info, ins.objectid, ins.offset, 0);
|
||||
|
|
|
@ -734,8 +734,7 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans,
|
|||
if (args->start >= inode->disk_i_size && !args->replace_extent)
|
||||
modify_tree = 0;
|
||||
|
||||
update_refs = (test_bit(BTRFS_ROOT_SHAREABLE, &root->state) ||
|
||||
root == fs_info->tree_root);
|
||||
update_refs = (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID);
|
||||
while (1) {
|
||||
recow = 0;
|
||||
ret = btrfs_lookup_file_extent(trans, root, path, ino,
|
||||
|
@ -2704,14 +2703,16 @@ int btrfs_replace_file_extents(struct btrfs_inode *inode,
|
|||
drop_args.bytes_found);
|
||||
if (ret != -ENOSPC) {
|
||||
/*
|
||||
* When cloning we want to avoid transaction aborts when
|
||||
* nothing was done and we are attempting to clone parts
|
||||
* of inline extents, in such cases -EOPNOTSUPP is
|
||||
* returned by __btrfs_drop_extents() without having
|
||||
* changed anything in the file.
|
||||
* The only time we don't want to abort is if we are
|
||||
* attempting to clone a partial inline extent, in which
|
||||
* case we'll get EOPNOTSUPP. However if we aren't
|
||||
* clone we need to abort no matter what, because if we
|
||||
* got EOPNOTSUPP via prealloc then we messed up and
|
||||
* need to abort.
|
||||
*/
|
||||
if (extent_info && !extent_info->is_new_extent &&
|
||||
ret && ret != -EOPNOTSUPP)
|
||||
if (ret &&
|
||||
(ret != -EOPNOTSUPP ||
|
||||
(extent_info && extent_info->is_new_extent)))
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue