Skip to content

Commit cca7a0a

Browse files
committed
Merge tag 'for-6.17-fix-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs fix from David Sterba: "A single btrfs commit. It fixes a problem that people started to hit since 6.15.3 during log replay (e.g. after a crash). The bug is old but got more likely to happen since commit 5e85262 ("btrfs: fix fsync of files with no hard links not persisting deletion") got backported to stable (6.15 only)" * tag 'for-6.17-fix-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: fix log tree replay failure due to file with 0 links and extents
2 parents d7edcc7 + 0a32e4f commit cca7a0a

File tree

1 file changed

+30
-18
lines changed

1 file changed

+30
-18
lines changed

fs/btrfs/tree-log.c

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -321,8 +321,7 @@ struct walk_control {
321321

322322
/*
323323
* Ignore any items from the inode currently being processed. Needs
324-
* to be set every time we find a BTRFS_INODE_ITEM_KEY and we are in
325-
* the LOG_WALK_REPLAY_INODES stage.
324+
* to be set every time we find a BTRFS_INODE_ITEM_KEY.
326325
*/
327326
bool ignore_cur_inode;
328327

@@ -2465,32 +2464,45 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
24652464

24662465
nritems = btrfs_header_nritems(eb);
24672466
for (i = 0; i < nritems; i++) {
2468-
btrfs_item_key_to_cpu(eb, &key, i);
2467+
struct btrfs_inode_item *inode_item;
24692468

2470-
/* inode keys are done during the first stage */
2471-
if (key.type == BTRFS_INODE_ITEM_KEY &&
2472-
wc->stage == LOG_WALK_REPLAY_INODES) {
2473-
struct btrfs_inode_item *inode_item;
2474-
u32 mode;
2469+
btrfs_item_key_to_cpu(eb, &key, i);
24752470

2476-
inode_item = btrfs_item_ptr(eb, i,
2477-
struct btrfs_inode_item);
2471+
if (key.type == BTRFS_INODE_ITEM_KEY) {
2472+
inode_item = btrfs_item_ptr(eb, i, struct btrfs_inode_item);
24782473
/*
2479-
* If we have a tmpfile (O_TMPFILE) that got fsync'ed
2480-
* and never got linked before the fsync, skip it, as
2481-
* replaying it is pointless since it would be deleted
2482-
* later. We skip logging tmpfiles, but it's always
2483-
* possible we are replaying a log created with a kernel
2484-
* that used to log tmpfiles.
2474+
* An inode with no links is either:
2475+
*
2476+
* 1) A tmpfile (O_TMPFILE) that got fsync'ed and never
2477+
* got linked before the fsync, skip it, as replaying
2478+
* it is pointless since it would be deleted later.
2479+
* We skip logging tmpfiles, but it's always possible
2480+
* we are replaying a log created with a kernel that
2481+
* used to log tmpfiles;
2482+
*
2483+
* 2) A non-tmpfile which got its last link deleted
2484+
* while holding an open fd on it and later got
2485+
* fsynced through that fd. We always log the
2486+
* parent inodes when inode->last_unlink_trans is
2487+
* set to the current transaction, so ignore all the
2488+
* inode items for this inode. We will delete the
2489+
* inode when processing the parent directory with
2490+
* replay_dir_deletes().
24852491
*/
24862492
if (btrfs_inode_nlink(eb, inode_item) == 0) {
24872493
wc->ignore_cur_inode = true;
24882494
continue;
24892495
} else {
24902496
wc->ignore_cur_inode = false;
24912497
}
2492-
ret = replay_xattr_deletes(wc->trans, root, log,
2493-
path, key.objectid);
2498+
}
2499+
2500+
/* Inode keys are done during the first stage. */
2501+
if (key.type == BTRFS_INODE_ITEM_KEY &&
2502+
wc->stage == LOG_WALK_REPLAY_INODES) {
2503+
u32 mode;
2504+
2505+
ret = replay_xattr_deletes(wc->trans, root, log, path, key.objectid);
24942506
if (ret)
24952507
break;
24962508
mode = btrfs_inode_mode(eb, inode_item);

0 commit comments

Comments
 (0)