Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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
5e85262e542d ("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

+30 -18
+30 -18
fs/btrfs/tree-log.c
··· 321 321 322 322 /* 323 323 * 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. 326 325 */ 327 326 bool ignore_cur_inode; 328 327 ··· 2464 2465 2465 2466 nritems = btrfs_header_nritems(eb); 2466 2467 for (i = 0; i < nritems; i++) { 2468 + struct btrfs_inode_item *inode_item; 2469 + 2467 2470 btrfs_item_key_to_cpu(eb, &key, i); 2468 2471 2469 - /* inode keys are done during the first stage */ 2470 - if (key.type == BTRFS_INODE_ITEM_KEY && 2471 - wc->stage == LOG_WALK_REPLAY_INODES) { 2472 - struct btrfs_inode_item *inode_item; 2473 - u32 mode; 2474 - 2475 - inode_item = btrfs_item_ptr(eb, i, 2476 - struct btrfs_inode_item); 2472 + if (key.type == BTRFS_INODE_ITEM_KEY) { 2473 + inode_item = btrfs_item_ptr(eb, i, struct btrfs_inode_item); 2477 2474 /* 2478 - * If we have a tmpfile (O_TMPFILE) that got fsync'ed 2479 - * and never got linked before the fsync, skip it, as 2480 - * replaying it is pointless since it would be deleted 2481 - * later. We skip logging tmpfiles, but it's always 2482 - * possible we are replaying a log created with a kernel 2483 - * that used to log tmpfiles. 2475 + * An inode with no links is either: 2476 + * 2477 + * 1) A tmpfile (O_TMPFILE) that got fsync'ed and never 2478 + * got linked before the fsync, skip it, as replaying 2479 + * it is pointless since it would be deleted later. 2480 + * We skip logging tmpfiles, but it's always possible 2481 + * we are replaying a log created with a kernel that 2482 + * used to log tmpfiles; 2483 + * 2484 + * 2) A non-tmpfile which got its last link deleted 2485 + * while holding an open fd on it and later got 2486 + * fsynced through that fd. We always log the 2487 + * parent inodes when inode->last_unlink_trans is 2488 + * set to the current transaction, so ignore all the 2489 + * inode items for this inode. We will delete the 2490 + * inode when processing the parent directory with 2491 + * replay_dir_deletes(). 2484 2492 */ 2485 2493 if (btrfs_inode_nlink(eb, inode_item) == 0) { 2486 2494 wc->ignore_cur_inode = true; ··· 2495 2489 } else { 2496 2490 wc->ignore_cur_inode = false; 2497 2491 } 2498 - ret = replay_xattr_deletes(wc->trans, root, log, 2499 - path, key.objectid); 2492 + } 2493 + 2494 + /* Inode keys are done during the first stage. */ 2495 + if (key.type == BTRFS_INODE_ITEM_KEY && 2496 + wc->stage == LOG_WALK_REPLAY_INODES) { 2497 + u32 mode; 2498 + 2499 + ret = replay_xattr_deletes(wc->trans, root, log, path, key.objectid); 2500 2500 if (ret) 2501 2501 break; 2502 2502 mode = btrfs_inode_mode(eb, inode_item);