All of lore.kernel.org
 help / color / mirror / Atom feed
From: Hui Peng <benquike@gmail.com>
To: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Cc: Jan Kara <jack@suse.cz>,
	linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH] fat: avoid freeing clusters on failed directory validation or read-only mounts
Date: Sat, 19 Sep 2026 20:48:10 +0000	[thread overview]
Message-ID: <20260919204810.2813594-1-benquike@gmail.com> (raw)

In fat_fill_inode(), set_nlink(inode, fat_subdirs(inode)) is called
before fat_validate_dir(inode). If a directory has zero valid
subdirectories (so fat_subdirs(inode) returns 0) and fat_validate_dir()
subsequently returns -EIO (due to a missing or malformed '.'/'..'
entry), fat_build_inode() calls iput(inode) with inode->i_nlink == 0 and
inode->i_start still populated.

fat_evict_inode() then checks !inode->i_nlink without checking
is_bad_inode(inode) or sb_rdonly(inode->i_sb) and calls
fat_truncate_blocks(inode, 0), freeing the cluster chain on disk even on
a read-only (MS_RDONLY) mount.

Validate the directory before setting i_nlink in fat_fill_inode(), mark
the inode bad on error in fat_build_inode(), and guard cluster
truncation and metadata writeback in fat_evict_inode() with
!is_bad_inode(inode) && !sb_rdonly(inode->i_sb).

Fixes: a3082d526f2d ("fat: add simple validation for directory inode")
Assisted-by: LLM
Signed-off-by: Hui Peng <benquike@gmail.com>
---
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -535,11 +535,11 @@ int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
 			return error;
 		MSDOS_I(inode)->mmu_private = inode->i_size;
 
-		set_nlink(inode, fat_subdirs(inode));
-
 		error = fat_validate_dir(inode);
 		if (error < 0)
 			return error;
+
+		set_nlink(inode, fat_subdirs(inode));
 	} else { /* not a directory */
 		inode->i_generation |= 1;
 		inode->i_mode = fat_make_mode(sbi, de->attr,
@@ -610,6 +610,7 @@ struct inode *fat_build_inode(struct super_block *sb,
 	inode_set_iversion(inode, 1);
 	err = fat_fill_inode(inode, de);
 	if (err) {
+		make_bad_inode(inode);
 		iput(inode);
 		inode = ERR_PTR(err);
 		goto out;
@@ -688,12 +689,14 @@ static void fat_free_eofblocks(struct inode *inode)
 static void fat_evict_inode(struct inode *inode)
 {
 	truncate_inode_pages_final(&inode->i_data);
-	if (!inode->i_nlink) {
-		inode->i_size = 0;
-		fat_truncate_blocks(inode, 0);
-	} else {
-		mmb_sync(&MSDOS_I(inode)->i_metadata_bhs);
-		fat_free_eofblocks(inode);
+	if (!is_bad_inode(inode) && !sb_rdonly(inode->i_sb)) {
+		if (!inode->i_nlink) {
+			inode->i_size = 0;
+			fat_truncate_blocks(inode, 0);
+		} else {
+			mmb_sync(&MSDOS_I(inode)->i_metadata_bhs);
+			fat_free_eofblocks(inode);
+		}
 	}
 
 	mmb_invalidate(&MSDOS_I(inode)->i_metadata_bhs);
-- 
2.43.0

             reply	other threads:[~2026-09-19 20:48 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-19 20:48 Hui Peng [this message]
2026-09-22 17:56 ` [PATCH] fat: avoid freeing clusters on failed directory validation or read-only mounts OGAWA Hirofumi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260919204810.2813594-1-benquike@gmail.com \
    --to=benquike@gmail.com \
    --cc=hirofumi@mail.parknet.co.jp \
    --cc=jack@suse.cz \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.