Skip to content

Commit 9fbec87

Browse files
fdmananakdave
authored andcommitted
btrfs: fix inode lookup error handling during log replay
When replay log trees we use read_one_inode() to get an inode, which is just a wrapper around btrfs_iget_logging(), which in turn is wrapper for btrfs_iget(). But read_one_inode() always returns NULL for any error that btrfs_iget_logging() / btrfs_iget() may return and this is a problem because: 1) In many callers of read_one_inode() we convert the NULL into -EIO, which is not accurate since btrfs_iget() may return -ENOMEM and -ENOENT for example, besides -EIO and other errors. So during log replay we may end up reporting a false -EIO, which is confusing since we may not have had any IO error at all; 2) When replaying directory deletes, at replay_dir_deletes(), we assume the NULL returned from read_one_inode() means that the inode doesn't exist and then proceed as if no error had happened. This is wrong because unless btrfs_iget() returned ERR_PTR(-ENOENT), we had an actual error and the target inode may exist in the target subvolume root - this may later result in the log replay code failing at a later stage (if we are "lucky") or succeed but leaving some inconsistency in the filesystem. So fix this by not ignoring errors from btrfs_iget_logging() and as a consequence remove the read_one_inode() wrapper and just use btrfs_iget_logging() directly. Also since btrfs_iget_logging() is supposed to be called only against subvolume roots, just like read_one_inode() which had a comment about it, add an assertion to btrfs_iget_logging() to check that the target root corresponds to a subvolume root. Fixes: 5d4f98a ("Btrfs: Mixed back reference (FORWARD ROLLING FORMAT CHANGE)") Signed-off-by: Filipe Manana <fdmanana@suse.com> Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 6437c70 commit 9fbec87

File tree

1 file changed

+62
-65
lines changed

1 file changed

+62
-65
lines changed

fs/btrfs/tree-log.c

Lines changed: 62 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,9 @@ static struct btrfs_inode *btrfs_iget_logging(u64 objectid, struct btrfs_root *r
143143
unsigned int nofs_flag;
144144
struct btrfs_inode *inode;
145145

146+
/* Only meant to be called for subvolume roots and not for log roots. */
147+
ASSERT(is_fstree(btrfs_root_id(root)));
148+
146149
/*
147150
* We're holding a transaction handle whether we are logging or
148151
* replaying a log tree, so we must make sure NOFS semantics apply
@@ -604,21 +607,6 @@ static int read_alloc_one_name(struct extent_buffer *eb, void *start, int len,
604607
return 0;
605608
}
606609

607-
/*
608-
* simple helper to read an inode off the disk from a given root
609-
* This can only be called for subvolume roots and not for the log
610-
*/
611-
static noinline struct btrfs_inode *read_one_inode(struct btrfs_root *root,
612-
u64 objectid)
613-
{
614-
struct btrfs_inode *inode;
615-
616-
inode = btrfs_iget_logging(objectid, root);
617-
if (IS_ERR(inode))
618-
return NULL;
619-
return inode;
620-
}
621-
622610
/* replays a single extent in 'eb' at 'slot' with 'key' into the
623611
* subvolume 'root'. path is released on entry and should be released
624612
* on exit.
@@ -674,9 +662,9 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
674662
return -EUCLEAN;
675663
}
676664

677-
inode = read_one_inode(root, key->objectid);
678-
if (!inode)
679-
return -EIO;
665+
inode = btrfs_iget_logging(key->objectid, root);
666+
if (IS_ERR(inode))
667+
return PTR_ERR(inode);
680668

681669
/*
682670
* first check to see if we already have this extent in the
@@ -948,9 +936,10 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans,
948936

949937
btrfs_release_path(path);
950938

951-
inode = read_one_inode(root, location.objectid);
952-
if (!inode) {
953-
ret = -EIO;
939+
inode = btrfs_iget_logging(location.objectid, root);
940+
if (IS_ERR(inode)) {
941+
ret = PTR_ERR(inode);
942+
inode = NULL;
954943
goto out;
955944
}
956945

@@ -1167,10 +1156,10 @@ static inline int __add_inode_ref(struct btrfs_trans_handle *trans,
11671156
kfree(victim_name.name);
11681157
return ret;
11691158
} else if (!ret) {
1170-
ret = -ENOENT;
1171-
victim_parent = read_one_inode(root,
1172-
parent_objectid);
1173-
if (victim_parent) {
1159+
victim_parent = btrfs_iget_logging(parent_objectid, root);
1160+
if (IS_ERR(victim_parent)) {
1161+
ret = PTR_ERR(victim_parent);
1162+
} else {
11741163
inc_nlink(&inode->vfs_inode);
11751164
btrfs_release_path(path);
11761165

@@ -1315,9 +1304,9 @@ static int unlink_old_inode_refs(struct btrfs_trans_handle *trans,
13151304
struct btrfs_inode *dir;
13161305

13171306
btrfs_release_path(path);
1318-
dir = read_one_inode(root, parent_id);
1319-
if (!dir) {
1320-
ret = -ENOENT;
1307+
dir = btrfs_iget_logging(parent_id, root);
1308+
if (IS_ERR(dir)) {
1309+
ret = PTR_ERR(dir);
13211310
kfree(name.name);
13221311
goto out;
13231312
}
@@ -1389,15 +1378,17 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
13891378
* copy the back ref in. The link count fixup code will take
13901379
* care of the rest
13911380
*/
1392-
dir = read_one_inode(root, parent_objectid);
1393-
if (!dir) {
1394-
ret = -ENOENT;
1381+
dir = btrfs_iget_logging(parent_objectid, root);
1382+
if (IS_ERR(dir)) {
1383+
ret = PTR_ERR(dir);
1384+
dir = NULL;
13951385
goto out;
13961386
}
13971387

1398-
inode = read_one_inode(root, inode_objectid);
1399-
if (!inode) {
1400-
ret = -EIO;
1388+
inode = btrfs_iget_logging(inode_objectid, root);
1389+
if (IS_ERR(inode)) {
1390+
ret = PTR_ERR(inode);
1391+
inode = NULL;
14011392
goto out;
14021393
}
14031394

@@ -1409,11 +1400,13 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
14091400
* parent object can change from one array
14101401
* item to another.
14111402
*/
1412-
if (!dir)
1413-
dir = read_one_inode(root, parent_objectid);
14141403
if (!dir) {
1415-
ret = -ENOENT;
1416-
goto out;
1404+
dir = btrfs_iget_logging(parent_objectid, root);
1405+
if (IS_ERR(dir)) {
1406+
ret = PTR_ERR(dir);
1407+
dir = NULL;
1408+
goto out;
1409+
}
14171410
}
14181411
} else {
14191412
ret = ref_get_fields(eb, ref_ptr, &name, &ref_index);
@@ -1681,9 +1674,9 @@ static noinline int fixup_inode_link_counts(struct btrfs_trans_handle *trans,
16811674
break;
16821675

16831676
btrfs_release_path(path);
1684-
inode = read_one_inode(root, key.offset);
1685-
if (!inode) {
1686-
ret = -EIO;
1677+
inode = btrfs_iget_logging(key.offset, root);
1678+
if (IS_ERR(inode)) {
1679+
ret = PTR_ERR(inode);
16871680
break;
16881681
}
16891682

@@ -1719,9 +1712,9 @@ static noinline int link_to_fixup_dir(struct btrfs_trans_handle *trans,
17191712
struct btrfs_inode *inode;
17201713
struct inode *vfs_inode;
17211714

1722-
inode = read_one_inode(root, objectid);
1723-
if (!inode)
1724-
return -EIO;
1715+
inode = btrfs_iget_logging(objectid, root);
1716+
if (IS_ERR(inode))
1717+
return PTR_ERR(inode);
17251718

17261719
vfs_inode = &inode->vfs_inode;
17271720
key.objectid = BTRFS_TREE_LOG_FIXUP_OBJECTID;
@@ -1760,14 +1753,14 @@ static noinline int insert_one_name(struct btrfs_trans_handle *trans,
17601753
struct btrfs_inode *dir;
17611754
int ret;
17621755

1763-
inode = read_one_inode(root, location->objectid);
1764-
if (!inode)
1765-
return -ENOENT;
1756+
inode = btrfs_iget_logging(location->objectid, root);
1757+
if (IS_ERR(inode))
1758+
return PTR_ERR(inode);
17661759

1767-
dir = read_one_inode(root, dirid);
1768-
if (!dir) {
1760+
dir = btrfs_iget_logging(dirid, root);
1761+
if (IS_ERR(dir)) {
17691762
iput(&inode->vfs_inode);
1770-
return -EIO;
1763+
return PTR_ERR(dir);
17711764
}
17721765

17731766
ret = btrfs_add_link(trans, dir, inode, name, 1, index);
@@ -1844,9 +1837,9 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
18441837
bool update_size = true;
18451838
bool name_added = false;
18461839

1847-
dir = read_one_inode(root, key->objectid);
1848-
if (!dir)
1849-
return -EIO;
1840+
dir = btrfs_iget_logging(key->objectid, root);
1841+
if (IS_ERR(dir))
1842+
return PTR_ERR(dir);
18501843

18511844
ret = read_alloc_one_name(eb, di + 1, btrfs_dir_name_len(eb, di), &name);
18521845
if (ret)
@@ -2146,9 +2139,10 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans,
21462139
btrfs_dir_item_key_to_cpu(eb, di, &location);
21472140
btrfs_release_path(path);
21482141
btrfs_release_path(log_path);
2149-
inode = read_one_inode(root, location.objectid);
2150-
if (!inode) {
2151-
ret = -EIO;
2142+
inode = btrfs_iget_logging(location.objectid, root);
2143+
if (IS_ERR(inode)) {
2144+
ret = PTR_ERR(inode);
2145+
inode = NULL;
21522146
goto out;
21532147
}
21542148

@@ -2300,14 +2294,17 @@ static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans,
23002294
if (!log_path)
23012295
return -ENOMEM;
23022296

2303-
dir = read_one_inode(root, dirid);
2304-
/* it isn't an error if the inode isn't there, that can happen
2305-
* because we replay the deletes before we copy in the inode item
2306-
* from the log
2297+
dir = btrfs_iget_logging(dirid, root);
2298+
/*
2299+
* It isn't an error if the inode isn't there, that can happen because
2300+
* we replay the deletes before we copy in the inode item from the log.
23072301
*/
2308-
if (!dir) {
2302+
if (IS_ERR(dir)) {
23092303
btrfs_free_path(log_path);
2310-
return 0;
2304+
ret = PTR_ERR(dir);
2305+
if (ret == -ENOENT)
2306+
ret = 0;
2307+
return ret;
23112308
}
23122309

23132310
range_start = 0;
@@ -2466,9 +2463,9 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
24662463
struct btrfs_inode *inode;
24672464
u64 from;
24682465

2469-
inode = read_one_inode(root, key.objectid);
2470-
if (!inode) {
2471-
ret = -EIO;
2466+
inode = btrfs_iget_logging(key.objectid, root);
2467+
if (IS_ERR(inode)) {
2468+
ret = PTR_ERR(inode);
24722469
break;
24732470
}
24742471
from = ALIGN(i_size_read(&inode->vfs_inode),

0 commit comments

Comments
 (0)