]> git.hungrycats.org Git - linux/commitdiff
NTFS: 2.1.8 release - If the $LogFile indicates a clean shutdown and a
authorAnton Altaparmakov <aia21@cantab.net>
Fri, 7 May 2004 18:55:19 +0000 (19:55 +0100)
committerAnton Altaparmakov <aia21@cantab.net>
Fri, 7 May 2004 18:55:19 +0000 (19:55 +0100)
      read-write (re)mount is requested, empty $LogFile by overwriting it
      with 0xff bytes to ensure that Windows cannot cause data corruption
      by replaying a stale journal after Linux has written to the volume.

Documentation/filesystems/ntfs.txt
fs/ntfs/ChangeLog
fs/ntfs/Makefile
fs/ntfs/logfile.c
fs/ntfs/logfile.h
fs/ntfs/super.c

index fda6bf8882d3f529a4ed93f7eaff86d3162de8a3..556f8517c895dc1f5849d29c94aa0731464632a0 100644 (file)
@@ -273,6 +273,18 @@ ChangeLog
 
 Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
 
+2.1.8:
+       - Read the $MFT mirror and compare it to the $MFT and if the two do not
+         match, force a read-only mount and do not allow read-write remounts.
+       - Read and parse the $LogFile journal and if it indicates that the
+         volume was not shutdown cleanly, force a read-only mount and do not
+         allow read-write remounts.  If the $LogFile indicates a clean
+         shutdown and a read-write (re)mount is requested, empty $LogFile to
+         ensure that Windows cannot cause data corruption by replaying a stale
+         journal after Linux has written to the volume.
+       - Improve time handling so that the NTFS time is fully preserved when
+         converted to kernel time and only up to 99 nano-seconds are lost when
+         kernel time is converted to NTFS time.
 2.1.7:
        - Enable NFS exporting of mounted NTFS volumes.
 2.1.6:
index 0e3e151ac19cf13d457560efca7dc8cbec93a06c..668900d80ec61de32d7090aff9c55699a4ed8611 100644 (file)
@@ -19,7 +19,7 @@ ToDo:
          sufficient for synchronisation here. We then just need to make sure
          ntfs_readpage/writepage/truncate interoperate properly with us.
 
-2.1.8-WIP
+2.1.8 - Handle $MFT mirror and $LogFile, improve time ihandling, and cleanups.
 
        - Use get_bh() instead of manual atomic_inc() in fs/ntfs/compress.c.
        - Modify fs/ntfs/time.c::ntfs2utc(), get_current_ntfs_time(), and
@@ -52,6 +52,10 @@ ToDo:
          think that a volume is dirty when in fact it is clean.  This should
          only affect volumes that have not been shutdown cleanly and did not
          have any pending, non-check-pointed i/o.
+       - If the $LogFile indicates a clean shutdown and a read-write (re)mount
+         is requested, empty $LogFile by overwriting it with 0xff bytes to
+         ensure that Windows cannot cause data corruption by replaying a stale
+         journal after Linux has written to the volume.
 
 2.1.7 - Enable NFS exporting of mounted NTFS volumes.
 
@@ -661,7 +665,7 @@ tng-0.0.7 - 13/02/2002 - The driver is now feature complete for read-only!
        - Change parameters to find_attr() and lookup_attr(). We no longer
          pass in the upcase table and its length. These can be gotten from
          ctx->ntfs_ino->vol->upcase{_len}. Update all callers.
-       - Cleanups in attrib.c. 
+       - Cleanups in attrib.c.
        - Implement merging of run lists, attrib.c::merge_run_lists() and its
          helpers. (Richard Russon)
        - Attribute lists part 2, attribute extents and multi part run lists:
index 0bb0a01cba730cb405b3c2bf5cfb27297a83e4d2..9601080b9070a3a9726933983628d0c1077ad32b 100644 (file)
@@ -5,7 +5,7 @@ obj-$(CONFIG_NTFS_FS) += ntfs.o
 ntfs-objs := aops.o attrib.o compress.o debug.o dir.o file.o inode.o logfile.o \
             mft.o mst.o namei.o super.o sysctl.o unistr.o upcase.o
 
-EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.8-WIP\"
+EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.8\"
 
 ifeq ($(CONFIG_NTFS_DEBUG),y)
 EXTRA_CFLAGS += -DDEBUG
index 868d7207936b7f8ea0ada55b7a1cdf707aeab38f..6b9547c75ddf66fe88cc18af7376fabcb532d8fe 100644 (file)
@@ -662,4 +662,76 @@ err_out:
        return FALSE;
 }
 
+/**
+ * ntfs_empty_logfile - empty the contents of the $LogFile journal
+ * @log_vi:    struct inode of loaded journal $LogFile to empty
+ *
+ * Empty the contents of the $LogFile journal @log_vi and return TRUE on
+ * success FALSE on error.
+ *
+ * This function assumes that the $LogFile journal has already been consistency
+ * checked by a call to ntfs_check_logfile() and that ntfs_is_logfile_clean()
+ * has been used to ensure that the $LogFile is clean.
+ */
+BOOL ntfs_empty_logfile(struct inode *log_vi)
+{
+       ntfs_volume *vol = NTFS_SB(log_vi->i_sb);
+       struct address_space *mapping;
+       pgoff_t idx, end;
+
+       ntfs_debug("Entering.");
+       if (NVolLogFileEmpty(vol))
+               goto done;
+       mapping = log_vi->i_mapping;
+       end = (log_vi->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+       for (idx = 0; idx < end; ++idx) {
+               struct page *page;
+               u8 *kaddr;
+
+               /* Find or create the current page.  (The page is locked.) */
+               page = grab_cache_page(mapping, idx);
+               if (unlikely(!page)) {
+                       ntfs_error(vol->sb, "Insufficient memory to grab "
+                                       "$LogFile page (index %lu).", idx);
+                       return FALSE;
+               }
+               /*
+                * Set all bytes in the page to 0xff.  It doesn't matter if we
+                * go beyond i_size, because ntfs_writepage() will take care of
+                * that for us.
+                */
+               kaddr = (u8*)kmap_atomic(page, KM_USER0);
+               memset(kaddr, 0xff, PAGE_CACHE_SIZE);
+               flush_dcache_page(page);
+               kunmap_atomic(kaddr, KM_USER0);
+               /*
+                * If the page has buffers, mark them uptodate since buffer
+                * state and not page state is definitive in 2.6 kernels.
+                */
+               if (page_has_buffers(page)) {
+                       struct buffer_head *bh, *head;
+
+                       bh = head = page_buffers(page);
+                       do {
+                               set_buffer_uptodate(bh);
+                       } while ((bh = bh->b_this_page) != head);
+               }
+               /* Now that buffers are uptodate, set the page uptodate, too. */
+               SetPageUptodate(page);
+               /*
+                * Set the page and all its buffers dirty and mark the inode
+                * dirty, too. The VM will write the page later on.
+                */
+               set_page_dirty(page);
+               /* Finally unlock and release the page. */
+               unlock_page(page);
+               page_cache_release(page);
+       }
+       /* We set the flag so we do not clear the log file again on remount. */
+       NVolSetLogFileEmpty(vol);
+done:
+       ntfs_debug("Done.");
+       return TRUE;
+}
+
 #endif /* NTFS_RW */
index 4ebec5e47edbc45cd0fe64151c7ecfba0bbf4c3e..abfe512427240165be5ef8e5097670c9dbb3b755 100644 (file)
@@ -298,6 +298,8 @@ extern BOOL ntfs_check_logfile(struct inode *log_vi);
 
 extern BOOL ntfs_is_logfile_clean(struct inode *log_vi);
 
+extern BOOL ntfs_empty_logfile(struct inode *log_vi);
+
 #endif /* NTFS_RW */
 
 #endif /* _LINUX_NTFS_LOGFILE_H */
index 973be10d97650c02ef68f6a52bb2a2474e9c578e..e5aa70018a125900eeeb99bb19398aa060e55deb 100644 (file)
@@ -299,8 +299,8 @@ needs_val:
  *
  * Change the mount options of an already mounted ntfs filesystem.
  *
- * NOTE: The VFS set the @sb->s_flags remount flags to @flags after
- * ntfs_remount() returns successfully (i.e. returns 0). Otherwise,
+ * NOTE:  The VFS sets the @sb->s_flags remount flags to @flags after
+ * ntfs_remount() returns successfully (i.e. returns 0).  Otherwise,
  * @sb->s_flags are not changed.
  */
 static int ntfs_remount(struct super_block *sb, int *flags, char *opt)
@@ -308,26 +308,33 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt)
        ntfs_volume *vol = NTFS_SB(sb);
 
        ntfs_debug("Entering with remount options string: %s", opt);
-
 #ifndef NTFS_RW
        /* For read-only compiled driver, enforce all read-only flags. */
        *flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME;
-#else
+#else /* ! NTFS_RW */
        /*
         * For the read-write compiled driver, if we are remounting read-write,
-        * make sure there aren't any volume errors.
+        * make sure there aren't any volume errors and empty the lofgile.
         */
        if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) {
+               static const char *es = ".  Cannot remount read-write.";
+
                if (NVolErrors(vol)) {
-                       ntfs_error(sb, "Volume has errors and is read-only. "
-                                       "Cannot remount read-write.");
+                       ntfs_error(sb, "Volume has errors and is read-only%s",
+                                       es);
+                       return -EROFS;
+               }
+               if (!ntfs_empty_logfile(vol->logfile_ino)) {
+                       ntfs_error(sb, "Failed to empty journal $LogFile%s",
+                                       es);
+                       NVolSetErrors(vol);
                        return -EROFS;
                }
        }
        // TODO:  For now we enforce no atime and dir atime updates as they are
        // not implemented.
        *flags |= MS_NOATIME | MS_NODIRATIME;
-#endif
+#endif /* ! NTFS_RW */
 
        // FIXME/TODO: If left like this we will have problems with rw->ro and
        // ro->rw, as well as with sync->async and vice versa remounts.
@@ -345,7 +352,7 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt)
 
        if (!parse_options(vol, opt))
                return -EINVAL;
-
+       ntfs_debug("Done.");
        return 0;
 }
 
@@ -1156,10 +1163,25 @@ get_ctx_vol_failed:
                                        !vol->logfile_ino ? es1 : es2, es3);
                /* This will prevent a read-write remount. */
                NVolSetErrors(vol);
+       /* If a read-write mount, empty the logfile. */
+       } else if (!(sb->s_flags & MS_RDONLY) &&
+                       !ntfs_empty_logfile(vol->logfile_ino)) {
+               static const char *es1 = "Failed to empty $LogFile";
+               static const char *es2 = ".  Mount in Windows.";
+
+               /* Convert to a read-only mount. */
+               if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO |
+                               ON_ERRORS_CONTINUE))) {
+                       ntfs_error(sb, "%s and neither on_errors=continue nor "
+                                       "on_errors=remount-ro was specified%s",
+                                       es1, es2);
+                       goto iput_logfile_err_out;
+               }
+               sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME;
+               ntfs_error(sb, "%s.  Mounting read-only%s", es1, es2);
+               /* This will prevent a read-write remount. */
+               NVolSetErrors(vol);
        }
-       // FIXME: Empty the logfile, but only if not read-only.
-       // FIXME: What happens if someone remounts rw? We need to empty the file
-       // then. We need a flag to tell us whether we have done it already.
 #endif
        /*
         * Get the inode for the attribute definitions file and parse the
@@ -2124,4 +2146,3 @@ MODULE_PARM_DESC(debug_msgs, "Enable debug messages.");
 
 module_init(init_ntfs_fs)
 module_exit(exit_ntfs_fs)
-