Commit 589ab626 authored by Anton Altaparmakov's avatar Anton Altaparmakov

NTFS: Read the journal ($LogFile) and determine if the volume has been shutdown cleanly

      and force a read-only mount if not (fs/ntfs/super.c and fs/ntfs/logfile.c).  This
      is a little bit of a crude check in that we only look at the restart areas and
      not at the actual log records so that there will be a very small number of cases
      where we 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.
parent ffa625ad
......@@ -38,11 +38,20 @@ ToDo:
- Determine the mft mirror size as the number of mirrored mft records
and store it in ntfs_volume->mftmirr_size (fs/ntfs/super.c).
- Load the mft mirror at mount time and compare the mft records stored
in it to the ones in the mft (fs/ntfs/super.c).
in it to the ones in the mft. Force a read-only mount if the two do
not match (fs/ntfs/super.c).
- Fix type casting related warnings on 64-bit architectures. Thanks
to Meelis Roos for reporting them.
- Move %L to %ll as %L is floating point and %ll is integer which is
what we want.
- Read the journal ($LogFile) and determine if the volume has been
shutdown cleanly and force a read-only mount if not (fs/ntfs/super.c
and fs/ntfs/logfile.c). This is a little bit of a crude check in
that we only look at the restart areas and not at the actual log
records so that there will be a very small number of cases where we
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.
2.1.7 - Enable NFS exporting of mounted NTFS volumes.
......
......@@ -2,15 +2,15 @@
obj-$(CONFIG_NTFS_FS) += ntfs.o
ntfs-objs := aops.o attrib.o compress.o debug.o dir.o file.o inode.o mft.o \
mst.o namei.o super.o sysctl.o unistr.o upcase.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\"
ifeq ($(CONFIG_NTFS_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
#EXTRA_CFLAGS += -DDEBUG
endif
ifeq ($(CONFIG_NTFS_RW),y)
EXTRA_CFLAGS += -DNTFS_RW
#EXTRA_CFLAGS += -DNTFS_RW
endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* malloc.h - NTFS kernel memory handling. Part of the Linux-NTFS project.
*
* Copyright (c) 2001,2002 Anton Altaparmakov.
* Copyright (c) 2001-2004 Anton Altaparmakov.
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
......@@ -38,7 +38,7 @@ static inline void *ntfs_malloc_nofs(unsigned long size)
{
if (likely(size <= PAGE_SIZE)) {
if (likely(size)) {
/* kmalloc() has per-CPU caches so if faster for now. */
/* kmalloc() has per-CPU caches so is faster for now. */
return kmalloc(PAGE_SIZE, GFP_NOFS);
/* return (void *)__get_free_page(GFP_NOFS |
__GFP_HIGHMEM); */
......@@ -61,4 +61,3 @@ static inline void ntfs_free(void *addr)
}
#endif /* _LINUX_NTFS_MALLOC_H */
/*
* mst.c - NTFS multi sector transfer protection handling code. Part of the
* Linux-NTFS project.
* Linux-NTFS project.
*
* Copyright (c) 2001 Anton Altaparmakov.
* Copyright (c) 2001-2004 Anton Altaparmakov.
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
......@@ -26,7 +26,7 @@
* post_read_mst_fixup - deprotect multi sector transfer protected data
* @b: pointer to the data to deprotect
* @size: size in bytes of @b
*
*
* Perform the necessary post read multi sector transfer fixup and detect the
* presence of incomplete multi sector transfers. - In that case, overwrite the
* magic of the ntfs record header being processed with "BAAD" (in memory only!)
......@@ -54,13 +54,13 @@ int post_read_mst_fixup(NTFS_RECORD *b, const u32 size)
usa_ofs + (usa_count * 2) > size ||
(size >> NTFS_BLOCK_SIZE_BITS) != usa_count)
return 0;
/* Position of usn in update sequence array. */
/* Position of usn in update sequence array. */
usa_pos = (u16*)b + usa_ofs/sizeof(u16);
/*
/*
* The update sequence number which has to be equal to each of the
* u16 values before they are fixed up. Note no need to care for
* endianness since we are comparing and moving data for on disk
* structures which means the data is consistent. - If it is
* structures which means the data is consistent. - If it is
* consistenty the wrong endianness it doesn't make any difference.
*/
usn = *usa_pos;
......@@ -68,18 +68,18 @@ int post_read_mst_fixup(NTFS_RECORD *b, const u32 size)
* Position in protected data of first u16 that needs fixing up.
*/
data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
/*
/*
* Check for incomplete multi sector transfer(s).
*/
while (usa_count--) {
if (*data_pos != usn) {
if (*data_pos != usn) {
/*
* Incomplete multi sector transfer detected! )-:
* Set the magic to "BAAD" and return failure.
* Note that magic_BAAD is already converted to le32.
*/
b->magic = magic_BAAD;
return -EINVAL;
return -EINVAL;
}
data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
}
......@@ -93,9 +93,9 @@ int post_read_mst_fixup(NTFS_RECORD *b, const u32 size)
* the usa into the data buffer.
*/
*data_pos = *(++usa_pos);
/* Increment position in data as well. */
/* Increment position in data as well. */
data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
}
}
return 0;
}
......@@ -103,7 +103,7 @@ int post_read_mst_fixup(NTFS_RECORD *b, const u32 size)
* pre_write_mst_fixup - apply multi sector transfer protection
* @b: pointer to the data to protect
* @size: size in bytes of @b
*
*
* Perform the necessary pre write multi sector transfer fixup on the data
* pointer to by @b of @size.
*
......@@ -126,7 +126,8 @@ int pre_write_mst_fixup(NTFS_RECORD *b, const u32 size)
u16 *usa_pos, *data_pos;
/* Sanity check + only fixup if it makes sense. */
if (!b || is_baad_record(b->magic) || is_hole_record(b->magic))
if (!b || ntfs_is_baad_record(b->magic) ||
ntfs_is_hole_record(b->magic))
return -EINVAL;
/* Setup the variables. */
usa_ofs = le16_to_cpu(b->usa_ofs);
......@@ -138,10 +139,10 @@ int pre_write_mst_fixup(NTFS_RECORD *b, const u32 size)
usa_ofs + (usa_count * 2) > size ||
(size >> NTFS_BLOCK_SIZE_BITS) != usa_count)
return -EINVAL;
/* Position of usn in update sequence array. */
/* Position of usn in update sequence array. */
usa_pos = (u16*)((u8*)b + usa_ofs);
/*
* Cyclically increment the update sequence number
* Cyclically increment the update sequence number
* (skipping 0 and -1, i.e. 0xffff).
*/
usn = le16_to_cpup(usa_pos) + 1;
......@@ -151,10 +152,10 @@ int pre_write_mst_fixup(NTFS_RECORD *b, const u32 size)
*usa_pos = usn;
/* Position in data of first u16 that needs fixing up. */
data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
/* Fixup all sectors. */
while (usa_count--) {
/* Fixup all sectors. */
while (usa_count--) {
/*
* Increment the position in the usa and save the
* Increment the position in the usa and save the
* original data from the data buffer into the usa.
*/
*(++usa_pos) = *data_pos;
......@@ -162,14 +163,14 @@ int pre_write_mst_fixup(NTFS_RECORD *b, const u32 size)
*data_pos = usn;
/* Increment position in data as well. */
data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
}
}
return 0;
}
/**
* post_write_mst_fixup - fast deprotect multi sector transfer protected data
* @b: pointer to the data to deprotect
*
*
* Perform the necessary post write multi sector transfer fixup, not checking
* for any errors, because we assume we have just used pre_write_mst_fixup(),
* thus the data will be fine or we would never have gotten here.
......@@ -181,13 +182,13 @@ void post_write_mst_fixup(NTFS_RECORD *b)
u16 usa_ofs = le16_to_cpu(b->usa_ofs);
u16 usa_count = le16_to_cpu(b->usa_count) - 1;
/* Position of usn in update sequence array. */
/* Position of usn in update sequence array. */
usa_pos = (u16*)b + usa_ofs/sizeof(u16);
/* Position in protected data of first u16 that needs fixing up. */
data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
/* Fixup all sectors. */
/* Fixup all sectors. */
while (usa_count--) {
/*
* Increment position in usa and restore original data from
......@@ -195,8 +196,7 @@ void post_write_mst_fixup(NTFS_RECORD *b)
*/
*data_pos = *(++usa_pos);
/* Increment position in data as well. */
/* Increment position in data as well. */
data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
}
}
}
......@@ -10,13 +10,13 @@
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
......@@ -77,10 +77,10 @@ extern struct inode_operations ntfs_empty_inode_ops;
/* Generic macros to convert pointers to values and vice versa. */
#ifndef p2n
#define p2n(p) ((ptrdiff_t)((ptrdiff_t*)(p)))
#define p2n(p) ((ptrdiff_t)((ptrdiff_t*)(p)))
#endif
#ifndef n2p
#define n2p(p) ((ptrdiff_t*)((ptrdiff_t)(p)))
#define n2p(p) ((ptrdiff_t*)((ptrdiff_t)(p)))
#endif
/**
......
......@@ -31,6 +31,7 @@
#include "ntfs.h"
#include "sysctl.h"
#include "logfile.h"
/* Number of mounted file systems which have compression enabled. */
static unsigned long ntfs_nr_compression_users;
......@@ -318,7 +319,7 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt)
*/
if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) {
if (NVolErrors(vol)) {
ntfs_error(sb, "Volume has errors and is read-only."
ntfs_error(sb, "Volume has errors and is read-only. "
"Cannot remount read-write.");
return -EROFS;
}
......@@ -728,7 +729,7 @@ static BOOL load_and_init_mft_mirror(ntfs_volume *vol)
if (IS_ERR(tmp_ino) || is_bad_inode(tmp_ino)) {
if (!IS_ERR(tmp_ino))
iput(tmp_ino);
ntfs_error(vol->sb, "Failed to load $MFTMirr.");
/* Caller will display error message. */
return FALSE;
}
/*
......@@ -773,6 +774,7 @@ static BOOL check_mft_mirror(ntfs_volume *vol)
run_list_element *rl, rl2[2];
int mrecs_per_page, i;
ntfs_debug("Entering.");
/* Compare contents of $MFT and $MFTMirr. */
mrecs_per_page = PAGE_CACHE_SIZE / vol->mft_record_size;
BUG_ON(!mrecs_per_page);
......@@ -808,7 +810,7 @@ static BOOL check_mft_mirror(ntfs_volume *vol)
++index;
}
/* Make sure the record is ok. */
if (is_baad_recordp(kmft)) {
if (ntfs_is_baad_recordp(kmft)) {
ntfs_error(sb, "Incomplete multi sector transfer "
"detected in mft record %i.", i);
mm_unmap_out:
......@@ -817,7 +819,7 @@ static BOOL check_mft_mirror(ntfs_volume *vol)
ntfs_unmap_page(mft_page);
return FALSE;
}
if (is_baad_recordp(kmirr)) {
if (ntfs_is_baad_recordp(kmirr)) {
ntfs_error(sb, "Incomplete multi sector transfer "
"detected in mft mirror record %i.", i);
goto mm_unmap_out;
......@@ -832,7 +834,7 @@ static BOOL check_mft_mirror(ntfs_volume *vol)
/* Compare the two records. */
if (memcmp(kmft, kmirr, bytes)) {
ntfs_error(sb, "$MFT and $MFTMirr (record %i) do not "
"match. Run ntfsfix or chkdsk.", i);
"match. Run ntfsfix or chkdsk.", i);
goto mm_unmap_out;
}
kmft += vol->mft_record_size;
......@@ -862,13 +864,42 @@ static BOOL check_mft_mirror(ntfs_volume *vol)
do {
if (rl2[i].vcn != rl[i].vcn || rl2[i].lcn != rl[i].lcn ||
rl2[i].length != rl[i].length) {
ntfs_error(sb, "$MFTMirr location mismatch. "
ntfs_error(sb, "$MFTMirr location mismatch. "
"Run chkdsk.");
up_read(&mirr_ni->run_list.lock);
return FALSE;
}
} while (rl2[i++].length);
up_read(&mirr_ni->run_list.lock);
ntfs_debug("Done.");
return TRUE;
}
/**
* load_and_check_logfile - load and check the logfile inode for a volume
* @vol: ntfs super block describing device whose logfile to load
*
* Return TRUE on success or FALSE on error.
*/
static BOOL load_and_check_logfile(ntfs_volume *vol)
{
struct inode *tmp_ino;
ntfs_debug("Entering.");
tmp_ino = ntfs_iget(vol->sb, FILE_LogFile);
if (IS_ERR(tmp_ino) || is_bad_inode(tmp_ino)) {
if (!IS_ERR(tmp_ino))
iput(tmp_ino);
/* Caller will display error message. */
return FALSE;
}
if (!ntfs_check_logfile(tmp_ino)) {
iput(tmp_ino);
/* ntfs_check_logfile() will have displayed error output. */
return FALSE;
}
vol->logfile_ino = tmp_ino;
ntfs_debug("Done.");
return TRUE;
}
......@@ -926,7 +957,7 @@ static BOOL load_and_init_upcase(ntfs_volume *vol)
goto read_partial_upcase_page;
}
vol->upcase_len = ino->i_size >> UCHAR_T_SIZE_BITS;
ntfs_debug("Read %lu bytes from $UpCase (expected %u bytes).",
ntfs_debug("Read %llu bytes from $UpCase (expected %u bytes).",
ino->i_size, 64 * 1024 * sizeof(uchar_t));
iput(ino);
down(&ntfs_lock);
......@@ -1094,25 +1125,42 @@ static BOOL load_system_files(ntfs_volume *vol)
unmap_mft_record(NTFS_I(vol->vol_ino));
printk(KERN_INFO "NTFS volume version %i.%i.\n", vol->major_ver,
vol->minor_ver);
#ifdef NTFS_RW
/*
* Get the inode for the logfile and empty it if this is a read-write
* mount.
* Get the inode for the logfile, check it and determine if the volume
* was shutdown cleanly.
*/
// TODO: vol->logfile_ino = ;
// TODO: Cleanup for error case at end of function.
tmp_ino = ntfs_iget(sb, FILE_LogFile);
if (IS_ERR(tmp_ino) || is_bad_inode(tmp_ino)) {
if (!IS_ERR(tmp_ino))
iput(tmp_ino);
ntfs_error(sb, "Failed to load $LogFile.");
// FIMXE: We only want to empty the thing so pointless bailing
// out. Can recover/ignore.
goto iput_vol_err_out;
if (!load_and_check_logfile(vol) ||
!ntfs_is_logfile_clean(vol->logfile_ino)) {
static const char *es1 = "Failed to load $LogFile";
static const char *es2 = "$LogFile is not clean";
static const char *es3 = ". Mount in Windows.";
/* If a read-write mount, convert it to a read-only mount. */
if (!(sb->s_flags & MS_RDONLY)) {
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",
!vol->logfile_ino ? es1 : es2,
es3);
goto iput_logfile_err_out;
}
sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME;
ntfs_error(sb, "%s. Mounting read-only%s",
!vol->logfile_ino ? es1 : es2, es3);
} else
ntfs_warning(sb, "%s. Will not be able to remount "
"read-write%s",
!vol->logfile_ino ? es1 : es2, es3);
/* 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.
iput(tmp_ino);
#endif
/*
* Get the inode for the attribute definitions file and parse the
* attribute definitions.
......@@ -1122,7 +1170,7 @@ static BOOL load_system_files(ntfs_volume *vol)
if (!IS_ERR(tmp_ino))
iput(tmp_ino);
ntfs_error(sb, "Failed to load $AttrDef.");
goto iput_vol_err_out;
goto iput_logfile_err_out;
}
// FIXME: Parse the attribute definitions.
iput(tmp_ino);
......@@ -1132,7 +1180,7 @@ static BOOL load_system_files(ntfs_volume *vol)
if (!IS_ERR(vol->root_ino))
iput(vol->root_ino);
ntfs_error(sb, "Failed to load root directory.");
goto iput_vol_err_out;
goto iput_logfile_err_out;
}
/* If on NTFS versions before 3.0, we are done. */
if (vol->major_ver < 3)
......@@ -1166,7 +1214,11 @@ static BOOL load_system_files(ntfs_volume *vol)
iput(vol->secure_ino);
iput_root_err_out:
iput(vol->root_ino);
iput_vol_err_out:
iput_logfile_err_out:
#ifdef NTFS_RW
if (vol->logfile_ino)
iput(vol->logfile_ino);
#endif /* NTFS_RW */
iput(vol->vol_ino);
iput_lcnbmp_err_out:
iput(vol->lcnbmp_ino);
......
......@@ -2,20 +2,20 @@
* types.h - Defines for NTFS Linux kernel driver specific types.
* Part of the Linux-NTFS project.
*
* Copyright (c) 2001,2002 Anton Altaparmakov.
* Copyright (c) 2001-2004 Anton Altaparmakov.
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
......@@ -23,14 +23,6 @@
#ifndef _LINUX_NTFS_TYPES_H
#define _LINUX_NTFS_TYPES_H
#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
#define SN(X) X /* Struct Name */
#define SC(P,N) P.N /* ShortCut: Prefix, Name */
#else
#define SN(X)
#define SC(P,N) N
#endif
/* 2-byte Unicode character type. */
typedef u16 uchar_t;
#define UCHAR_T_SIZE_BITS 1
......@@ -42,15 +34,22 @@ typedef u16 uchar_t;
typedef s64 VCN;
typedef s64 LCN;
/*
* The NTFS journal $LogFile uses log sequence numbers which are signed 64-bit
* values. We define our own type LSN, to allow for type checking and better
* code readability.
*/
typedef s64 LSN;
/**
* run_list_element - in memory vcn to lcn mapping array element
* @vcn: starting vcn of the current array element
* @lcn: starting lcn of the current array element
* @length: length in clusters of the current array element
*
*
* The last vcn (in fact the last vcn + 1) is reached when length == 0.
*
* When lcn == -1 this means that the count vcns starting at vcn are not
*
* When lcn == -1 this means that the count vcns starting at vcn are not
* physically allocated (i.e. this is a hole / data is sparse).
*/
typedef struct { /* In memory vcn to lcn mapping structure element. */
......@@ -63,7 +62,7 @@ typedef struct { /* In memory vcn to lcn mapping structure element. */
* run_list - in memory vcn to lcn mapping array including a read/write lock
* @rl: pointer to an array of run list elements
* @lock: read/write spinlock for serializing access to @rl
*
*
*/
typedef struct {
run_list_element *rl;
......@@ -81,4 +80,3 @@ typedef enum {
} IGNORE_CASE_BOOL;
#endif /* _LINUX_NTFS_TYPES_H */
......@@ -116,6 +116,7 @@ typedef enum {
create filenames in the POSIX namespace.
Otherwise be case insensitive and create
file names in WIN32 namespace. */
NV_LogFileEmpty, /* 1: $LogFile journal is empty. */
} ntfs_volume_flags;
/*
......@@ -140,5 +141,6 @@ static inline void NVolClear##flag(ntfs_volume *vol) \
NVOL_FNS(Errors)
NVOL_FNS(ShowSystemFiles)
NVOL_FNS(CaseSensitive)
NVOL_FNS(LogFileEmpty)
#endif /* _LINUX_NTFS_VOLUME_H */
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