Skip to content

Commit 6a4cd3e

Browse files
fs/ntfs3: Alternative boot if primary boot is corrupted
Some code refactoring added also. Signed-off-by: Konstantin Komarov <[email protected]>
1 parent e0f363a commit 6a4cd3e

File tree

1 file changed

+71
-27
lines changed

1 file changed

+71
-27
lines changed

fs/ntfs3/super.c

Lines changed: 71 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -724,18 +724,21 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
724724
struct MFT_REC *rec;
725725
u16 fn, ao;
726726
u8 cluster_bits;
727+
u32 boot_off = 0;
728+
const char *hint = "Primary boot";
727729

728730
sbi->volume.blocks = dev_size >> PAGE_SHIFT;
729731

730732
bh = ntfs_bread(sb, 0);
731733
if (!bh)
732734
return -EIO;
733735

736+
check_boot:
734737
err = -EINVAL;
735-
boot = (struct NTFS_BOOT *)bh->b_data;
738+
boot = (struct NTFS_BOOT *)Add2Ptr(bh->b_data, boot_off);
736739

737740
if (memcmp(boot->system_id, "NTFS ", sizeof("NTFS ") - 1)) {
738-
ntfs_err(sb, "Boot's signature is not NTFS.");
741+
ntfs_err(sb, "%s signature is not NTFS.", hint);
739742
goto out;
740743
}
741744

@@ -748,14 +751,16 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
748751
boot->bytes_per_sector[0];
749752
if (boot_sector_size < SECTOR_SIZE ||
750753
!is_power_of_2(boot_sector_size)) {
751-
ntfs_err(sb, "Invalid bytes per sector %u.", boot_sector_size);
754+
ntfs_err(sb, "%s: invalid bytes per sector %u.", hint,
755+
boot_sector_size);
752756
goto out;
753757
}
754758

755759
/* cluster size: 512, 1K, 2K, 4K, ... 2M */
756760
sct_per_clst = true_sectors_per_clst(boot);
757761
if ((int)sct_per_clst < 0 || !is_power_of_2(sct_per_clst)) {
758-
ntfs_err(sb, "Invalid sectors per cluster %u.", sct_per_clst);
762+
ntfs_err(sb, "%s: invalid sectors per cluster %u.", hint,
763+
sct_per_clst);
759764
goto out;
760765
}
761766

@@ -771,8 +776,8 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
771776
if (mlcn * sct_per_clst >= sectors || mlcn2 * sct_per_clst >= sectors) {
772777
ntfs_err(
773778
sb,
774-
"Start of MFT 0x%llx (0x%llx) is out of volume 0x%llx.",
775-
mlcn, mlcn2, sectors);
779+
"%s: start of MFT 0x%llx (0x%llx) is out of volume 0x%llx.",
780+
hint, mlcn, mlcn2, sectors);
776781
goto out;
777782
}
778783

@@ -784,7 +789,7 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
784789

785790
/* Check MFT record size. */
786791
if (record_size < SECTOR_SIZE || !is_power_of_2(record_size)) {
787-
ntfs_err(sb, "Invalid bytes per MFT record %u (%d).",
792+
ntfs_err(sb, "%s: invalid bytes per MFT record %u (%d).", hint,
788793
record_size, boot->record_size);
789794
goto out;
790795
}
@@ -801,13 +806,13 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
801806

802807
/* Check index record size. */
803808
if (sbi->index_size < SECTOR_SIZE || !is_power_of_2(sbi->index_size)) {
804-
ntfs_err(sb, "Invalid bytes per index %u(%d).", sbi->index_size,
805-
boot->index_size);
809+
ntfs_err(sb, "%s: invalid bytes per index %u(%d).", hint,
810+
sbi->index_size, boot->index_size);
806811
goto out;
807812
}
808813

809814
if (sbi->index_size > MAXIMUM_BYTES_PER_INDEX) {
810-
ntfs_err(sb, "Unsupported bytes per index %u.",
815+
ntfs_err(sb, "%s: unsupported bytes per index %u.", hint,
811816
sbi->index_size);
812817
goto out;
813818
}
@@ -834,7 +839,7 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
834839

835840
/* Compare boot's cluster and sector. */
836841
if (sbi->cluster_size < boot_sector_size) {
837-
ntfs_err(sb, "Invalid bytes per cluster (%u).",
842+
ntfs_err(sb, "%s: invalid bytes per cluster (%u).", hint,
838843
sbi->cluster_size);
839844
goto out;
840845
}
@@ -930,7 +935,46 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
930935

931936
err = 0;
932937

938+
if (bh->b_blocknr && !sb_rdonly(sb)) {
939+
/*
940+
* Alternative boot is ok but primary is not ok.
941+
* Update primary boot.
942+
*/
943+
struct buffer_head *bh0 = sb_getblk(sb, 0);
944+
if (bh0) {
945+
if (buffer_locked(bh0))
946+
__wait_on_buffer(bh0);
947+
948+
lock_buffer(bh0);
949+
memcpy(bh0->b_data, boot, sizeof(*boot));
950+
set_buffer_uptodate(bh0);
951+
mark_buffer_dirty(bh0);
952+
unlock_buffer(bh0);
953+
if (!sync_dirty_buffer(bh0))
954+
ntfs_warn(sb, "primary boot is updated");
955+
put_bh(bh0);
956+
}
957+
}
958+
933959
out:
960+
if (err == -EINVAL && !bh->b_blocknr && dev_size > PAGE_SHIFT) {
961+
u32 block_size = min_t(u32, sector_size, PAGE_SIZE);
962+
u64 lbo = dev_size - sizeof(*boot);
963+
964+
/*
965+
* Try alternative boot (last sector)
966+
*/
967+
brelse(bh);
968+
969+
sb_set_blocksize(sb, block_size);
970+
bh = ntfs_bread(sb, lbo >> blksize_bits(block_size));
971+
if (!bh)
972+
return -EINVAL;
973+
974+
boot_off = lbo & (block_size - 1);
975+
hint = "Alternative boot";
976+
goto check_boot;
977+
}
934978
brelse(bh);
935979

936980
return err;
@@ -955,6 +999,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
955999
struct ATTR_DEF_ENTRY *t;
9561000
u16 *shared;
9571001
struct MFT_REF ref;
1002+
bool ro = sb_rdonly(sb);
9581003

9591004
ref.high = 0;
9601005

@@ -1035,6 +1080,10 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
10351080
sbi->volume.minor_ver = info->minor_ver;
10361081
sbi->volume.flags = info->flags;
10371082
sbi->volume.ni = ni;
1083+
if (info->flags & VOLUME_FLAG_DIRTY) {
1084+
sbi->volume.real_dirty = true;
1085+
ntfs_info(sb, "It is recommened to use chkdsk.");
1086+
}
10381087

10391088
/* Load $MFTMirr to estimate recs_mirr. */
10401089
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)
10691118

10701119
iput(inode);
10711120

1072-
if (sbi->flags & NTFS_FLAGS_NEED_REPLAY) {
1073-
if (!sb_rdonly(sb)) {
1074-
ntfs_warn(sb,
1075-
"failed to replay log file. Can't mount rw!");
1076-
err = -EINVAL;
1077-
goto out;
1078-
}
1079-
} else if (sbi->volume.flags & VOLUME_FLAG_DIRTY) {
1080-
if (!sb_rdonly(sb) && !options->force) {
1081-
ntfs_warn(
1082-
sb,
1083-
"volume is dirty and \"force\" flag is not set!");
1084-
err = -EINVAL;
1085-
goto out;
1086-
}
1121+
if ((sbi->flags & NTFS_FLAGS_NEED_REPLAY) && !ro) {
1122+
ntfs_warn(sb, "failed to replay log file. Can't mount rw!");
1123+
err = -EINVAL;
1124+
goto out;
1125+
}
1126+
1127+
if ((sbi->volume.flags & VOLUME_FLAG_DIRTY) && !ro && !options->force) {
1128+
ntfs_warn(sb, "volume is dirty and \"force\" flag is not set!");
1129+
err = -EINVAL;
1130+
goto out;
10871131
}
10881132

10891133
/* Load $MFT. */
@@ -1173,7 +1217,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
11731217

11741218
bad_len += len;
11751219
bad_frags += 1;
1176-
if (sb_rdonly(sb))
1220+
if (ro)
11771221
continue;
11781222

11791223
if (wnd_set_used_safe(&sbi->used.bitmap, lcn, len, &tt) || tt) {

0 commit comments

Comments
 (0)