Skip to content

Commit 77a5b9e

Browse files
fdmananakdave
authored andcommitted
btrfs: deal with errors when checking if a dir entry exists during log replay
Currently inode_in_dir() ignores errors returned from btrfs_lookup_dir_index_item() and from btrfs_lookup_dir_item(), treating any errors as if the directory entry does not exists in the fs/subvolume tree, which is obviously not correct, as we can get errors such as -EIO when reading extent buffers while searching the fs/subvolume's tree. Fix that by making inode_in_dir() return the errors and making its only caller, add_inode_ref(), deal with returned errors as well. Signed-off-by: Filipe Manana <[email protected]> Reviewed-by: David Sterba <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent d175209 commit 77a5b9e

File tree

1 file changed

+29
-18
lines changed

1 file changed

+29
-18
lines changed

fs/btrfs/tree-log.c

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -939,9 +939,11 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans,
939939
}
940940

941941
/*
942-
* helper function to see if a given name and sequence number found
943-
* in an inode back reference are already in a directory and correctly
944-
* point to this inode
942+
* See if a given name and sequence number found in an inode back reference are
943+
* already in a directory and correctly point to this inode.
944+
*
945+
* Returns: < 0 on error, 0 if the directory entry does not exists and 1 if it
946+
* exists.
945947
*/
946948
static noinline int inode_in_dir(struct btrfs_root *root,
947949
struct btrfs_path *path,
@@ -950,29 +952,35 @@ static noinline int inode_in_dir(struct btrfs_root *root,
950952
{
951953
struct btrfs_dir_item *di;
952954
struct btrfs_key location;
953-
int match = 0;
955+
int ret = 0;
954956

955957
di = btrfs_lookup_dir_index_item(NULL, root, path, dirid,
956958
index, name, name_len, 0);
957-
if (di && !IS_ERR(di)) {
959+
if (IS_ERR(di)) {
960+
if (PTR_ERR(di) != -ENOENT)
961+
ret = PTR_ERR(di);
962+
goto out;
963+
} else if (di) {
958964
btrfs_dir_item_key_to_cpu(path->nodes[0], di, &location);
959965
if (location.objectid != objectid)
960966
goto out;
961-
} else
967+
} else {
962968
goto out;
963-
btrfs_release_path(path);
969+
}
964970

971+
btrfs_release_path(path);
965972
di = btrfs_lookup_dir_item(NULL, root, path, dirid, name, name_len, 0);
966-
if (di && !IS_ERR(di)) {
967-
btrfs_dir_item_key_to_cpu(path->nodes[0], di, &location);
968-
if (location.objectid != objectid)
969-
goto out;
970-
} else
973+
if (IS_ERR(di)) {
974+
ret = PTR_ERR(di);
971975
goto out;
972-
match = 1;
976+
} else if (di) {
977+
btrfs_dir_item_key_to_cpu(path->nodes[0], di, &location);
978+
if (location.objectid == objectid)
979+
ret = 1;
980+
}
973981
out:
974982
btrfs_release_path(path);
975-
return match;
983+
return ret;
976984
}
977985

978986
/*
@@ -1517,10 +1525,12 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
15171525
if (ret)
15181526
goto out;
15191527

1520-
/* if we already have a perfect match, we're done */
1521-
if (!inode_in_dir(root, path, btrfs_ino(BTRFS_I(dir)),
1522-
btrfs_ino(BTRFS_I(inode)), ref_index,
1523-
name, namelen)) {
1528+
ret = inode_in_dir(root, path, btrfs_ino(BTRFS_I(dir)),
1529+
btrfs_ino(BTRFS_I(inode)), ref_index,
1530+
name, namelen);
1531+
if (ret < 0) {
1532+
goto out;
1533+
} else if (ret == 0) {
15241534
/*
15251535
* look for a conflicting back reference in the
15261536
* metadata. if we find one we have to unlink that name
@@ -1580,6 +1590,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
15801590
if (ret)
15811591
goto out;
15821592
}
1593+
/* Else, ret == 1, we already have a perfect match, we're done. */
15831594

15841595
ref_ptr = (unsigned long)(ref_ptr + ref_struct_size) + namelen;
15851596
kfree(name);

0 commit comments

Comments
 (0)