Skip to content

Commit 5f61b96

Browse files
fdmananakdave
authored andcommitted
btrfs: fix inode lookup error handling during log replay
When replaying log trees we use read_one_inode() to get an inode, which is just a wrapper around btrfs_iget_logging(), which in turn is a 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)") Reviewed-by: Johannes Thumshirn <[email protected]> Reviewed-by: Qu Wenruo <[email protected]> Signed-off-by: Filipe Manana <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 54a7081 commit 5f61b96

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

@@ -1169,10 +1158,10 @@ static inline int __add_inode_ref(struct btrfs_trans_handle *trans,
11691158
kfree(victim_name.name);
11701159
return ret;
11711160
} else if (!ret) {
1172-
ret = -ENOENT;
1173-
victim_parent = read_one_inode(root,
1174-
parent_objectid);
1175-
if (victim_parent) {
1161+
victim_parent = btrfs_iget_logging(parent_objectid, root);
1162+
if (IS_ERR(victim_parent)) {
1163+
ret = PTR_ERR(victim_parent);
1164+
} else {
11761165
inc_nlink(&inode->vfs_inode);
11771166
btrfs_release_path(path);
11781167

@@ -1317,9 +1306,9 @@ static int unlink_old_inode_refs(struct btrfs_trans_handle *trans,
13171306
struct btrfs_inode *dir;
13181307

13191308
btrfs_release_path(path);
1320-
dir = read_one_inode(root, parent_id);
1321-
if (!dir) {
1322-
ret = -ENOENT;
1309+
dir = btrfs_iget_logging(parent_id, root);
1310+
if (IS_ERR(dir)) {
1311+
ret = PTR_ERR(dir);
13231312
kfree(name.name);
13241313
goto out;
13251314
}
@@ -1391,15 +1380,17 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
13911380
* copy the back ref in. The link count fixup code will take
13921381
* care of the rest
13931382
*/
1394-
dir = read_one_inode(root, parent_objectid);
1395-
if (!dir) {
1396-
ret = -ENOENT;
1383+
dir = btrfs_iget_logging(parent_objectid, root);
1384+
if (IS_ERR(dir)) {
1385+
ret = PTR_ERR(dir);
1386+
dir = NULL;
13971387
goto out;
13981388
}
13991389

1400-
inode = read_one_inode(root, inode_objectid);
1401-
if (!inode) {
1402-
ret = -EIO;
1390+
inode = btrfs_iget_logging(inode_objectid, root);
1391+
if (IS_ERR(inode)) {
1392+
ret = PTR_ERR(inode);
1393+
inode = NULL;
14031394
goto out;
14041395
}
14051396

@@ -1411,11 +1402,13 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
14111402
* parent object can change from one array
14121403
* item to another.
14131404
*/
1414-
if (!dir)
1415-
dir = read_one_inode(root, parent_objectid);
14161405
if (!dir) {
1417-
ret = -ENOENT;
1418-
goto out;
1406+
dir = btrfs_iget_logging(parent_objectid, root);
1407+
if (IS_ERR(dir)) {
1408+
ret = PTR_ERR(dir);
1409+
dir = NULL;
1410+
goto out;
1411+
}
14191412
}
14201413
} else {
14211414
ret = ref_get_fields(eb, ref_ptr, &name, &ref_index);
@@ -1684,9 +1677,9 @@ static noinline int fixup_inode_link_counts(struct btrfs_trans_handle *trans,
16841677
break;
16851678

16861679
btrfs_release_path(path);
1687-
inode = read_one_inode(root, key.offset);
1688-
if (!inode) {
1689-
ret = -EIO;
1680+
inode = btrfs_iget_logging(key.offset, root);
1681+
if (IS_ERR(inode)) {
1682+
ret = PTR_ERR(inode);
16901683
break;
16911684
}
16921685

@@ -1722,9 +1715,9 @@ static noinline int link_to_fixup_dir(struct btrfs_trans_handle *trans,
17221715
struct btrfs_inode *inode;
17231716
struct inode *vfs_inode;
17241717

1725-
inode = read_one_inode(root, objectid);
1726-
if (!inode)
1727-
return -EIO;
1718+
inode = btrfs_iget_logging(objectid, root);
1719+
if (IS_ERR(inode))
1720+
return PTR_ERR(inode);
17281721

17291722
vfs_inode = &inode->vfs_inode;
17301723
key.objectid = BTRFS_TREE_LOG_FIXUP_OBJECTID;
@@ -1763,14 +1756,14 @@ static noinline int insert_one_name(struct btrfs_trans_handle *trans,
17631756
struct btrfs_inode *dir;
17641757
int ret;
17651758

1766-
inode = read_one_inode(root, location->objectid);
1767-
if (!inode)
1768-
return -ENOENT;
1759+
inode = btrfs_iget_logging(location->objectid, root);
1760+
if (IS_ERR(inode))
1761+
return PTR_ERR(inode);
17691762

1770-
dir = read_one_inode(root, dirid);
1771-
if (!dir) {
1763+
dir = btrfs_iget_logging(dirid, root);
1764+
if (IS_ERR(dir)) {
17721765
iput(&inode->vfs_inode);
1773-
return -EIO;
1766+
return PTR_ERR(dir);
17741767
}
17751768

17761769
ret = btrfs_add_link(trans, dir, inode, name, 1, index);
@@ -1847,9 +1840,9 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
18471840
bool update_size = true;
18481841
bool name_added = false;
18491842

1850-
dir = read_one_inode(root, key->objectid);
1851-
if (!dir)
1852-
return -EIO;
1843+
dir = btrfs_iget_logging(key->objectid, root);
1844+
if (IS_ERR(dir))
1845+
return PTR_ERR(dir);
18531846

18541847
ret = read_alloc_one_name(eb, di + 1, btrfs_dir_name_len(eb, di), &name);
18551848
if (ret)
@@ -2149,9 +2142,10 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans,
21492142
btrfs_dir_item_key_to_cpu(eb, di, &location);
21502143
btrfs_release_path(path);
21512144
btrfs_release_path(log_path);
2152-
inode = read_one_inode(root, location.objectid);
2153-
if (!inode) {
2154-
ret = -EIO;
2145+
inode = btrfs_iget_logging(location.objectid, root);
2146+
if (IS_ERR(inode)) {
2147+
ret = PTR_ERR(inode);
2148+
inode = NULL;
21552149
goto out;
21562150
}
21572151

@@ -2303,14 +2297,17 @@ static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans,
23032297
if (!log_path)
23042298
return -ENOMEM;
23052299

2306-
dir = read_one_inode(root, dirid);
2307-
/* it isn't an error if the inode isn't there, that can happen
2308-
* because we replay the deletes before we copy in the inode item
2309-
* from the log
2300+
dir = btrfs_iget_logging(dirid, root);
2301+
/*
2302+
* It isn't an error if the inode isn't there, that can happen because
2303+
* we replay the deletes before we copy in the inode item from the log.
23102304
*/
2311-
if (!dir) {
2305+
if (IS_ERR(dir)) {
23122306
btrfs_free_path(log_path);
2313-
return 0;
2307+
ret = PTR_ERR(dir);
2308+
if (ret == -ENOENT)
2309+
ret = 0;
2310+
return ret;
23142311
}
23152312

23162313
range_start = 0;
@@ -2469,9 +2466,9 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
24692466
struct btrfs_inode *inode;
24702467
u64 from;
24712468

2472-
inode = read_one_inode(root, key.objectid);
2473-
if (!inode) {
2474-
ret = -EIO;
2469+
inode = btrfs_iget_logging(key.objectid, root);
2470+
if (IS_ERR(inode)) {
2471+
ret = PTR_ERR(inode);
24752472
break;
24762473
}
24772474
from = ALIGN(i_size_read(&inode->vfs_inode),

0 commit comments

Comments
 (0)