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:
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
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.
- 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:
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
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 */
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 */
*
* 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)
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.
if (!parse_options(vol, opt))
return -EINVAL;
-
+ ntfs_debug("Done.");
return 0;
}
!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
module_init(init_ntfs_fs)
module_exit(exit_ntfs_fs)
-