The hibernation check in load_system_files() only converts the superblock to read-only under errors=remount-ro. With the default errors=continue (and with errors=panic), a hibernated volume is mounted read-write and the mount-time $LogFile emptying writes to it, although a hibernated volume must not be written to at all. Drop the on_errors term so that a hibernated volume, or a volume whose hibernation state cannot be determined, always mounts read-only. NVolErrors() is still recorded, so ntfs_reconfigure() keeps refusing remounts to read-write, and the $LogFile emptying is skipped by its !sb_rdonly() check. The check itself must not apply the errors= policy either: it runs before SB_RDONLY is set, and ntfs_lookup_inode_by_name() and ntfs_iget() call ntfs_error() internally on corruption or I/O errors, which under errors=panic would panic the machine before the read-only fallback has made its decision. Run the check with the super block temporarily marked read-only, which makes ntfs_handle_error() ignore any ntfs_error() issued on this path; the super block is not published yet at this point, so the temporary flag is not visible elsewhere. Restore read-write access only if the check succeeded and no errors were recorded earlier during the mount, e.g. when loading the LogFile, so that a volume with recorded errors stays read-only, matching what ntfs_reconfigure() enforces for remounts, and a message is logged for that case. Fixes: 6251f0b0de7d ("ntfs: update super block operations") Cc: stable@vger.kernel.org Signed-off-by: Hongling Zeng --- Change in v4: -Rework the errors=panic handling per review feedback. --- fs/ntfs/super.c | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index f4a73e45773d..473c76d2962f 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -1398,6 +1398,7 @@ static bool load_system_files(struct ntfs_volume *vol) struct ntfs_attr_search_ctx *ctx; struct restart_page_header *rp; int err; + bool temporary_ro = false; ntfs_debug("Entering."); /* Get mft mirror inode compare the contents of $MFT and $MFTMirr. */ @@ -1572,8 +1573,20 @@ static bool load_system_files(struct ntfs_volume *vol) * NVolErrors() without setting the dirty volume flag and mount * read-only. This will prevent read-write remounting and it will also * prevent all writes. + * + * The check runs with the super block temporarily marked read-only, so + * that ntfs_error() calls issued internally by ntfs_lookup_inode_by_name() + * and ntfs_iget() cannot trigger errors=panic before the read-only + * fallback has run. The super block is not published yet, so the flag + * is not visible elsewhere. */ + if (!sb_rdonly(sb)) { + sb->s_flags |= SB_RDONLY; + temporary_ro = true; + } err = check_windows_hibernation_status(vol); + if (temporary_ro && !err && !NVolErrors(vol)) + sb->s_flags &= ~SB_RDONLY; if (unlikely(err)) { static const char *es1a = "Failed to determine if Windows is hibernated"; static const char *es1b = "Windows is hibernated"; @@ -1581,12 +1594,27 @@ static bool load_system_files(struct ntfs_volume *vol) const char *es1; es1 = err < 0 ? es1a : es1b; - /* If a read-write mount, convert it to a read-only mount. */ - if (!sb_rdonly(sb) && vol->on_errors == ON_ERRORS_REMOUNT_RO) { + /* + * A Windows hibernation image is not a filesystem error, so + * this is a safety interlock rather than something the + * errors= policy may downgrade: always convert a read-write + * mount to read-only. + */ + if (!sb_rdonly(sb)) sb->s_flags |= SB_RDONLY; - ntfs_error(sb, "%s. Mounting read-only%s", es1, es2); - } + + ntfs_error(sb, "%s. Mounting read-only%s", es1, es2); NVolSetErrors(vol); + } else if (unlikely(temporary_ro && sb_rdonly(sb))) { + static const char *es1 = "Errors were recorded during mount"; + static const char *es2 = ". Run chkdsk."; + + /* + * Errors were recorded during the check or earlier, e.g. when + * loading the LogFile. Stay read-only, like ntfs_reconfigure() + * does for volumes with recorded errors. + */ + ntfs_error(sb, "%s. Mounting read-only%s", es1, es2); } /* If (still) a read-write mount, empty the logfile. */ -- 2.25.1