NTFS: More $LogFile handling fixes: when chkdsk has been run, it can leave the
authorAnton Altaparmakov <aia21@cantab.net>
Mon, 26 Sep 2005 09:48:54 +0000 (10:48 +0100)
committerAnton Altaparmakov <aia21@cantab.net>
Mon, 26 Sep 2005 09:48:54 +0000 (10:48 +0100)
      restart pages in the journal without multi sector transfer protection
      fixups (i.e. the update sequence array is empty and in fact does not
      exist).

Signed-off-by: Anton Altaparmakov <aia21@cantab.net>
fs/ntfs/ChangeLog
fs/ntfs/Makefile
fs/ntfs/logfile.c

index 574896f..83f3322 100644 (file)
@@ -22,14 +22,6 @@ ToDo/Notes:
        - Enable the code for setting the NT4 compatibility flag when we start
          making NTFS 1.2 specific modifications.
 
        - Enable the code for setting the NT4 compatibility flag when we start
          making NTFS 1.2 specific modifications.
 
-2.1.25-WIP
-
-       - Fix sparse warnings that have crept in over time.
-       - Change ntfs_cluster_free() to require a write locked runlist on entry
-         since we otherwise get into a lock reversal deadlock if a read locked
-         runlist is passed in. In the process also change it to take an ntfs
-         inode instead of a vfs inode as parameter.
-
 2.1.24 - Lots of bug fixes and support more clean journal states.
 
        - Support journals ($LogFile) which have been modified by chkdsk.  This
 2.1.24 - Lots of bug fixes and support more clean journal states.
 
        - Support journals ($LogFile) which have been modified by chkdsk.  This
@@ -37,7 +29,8 @@ ToDo/Notes:
          The Windows boot will run chkdsk and then reboot.  The user can then
          immediately boot into Linux rather than having to do a full Windows
          boot first before rebooting into Linux and we will recognize such a
          The Windows boot will run chkdsk and then reboot.  The user can then
          immediately boot into Linux rather than having to do a full Windows
          boot first before rebooting into Linux and we will recognize such a
-         journal and empty it as it is clean by definition.
+         journal and empty it as it is clean by definition.  Note, this only
+         works if chkdsk left the journal in an obviously clean state.
        - Support journals ($LogFile) with only one restart page as well as
          journals with two different restart pages.  We sanity check both and
          either use the only sane one or the more recent one of the two in the
        - Support journals ($LogFile) with only one restart page as well as
          journals with two different restart pages.  We sanity check both and
          either use the only sane one or the more recent one of the two in the
@@ -102,6 +95,13 @@ ToDo/Notes:
          my ways.
        - Fix various bugs in the runlist merging code.  (Based on libntfs
          changes by Richard Russon.)
          my ways.
        - Fix various bugs in the runlist merging code.  (Based on libntfs
          changes by Richard Russon.)
+       - Fix sparse warnings that have crept in over time.
+       - Change ntfs_cluster_free() to require a write locked runlist on entry
+         since we otherwise get into a lock reversal deadlock if a read locked
+         runlist is passed in. In the process also change it to take an ntfs
+         inode instead of a vfs inode as parameter.
+       - Fix the definition of the CHKD ntfs record magic.  It had an off by
+         two error causing it to be CHKB instead of CHKD.
 
 2.1.23 - Implement extension of resident files and make writing safe as well as
         many bug fixes, cleanups, and enhancements...
 
 2.1.23 - Implement extension of resident files and make writing safe as well as
         many bug fixes, cleanups, and enhancements...
index a3ce2c0..894b2b8 100644 (file)
@@ -6,7 +6,7 @@ ntfs-objs := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \
             index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \
             unistr.o upcase.o
 
             index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \
             unistr.o upcase.o
 
-EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.25-WIP\"
+EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.24\"
 
 ifeq ($(CONFIG_NTFS_DEBUG),y)
 EXTRA_CFLAGS += -DDEBUG
 
 ifeq ($(CONFIG_NTFS_DEBUG),y)
 EXTRA_CFLAGS += -DDEBUG
index 0173e95..0fd7029 100644 (file)
@@ -51,7 +51,8 @@ static BOOL ntfs_check_restart_page_header(struct inode *vi,
                RESTART_PAGE_HEADER *rp, s64 pos)
 {
        u32 logfile_system_page_size, logfile_log_page_size;
                RESTART_PAGE_HEADER *rp, s64 pos)
 {
        u32 logfile_system_page_size, logfile_log_page_size;
-       u16 usa_count, usa_ofs, usa_end, ra_ofs;
+       u16 ra_ofs, usa_count, usa_ofs, usa_end = 0;
+       BOOL have_usa = TRUE;
 
        ntfs_debug("Entering.");
        /*
 
        ntfs_debug("Entering.");
        /*
@@ -86,6 +87,14 @@ static BOOL ntfs_check_restart_page_header(struct inode *vi,
                                (int)sle16_to_cpu(rp->minor_ver));
                return FALSE;
        }
                                (int)sle16_to_cpu(rp->minor_ver));
                return FALSE;
        }
+       /*
+        * If chkdsk has been run the restart page may not be protected by an
+        * update sequence array.
+        */
+       if (ntfs_is_chkd_record(rp->magic) && !le16_to_cpu(rp->usa_count)) {
+               have_usa = FALSE;
+               goto skip_usa_checks;
+       }
        /* Verify the size of the update sequence array. */
        usa_count = 1 + (logfile_system_page_size >> NTFS_BLOCK_SIZE_BITS);
        if (usa_count != le16_to_cpu(rp->usa_count)) {
        /* Verify the size of the update sequence array. */
        usa_count = 1 + (logfile_system_page_size >> NTFS_BLOCK_SIZE_BITS);
        if (usa_count != le16_to_cpu(rp->usa_count)) {
@@ -102,6 +111,7 @@ static BOOL ntfs_check_restart_page_header(struct inode *vi,
                                "inconsistent update sequence array offset.");
                return FALSE;
        }
                                "inconsistent update sequence array offset.");
                return FALSE;
        }
+skip_usa_checks:
        /*
         * Verify the position of the restart area.  It must be:
         *      - aligned to 8-byte boundary,
        /*
         * Verify the position of the restart area.  It must be:
         *      - aligned to 8-byte boundary,
@@ -109,7 +119,8 @@ static BOOL ntfs_check_restart_page_header(struct inode *vi,
         *      - within the system page size.
         */
        ra_ofs = le16_to_cpu(rp->restart_area_offset);
         *      - within the system page size.
         */
        ra_ofs = le16_to_cpu(rp->restart_area_offset);
-       if (ra_ofs & 7 || ra_ofs < usa_end ||
+       if (ra_ofs & 7 || (have_usa ? ra_ofs < usa_end :
+                       ra_ofs < sizeof(RESTART_PAGE_HEADER)) ||
                        ra_ofs > logfile_system_page_size) {
                ntfs_error(vi->i_sb, "$LogFile restart page specifies "
                                "inconsistent restart area offset.");
                        ra_ofs > logfile_system_page_size) {
                ntfs_error(vi->i_sb, "$LogFile restart page specifies "
                                "inconsistent restart area offset.");
@@ -402,8 +413,12 @@ static int ntfs_check_and_load_restart_page(struct inode *vi,
                        idx++;
                } while (to_read > 0);
        }
                        idx++;
                } while (to_read > 0);
        }
-       /* Perform the multi sector transfer deprotection on the buffer. */
-       if (post_read_mst_fixup((NTFS_RECORD*)trp,
+       /*
+        * Perform the multi sector transfer deprotection on the buffer if the
+        * restart page is protected.
+        */
+       if ((!ntfs_is_chkd_record(trp->magic) || le16_to_cpu(trp->usa_count))
+                       && post_read_mst_fixup((NTFS_RECORD*)trp,
                        le32_to_cpu(rp->system_page_size))) {
                /*
                 * A multi sector tranfer error was detected.  We only need to
                        le32_to_cpu(rp->system_page_size))) {
                /*
                 * A multi sector tranfer error was detected.  We only need to
@@ -615,11 +630,16 @@ is_empty:
                 * Otherwise just throw it away.
                 */
                if (rstr2_lsn > rstr1_lsn) {
                 * Otherwise just throw it away.
                 */
                if (rstr2_lsn > rstr1_lsn) {
+                       ntfs_debug("Using second restart page as it is more "
+                                       "recent.");
                        ntfs_free(rstr1_ph);
                        rstr1_ph = rstr2_ph;
                        /* rstr1_lsn = rstr2_lsn; */
                        ntfs_free(rstr1_ph);
                        rstr1_ph = rstr2_ph;
                        /* rstr1_lsn = rstr2_lsn; */
-               } else
+               } else {
+                       ntfs_debug("Using first restart page as it is more "
+                                       "recent.");
                        ntfs_free(rstr2_ph);
                        ntfs_free(rstr2_ph);
+               }
                rstr2_ph = NULL;
        }
        /* All consistency checks passed. */
                rstr2_ph = NULL;
        }
        /* All consistency checks passed. */