for-6.17-fix-tag

-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEE8rQSAMVO+zA4DBdWxWXV+ddtWDsFAmiTNoEACgkQxWXV+ddt
 WDuo3Q/+PPl1TH5+8A9zp+Aq0teDiF4I4pfpFRcoy+18lvNiPj8zFMOelOoOXczb
 rpYegaAjTrtZFlk9lVChTI4fSlAUkhPjgzELMWmpQsTSiYqGJxLO7B3BJEBqvuEt
 HDR0l1yBOW30EFszc8LKDXFj6IPI78xtQ2QyzFOcs0Xk9RVO2e8NpTFeroSr/bou
 uORWjZKOpQwPMLHjhZmhg/iAO+BM4hdV0MP9mQL4p4fAEfm0IKkRvQC/IQitSmHD
 e2WB9GsnFn6DxkEy3AkqZyyKwEfWNTIo+af4xSkbfOIn1KRtvABCXRtvb7Iuc31z
 TjPTubCsVIa48MeYkK+Qj7roMbjpcIIPciSgQWnEF/OTaiEZtPgbJJUYtQbtg/6o
 IglLquGn96k10sWIBEaiqBbmTwDOEaPLrrq75PeN5F6BENGAGdNr19B+5UXPvGpp
 f5XBoSKrgvFmtEzhSzkOk9obJvUaY5060JMVoymUopOXQdi243gAzGJaPLKugzDY
 qwRHe594DR438FFfDtqCs9s8+F23SL+mRWoD5H26H0fTgOe8hMc1sSELD99yZrRm
 4SGum5/7VjF422Q3lacHrdCaOWCFr3tbbK+6CYB975v0XwGIZj0Lh1Y7joDx0faW
 YHee1AcPw3zAqXXUcKv5aU3KcdsCE9xXlLAUDxVGxQzebh46heU=
 =tSdx
 -----END PGP SIGNATURE-----

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
  5e85262e54 ("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
This commit is contained in:
Linus Torvalds 2025-08-06 15:52:56 +03:00
commit cca7a0aae8
1 changed files with 30 additions and 18 deletions

View File

@ -321,8 +321,7 @@ struct walk_control {
/*
* Ignore any items from the inode currently being processed. Needs
* to be set every time we find a BTRFS_INODE_ITEM_KEY and we are in
* the LOG_WALK_REPLAY_INODES stage.
* to be set every time we find a BTRFS_INODE_ITEM_KEY.
*/
bool ignore_cur_inode;
@ -2465,23 +2464,30 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
nritems = btrfs_header_nritems(eb);
for (i = 0; i < nritems; i++) {
struct btrfs_inode_item *inode_item;
btrfs_item_key_to_cpu(eb, &key, i);
/* inode keys are done during the first stage */
if (key.type == BTRFS_INODE_ITEM_KEY &&
wc->stage == LOG_WALK_REPLAY_INODES) {
struct btrfs_inode_item *inode_item;
u32 mode;
inode_item = btrfs_item_ptr(eb, i,
struct btrfs_inode_item);
if (key.type == BTRFS_INODE_ITEM_KEY) {
inode_item = btrfs_item_ptr(eb, i, struct btrfs_inode_item);
/*
* If we have a tmpfile (O_TMPFILE) that got fsync'ed
* and never got linked before the fsync, skip it, as
* replaying it is pointless since it would be deleted
* later. We skip logging tmpfiles, but it's always
* possible we are replaying a log created with a kernel
* that used to log tmpfiles.
* An inode with no links is either:
*
* 1) A tmpfile (O_TMPFILE) that got fsync'ed and never
* got linked before the fsync, skip it, as replaying
* it is pointless since it would be deleted later.
* We skip logging tmpfiles, but it's always possible
* we are replaying a log created with a kernel that
* used to log tmpfiles;
*
* 2) A non-tmpfile which got its last link deleted
* while holding an open fd on it and later got
* fsynced through that fd. We always log the
* parent inodes when inode->last_unlink_trans is
* set to the current transaction, so ignore all the
* inode items for this inode. We will delete the
* inode when processing the parent directory with
* replay_dir_deletes().
*/
if (btrfs_inode_nlink(eb, inode_item) == 0) {
wc->ignore_cur_inode = true;
@ -2489,8 +2495,14 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
} else {
wc->ignore_cur_inode = false;
}
ret = replay_xattr_deletes(wc->trans, root, log,
path, key.objectid);
}
/* Inode keys are done during the first stage. */
if (key.type == BTRFS_INODE_ITEM_KEY &&
wc->stage == LOG_WALK_REPLAY_INODES) {
u32 mode;
ret = replay_xattr_deletes(wc->trans, root, log, path, key.objectid);
if (ret)
break;
mode = btrfs_inode_mode(eb, inode_item);