public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: linux-kernel@vger.kernel.org, stable@vger.kernel.org
Cc: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>,
	Sasha Levin <sashal@kernel.org>
Subject: [PATCH AUTOSEL 6.4 32/40] fs/ntfs3: Alternative boot if primary boot is corrupted
Date: Sun, 23 Jul 2023 21:31:32 -0400	[thread overview]
Message-ID: <20230724013140.2327815-32-sashal@kernel.org> (raw)
In-Reply-To: <20230724013140.2327815-1-sashal@kernel.org>

From: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>

[ Upstream commit 6a4cd3ea7d771be17177d95ff67d22cfa2a38b50 ]

Some code refactoring added also.

Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 fs/ntfs3/super.c | 98 +++++++++++++++++++++++++++++++++++-------------
 1 file changed, 71 insertions(+), 27 deletions(-)

diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c
index 5158dd31fd97f..ecf899d571d83 100644
--- a/fs/ntfs3/super.c
+++ b/fs/ntfs3/super.c
@@ -724,6 +724,8 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
 	struct MFT_REC *rec;
 	u16 fn, ao;
 	u8 cluster_bits;
+	u32 boot_off = 0;
+	const char *hint = "Primary boot";
 
 	sbi->volume.blocks = dev_size >> PAGE_SHIFT;
 
@@ -731,11 +733,12 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
 	if (!bh)
 		return -EIO;
 
+check_boot:
 	err = -EINVAL;
-	boot = (struct NTFS_BOOT *)bh->b_data;
+	boot = (struct NTFS_BOOT *)Add2Ptr(bh->b_data, boot_off);
 
 	if (memcmp(boot->system_id, "NTFS    ", sizeof("NTFS    ") - 1)) {
-		ntfs_err(sb, "Boot's signature is not NTFS.");
+		ntfs_err(sb, "%s signature is not NTFS.", hint);
 		goto out;
 	}
 
@@ -748,14 +751,16 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
 			   boot->bytes_per_sector[0];
 	if (boot_sector_size < SECTOR_SIZE ||
 	    !is_power_of_2(boot_sector_size)) {
-		ntfs_err(sb, "Invalid bytes per sector %u.", boot_sector_size);
+		ntfs_err(sb, "%s: invalid bytes per sector %u.", hint,
+			 boot_sector_size);
 		goto out;
 	}
 
 	/* cluster size: 512, 1K, 2K, 4K, ... 2M */
 	sct_per_clst = true_sectors_per_clst(boot);
 	if ((int)sct_per_clst < 0 || !is_power_of_2(sct_per_clst)) {
-		ntfs_err(sb, "Invalid sectors per cluster %u.", sct_per_clst);
+		ntfs_err(sb, "%s: invalid sectors per cluster %u.", hint,
+			 sct_per_clst);
 		goto out;
 	}
 
@@ -771,8 +776,8 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
 	if (mlcn * sct_per_clst >= sectors || mlcn2 * sct_per_clst >= sectors) {
 		ntfs_err(
 			sb,
-			"Start of MFT 0x%llx (0x%llx) is out of volume 0x%llx.",
-			mlcn, mlcn2, sectors);
+			"%s: start of MFT 0x%llx (0x%llx) is out of volume 0x%llx.",
+			hint, mlcn, mlcn2, sectors);
 		goto out;
 	}
 
@@ -784,7 +789,7 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
 
 	/* Check MFT record size. */
 	if (record_size < SECTOR_SIZE || !is_power_of_2(record_size)) {
-		ntfs_err(sb, "Invalid bytes per MFT record %u (%d).",
+		ntfs_err(sb, "%s: invalid bytes per MFT record %u (%d).", hint,
 			 record_size, boot->record_size);
 		goto out;
 	}
@@ -801,13 +806,13 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
 
 	/* Check index record size. */
 	if (sbi->index_size < SECTOR_SIZE || !is_power_of_2(sbi->index_size)) {
-		ntfs_err(sb, "Invalid bytes per index %u(%d).", sbi->index_size,
-			 boot->index_size);
+		ntfs_err(sb, "%s: invalid bytes per index %u(%d).", hint,
+			 sbi->index_size, boot->index_size);
 		goto out;
 	}
 
 	if (sbi->index_size > MAXIMUM_BYTES_PER_INDEX) {
-		ntfs_err(sb, "Unsupported bytes per index %u.",
+		ntfs_err(sb, "%s: unsupported bytes per index %u.", hint,
 			 sbi->index_size);
 		goto out;
 	}
@@ -834,7 +839,7 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
 
 	/* Compare boot's cluster and sector. */
 	if (sbi->cluster_size < boot_sector_size) {
-		ntfs_err(sb, "Invalid bytes per cluster (%u).",
+		ntfs_err(sb, "%s: invalid bytes per cluster (%u).", hint,
 			 sbi->cluster_size);
 		goto out;
 	}
@@ -930,7 +935,46 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
 
 	err = 0;
 
+	if (bh->b_blocknr && !sb_rdonly(sb)) {
+		/*
+	 	 * Alternative boot is ok but primary is not ok.
+	 	 * Update primary boot.
+		 */
+		struct buffer_head *bh0 = sb_getblk(sb, 0);
+		if (bh0) {
+			if (buffer_locked(bh0))
+				__wait_on_buffer(bh0);
+
+			lock_buffer(bh0);
+			memcpy(bh0->b_data, boot, sizeof(*boot));
+			set_buffer_uptodate(bh0);
+			mark_buffer_dirty(bh0);
+			unlock_buffer(bh0);
+			if (!sync_dirty_buffer(bh0))
+				ntfs_warn(sb, "primary boot is updated");
+			put_bh(bh0);
+		}
+	}
+
 out:
+	if (err == -EINVAL && !bh->b_blocknr && dev_size > PAGE_SHIFT) {
+		u32 block_size = min_t(u32, sector_size, PAGE_SIZE);
+		u64 lbo = dev_size - sizeof(*boot);
+
+		/*
+	 	 * Try alternative boot (last sector)
+		 */
+		brelse(bh);
+
+		sb_set_blocksize(sb, block_size);
+		bh = ntfs_bread(sb, lbo >> blksize_bits(block_size));
+		if (!bh)
+			return -EINVAL;
+
+		boot_off = lbo & (block_size - 1);
+		hint = "Alternative boot";
+		goto check_boot;
+	}
 	brelse(bh);
 
 	return err;
@@ -955,6 +999,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
 	struct ATTR_DEF_ENTRY *t;
 	u16 *shared;
 	struct MFT_REF ref;
+	bool ro = sb_rdonly(sb);
 
 	ref.high = 0;
 
@@ -1035,6 +1080,10 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
 	sbi->volume.minor_ver = info->minor_ver;
 	sbi->volume.flags = info->flags;
 	sbi->volume.ni = ni;
+	if (info->flags & VOLUME_FLAG_DIRTY) {
+		sbi->volume.real_dirty = true;
+		ntfs_info(sb, "It is recommened to use chkdsk.");
+	}
 
 	/* Load $MFTMirr to estimate recs_mirr. */
 	ref.low = cpu_to_le32(MFT_REC_MIRR);
@@ -1069,21 +1118,16 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
 
 	iput(inode);
 
-	if (sbi->flags & NTFS_FLAGS_NEED_REPLAY) {
-		if (!sb_rdonly(sb)) {
-			ntfs_warn(sb,
-				  "failed to replay log file. Can't mount rw!");
-			err = -EINVAL;
-			goto out;
-		}
-	} else if (sbi->volume.flags & VOLUME_FLAG_DIRTY) {
-		if (!sb_rdonly(sb) && !options->force) {
-			ntfs_warn(
-				sb,
-				"volume is dirty and \"force\" flag is not set!");
-			err = -EINVAL;
-			goto out;
-		}
+	if ((sbi->flags & NTFS_FLAGS_NEED_REPLAY) && !ro) {
+		ntfs_warn(sb, "failed to replay log file. Can't mount rw!");
+		err = -EINVAL;
+		goto out;
+	}
+
+	if ((sbi->volume.flags & VOLUME_FLAG_DIRTY) && !ro && !options->force) {
+		ntfs_warn(sb, "volume is dirty and \"force\" flag is not set!");
+		err = -EINVAL;
+		goto out;
 	}
 
 	/* Load $MFT. */
@@ -1173,7 +1217,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
 
 		bad_len += len;
 		bad_frags += 1;
-		if (sb_rdonly(sb))
+		if (ro)
 			continue;
 
 		if (wnd_set_used_safe(&sbi->used.bitmap, lcn, len, &tt) || tt) {
-- 
2.39.2


  parent reply	other threads:[~2023-07-24  1:39 UTC|newest]

Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-07-24  1:31 [PATCH AUTOSEL 6.4 01/40] serial: stm32: Ignore return value of uart_remove_one_port() in .remove() Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 02/40] led: qcom-lpg: Fix resource leaks in for_each_available_child_of_node() loops Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 03/40] media: v4l2-mem2mem: add lock to protect parameter num_rdy Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 04/40] media: camss: set VFE bpl_alignment to 16 for sdm845 and sm8250 Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 05/40] usb: gadget: u_serial: Avoid spinlock recursion in __gs_console_push Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 06/40] usb: gadget: uvc: queue empty isoc requests if no video buffer is available Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 07/40] media: platform: mediatek: vpu: fix NULL ptr dereference Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 08/40] thunderbolt: Read retimer NVM authentication status prior tb_retimer_set_inbound_sbtx() Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 09/40] xhci: Don't require a valid get_quirks() function pointer during xhci setup Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 10/40] xhci: get rid of XHCI_PLAT quirk that used to prevent MSI setup Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 11/40] usb: chipidea: imx: don't request QoS for imx8ulp Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 12/40] usb: cdns2: Device side header file for CDNS2 driver Sasha Levin
2023-07-24  4:09   ` Greg Kroah-Hartman
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 13/40] usb: chipidea: imx: turn off vbus comparator when suspend Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 14/40] usb: chipidea: imx: add missing USB PHY DPDM wakeup setting Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 15/40] gfs2: Fix possible data races in gfs2_show_options() Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 16/40] pcmcia: rsrc_nonstatic: Fix memory leak in nonstatic_release_resource_db() Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 17/40] thunderbolt: Add Intel Barlow Ridge PCI ID Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 18/40] thunderbolt: Limit Intel Barlow Ridge USB3 bandwidth Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 19/40] firewire: net: fix use after free in fwnet_finish_incoming_packet() Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 20/40] watchdog: sp5100_tco: support Hygon FCH/SCH (Server Controller Hub) Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 21/40] Bluetooth: L2CAP: Fix use-after-free Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 22/40] Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_ready_cb Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 23/40] Bluetooth: btusb: Add MT7922 bluetooth ID for the Asus Ally Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 24/40] ceph: try to dump the msgs when decoding fails Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 25/40] drm/amdgpu: Fix potential fence use-after-free v2 Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 26/40] f2fs: fix to do sanity check on direct node in truncate_dnode() Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 27/40] fs/ntfs3: Enhance sanity check while generating attr_list Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 28/40] fs/ntfs3: Return error for inconsistent extended attributes Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 29/40] fs: ntfs3: Fix possible null-pointer dereferences in mi_read() Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 30/40] fs/ntfs3: Use __GFP_NOWARN allocation at ntfs_load_attr_list() Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 31/40] fs/ntfs3: Mark ntfs dirty when on-disk struct is corrupted Sasha Levin
2023-07-24  1:31 ` Sasha Levin [this message]
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 33/40] ALSA: hda/realtek: Add quirks for Unis H3C Desktop B760 & Q760 Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 34/40] ALSA: hda: fix a possible null-pointer dereference due to data race in snd_hdac_regmap_sync() Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 35/40] ALSA: hda/realtek: Add quirk for ASUS ROG GX650P Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 36/40] ALSA: hda/realtek: Add quirk for ASUS ROG GA402X Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 37/40] ALSA: hda/realtek: Amend G634 quirk to enable rear speakers Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 38/40] ALSA: hda/realtek: Add quirk for ASUS ROG G614Jx Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 39/40] apparmor: fix use of strcpy in policy_unpack_test Sasha Levin
2023-07-24  1:31 ` [PATCH AUTOSEL 6.4 40/40] ALSA: hda/realtek: Add quirk for ASUS ROG GZ301V Sasha Levin

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=20230724013140.2327815-32-sashal@kernel.org \
    --to=sashal@kernel.org \
    --cc=almaz.alexandrovich@paragon-software.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=stable@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox