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
......@@ -113,36 +113,64 @@ typedef struct {
* records (like mft records for example).
*/
typedef enum {
magic_BAAD = const_cpu_to_le32(0x44414142), /* BAAD == corrupt record */
magic_CHKD = const_cpu_to_le32(0x424b4843), /* CHKD == chkdsk ??? */
magic_FILE = const_cpu_to_le32(0x454c4946), /* FILE == mft entry */
magic_HOLE = const_cpu_to_le32(0x454c4f48), /* HOLE == ? (NTFS 3.0+?) */
magic_INDX = const_cpu_to_le32(0x58444e49), /* INDX == index buffer */
/* Found in $MFT/$DATA. */
magic_FILE = const_cpu_to_le32(0x454c4946), /* Mft entry. */
magic_INDX = const_cpu_to_le32(0x58444e49), /* Index buffer. */
magic_HOLE = const_cpu_to_le32(0x454c4f48), /* ? (NTFS 3.0+?) */
/* Found in $LogFile/$DATA. */
magic_RSTR = const_cpu_to_le32(0x52545352), /* Restart page. */
magic_RCRD = const_cpu_to_le32(0x44524352), /* Log record page. */
/* Found in $LogFile/$DATA. (May be found in $MFT/$DATA, also?) */
magic_CHKD = const_cpu_to_le32(0x424b4843), /* Modified by chkdsk. */
/* Found in all ntfs record containing records. */
magic_BAAD = const_cpu_to_le32(0x44414142), /* Failed multi sector
transfer was detected. */
/*
* Found in $LogFile/$DATA when a page is full or 0xff bytes and is
* thus not initialized. User has to initialize the page before using
* it.
*/
magic_empty = const_cpu_to_le32(0xffffffff),/* Record is empty and has
to be initialized before
it can be used. */
} NTFS_RECORD_TYPES;
/*
* Generic magic comparison macros. Finally found a use for the ## preprocessor
* operator! (-8
*/
#define is_magic(x, m) ( (u32)(x) == magic_##m )
#define is_magicp(p, m) ( *(u32*)(p) == magic_##m )
#define ntfs_is_magic(x, m) ( (u32)(x) == magic_##m )
#define ntfs_is_magicp(p, m) ( *(u32*)(p) == magic_##m )
/*
* Specialised magic comparison macros.
* Specialised magic comparison macros for the NTFS_RECORD_TYPES defined above.
*/
#define is_baad_record(x) ( is_magic (x, BAAD) )
#define is_baad_recordp(p) ( is_magicp(p, BAAD) )
#define is_chkd_record(x) ( is_magic (x, CHKD) )
#define is_chkd_recordp(p) ( is_magicp(p, CHKD) )
#define is_file_record(x) ( is_magic (x, FILE) )
#define is_file_recordp(p) ( is_magicp(p, FILE) )
#define is_hole_record(x) ( is_magic (x, HOLE) )
#define is_hole_recordp(p) ( is_magicp(p, HOLE) )
#define is_indx_record(x) ( is_magic (x, INDX) )
#define is_indx_recordp(p) ( is_magicp(p, INDX) )
#define ntfs_is_file_record(x) ( ntfs_is_magic (x, FILE) )
#define ntfs_is_file_recordp(p) ( ntfs_is_magicp(p, FILE) )
#define ntfs_is_mft_record(x) ( ntfs_is_file_record(x) )
#define ntfs_is_mft_recordp(p) ( ntfs_is_file_recordp(p) )
#define ntfs_is_indx_record(x) ( ntfs_is_magic (x, INDX) )
#define ntfs_is_indx_recordp(p) ( ntfs_is_magicp(p, INDX) )
#define ntfs_is_hole_record(x) ( ntfs_is_magic (x, HOLE) )
#define ntfs_is_hole_recordp(p) ( ntfs_is_magicp(p, HOLE) )
#define ntfs_is_rstr_record(x) ( ntfs_is_magic (x, RSTR) )
#define ntfs_is_rstr_recordp(p) ( ntfs_is_magicp(p, RSTR) )
#define ntfs_is_rcrd_record(x) ( ntfs_is_magic (x, RCRD) )
#define ntfs_is_rcrd_recordp(p) ( ntfs_is_magicp(p, RCRD) )
#define ntfs_is_chkd_record(x) ( ntfs_is_magic (x, CHKD) )
#define ntfs_is_chkd_recordp(p) ( ntfs_is_magicp(p, CHKD) )
#define ntfs_is_baad_record(x) ( ntfs_is_magic (x, BAAD) )
#define ntfs_is_baad_recordp(p) ( ntfs_is_magicp(p, BAAD) )
#define is_mft_record(x) ( is_file_record(x) )
#define is_mft_recordp(p) ( is_file_recordp(p) )
#define ntfs_is_empty_record(x) ( ntfs_is_magic (x, empty) )
#define ntfs_is_empty_recordp(p) ( ntfs_is_magicp(p, empty) )
/*
* The Update Sequence Array (usa) is an array of the u16 values which belong
......@@ -1513,49 +1541,46 @@ typedef enum {
/*
* The security descriptor control flags (16-bit).
*
* SE_OWNER_DEFAULTED - This boolean flag, when set, indicates that the
* SID pointed to by the Owner field was provided by a
* defaulting mechanism rather than explicitly provided by the
* original provider of the security descriptor. This may
* affect the treatment of the SID with respect to inheritence
* of an owner.
*
* SE_GROUP_DEFAULTED - This boolean flag, when set, indicates that the
* SID in the Group field was provided by a defaulting mechanism
* rather than explicitly provided by the original provider of
* the security descriptor. This may affect the treatment of
* the SID with respect to inheritence of a primary group.
*
* SE_DACL_PRESENT - This boolean flag, when set, indicates that the
* security descriptor contains a discretionary ACL. If this
* flag is set and the Dacl field of the SECURITY_DESCRIPTOR is
* null, then a null ACL is explicitly being specified.
*
* SE_DACL_DEFAULTED - This boolean flag, when set, indicates that the
* ACL pointed to by the Dacl field was provided by a defaulting
* mechanism rather than explicitly provided by the original
* provider of the security descriptor. This may affect the
* treatment of the ACL with respect to inheritence of an ACL.
* This flag is ignored if the DaclPresent flag is not set.
*
* SE_SACL_PRESENT - This boolean flag, when set, indicates that the
* security descriptor contains a system ACL pointed to by the
* Sacl field. If this flag is set and the Sacl field of the
* SECURITY_DESCRIPTOR is null, then an empty (but present)
* ACL is being specified.
*
* SE_SACL_DEFAULTED - This boolean flag, when set, indicates that the
* ACL pointed to by the Sacl field was provided by a defaulting
* mechanism rather than explicitly provided by the original
* provider of the security descriptor. This may affect the
* treatment of the ACL with respect to inheritence of an ACL.
* This flag is ignored if the SaclPresent flag is not set.
*
* SE_SELF_RELATIVE - This boolean flag, when set, indicates that the
* security descriptor is in self-relative form. In this form,
* all fields of the security descriptor are contiguous in memory
* and all pointer fields are expressed as offsets from the
* beginning of the security descriptor.
* SE_OWNER_DEFAULTED - This boolean flag, when set, indicates that the SID
* pointed to by the Owner field was provided by a defaulting mechanism
* rather than explicitly provided by the original provider of the
* security descriptor. This may affect the treatment of the SID with
* respect to inheritence of an owner.
*
* SE_GROUP_DEFAULTED - This boolean flag, when set, indicates that the SID in
* the Group field was provided by a defaulting mechanism rather than
* explicitly provided by the original provider of the security
* descriptor. This may affect the treatment of the SID with respect to
* inheritence of a primary group.
*
* SE_DACL_PRESENT - This boolean flag, when set, indicates that the security
* descriptor contains a discretionary ACL. If this flag is set and the
* Dacl field of the SECURITY_DESCRIPTOR is null, then a null ACL is
* explicitly being specified.
*
* SE_DACL_DEFAULTED - This boolean flag, when set, indicates that the ACL
* pointed to by the Dacl field was provided by a defaulting mechanism
* rather than explicitly provided by the original provider of the
* security descriptor. This may affect the treatment of the ACL with
* respect to inheritence of an ACL. This flag is ignored if the
* DaclPresent flag is not set.
*
* SE_SACL_PRESENT - This boolean flag, when set, indicates that the security
* descriptor contains a system ACL pointed to by the Sacl field. If this
* flag is set and the Sacl field of the SECURITY_DESCRIPTOR is null, then
* an empty (but present) ACL is being specified.
*
* SE_SACL_DEFAULTED - This boolean flag, when set, indicates that the ACL
* pointed to by the Sacl field was provided by a defaulting mechanism
* rather than explicitly provided by the original provider of the
* security descriptor. This may affect the treatment of the ACL with
* respect to inheritence of an ACL. This flag is ignored if the
* SaclPresent flag is not set.
*
* SE_SELF_RELATIVE - This boolean flag, when set, indicates that the security
* descriptor is in self-relative form. In this form, all fields of the
* security descriptor are contiguous in memory and all pointer fields are
* expressed as offsets from the beginning of the security descriptor.
*/
typedef enum {
SE_OWNER_DEFAULTED = const_cpu_to_le16(0x0001),
......
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
......@@ -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 */
......@@ -2,7 +2,7 @@
* mst.c - NTFS multi sector transfer protection handling code. Part of the
* 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
......@@ -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);
......@@ -199,4 +200,3 @@ void post_write_mst_fixup(NTFS_RECORD *b)
data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
}
}
......@@ -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;
......@@ -869,6 +871,35 @@ static BOOL check_mft_mirror(ntfs_volume *vol)
}
} 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,7 +2,7 @@
* 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
......@@ -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,6 +34,13 @@ 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
......@@ -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