Commit ec44dec7 authored by Anton Altaparmakov's avatar Anton Altaparmakov

NTFS: 2.1.8 release - 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.
parent 1660b1af
......@@ -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:
......
......@@ -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.
......
......@@ -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
......
......@@ -662,4 +662,76 @@ BOOL ntfs_is_logfile_clean(struct inode *log_vi)
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 */
......@@ -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 */
......@@ -299,7 +299,7 @@ static BOOL parse_options(ntfs_volume *vol, char *opt)
*
* Change the mount options of an already mounted ntfs filesystem.
*
* NOTE: The VFS set the @sb->s_flags remount flags to @flags after
* 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.
*/
......@@ -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 @@ static BOOL load_system_files(ntfs_volume *vol)
!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)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment