Commit aea571fc authored by Anton Altaparmakov's avatar Anton Altaparmakov

Merge cantab.net:/home/src/bklinux-2.6

into cantab.net:/home/src/ntfs-2.6
parents 9fa12b00 93b62d3a
......@@ -71,6 +71,7 @@ Features
compatibility, we implement access to files using their short file names if
they exist. The driver will not create short file names however, and a rename
will discard any existing short file name.
- The new driver supports exporting of mounted NTFS volumes via NFS.
Supported mount options
......
......@@ -19,6 +19,27 @@ ToDo:
sufficient for synchronisation here. We then just need to make sure
ntfs_readpage/writepage/truncate interoperate properly with us.
2.1.8-WIP
- Use get_bh() instead of manual atomic_inc() in fs/ntfs/compress.c.
- Modify fs/ntfs/time.c::ntfs2utc(), get_current_ntfs_time(), and
utc2ntfs() to work with struct timespec instead of time_t on the
Linux UTC time side thus preserving the full precision of the NTFS
time and only loosing up to 99 nano-seconds in the Linux UTC time.
- Move fs/ntfs/time.c to fs/ntfs/time.h and make the time functions
static inline.
- Remove unused ntfs_dirty_inode().
- Cleanup super operations declaration in fs/ntfs/super.c.
- Wrap flush_dcache_mft_record_page() in #ifdef NTFS_RW.
- Add NInoTestSetFoo() and NInoTestClearFoo() macro magic to
fs/ntfs/inode.h and use it to declare NInoTest{Set,Clear}Dirty.
- Move typedefs for ntfs_attr and test_t from fs/ntfs/inode.c to
fs/ntfs/inode.h so they can be used elsewhere.
- 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).
2.1.7 - Enable NFS exporting of mounted NTFS volumes.
- Set i_generation in the VFS inode from the seq_no of the NTFS inode.
......
......@@ -3,9 +3,9 @@
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 time.o unistr.o upcase.o
mst.o namei.o super.o sysctl.o unistr.o upcase.o
EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.7\"
EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.8-WIP\"
ifeq ($(CONFIG_NTFS_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
......
......@@ -2,7 +2,7 @@
* compress.c - NTFS kernel compressed attributes handling.
* Part of the Linux-NTFS project.
*
* Copyright (c) 2001-2003 Anton Altaparmakov
* Copyright (c) 2001-2004 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
......@@ -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
*/
......@@ -357,7 +357,7 @@ static int ntfs_decompress(struct page *dest_pages[], int *dest_index,
continue;
}
/*
/*
* We have a phrase token. Make sure it is not the first tag in
* the sb as this is illegal and would confuse the code below.
*/
......@@ -643,7 +643,7 @@ int ntfs_read_compressed_block(struct page *page)
unlock_buffer(tbh);
continue;
}
atomic_inc(&tbh->b_count);
get_bh(tbh);
tbh->b_end_io = end_buffer_read_sync;
submit_bh(READ, tbh);
}
......@@ -943,4 +943,3 @@ int ntfs_read_compressed_block(struct page *page)
kfree(pages);
return -EIO;
}
......@@ -8,13 +8,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
*/
......@@ -29,26 +29,7 @@
#include "dir.h"
#include "inode.h"
#include "attrib.h"
/**
* ntfs_attr - ntfs in memory attribute structure
* @mft_no: mft record number of the base mft record of this attribute
* @name: Unicode name of the attribute (NULL if unnamed)
* @name_len: length of @name in Unicode characters (0 if unnamed)
* @type: attribute type (see layout.h)
*
* This structure exists only to provide a small structure for the
* ntfs_{attr_}iget()/ntfs_test_inode()/ntfs_init_locked_inode() mechanism.
*
* NOTE: Elements are ordered by size to make the structure as compact as
* possible on all architectures.
*/
typedef struct {
unsigned long mft_no;
uchar_t *name;
u32 name_len;
ATTR_TYPES type;
} ntfs_attr;
#include "time.h"
/**
* ntfs_test_inode - compare two (possibly fake) inodes for equality
......@@ -66,7 +47,7 @@ typedef struct {
* NOTE: This function runs with the inode_lock spin lock held so it is not
* allowed to sleep.
*/
static int ntfs_test_inode(struct inode *vi, ntfs_attr *na)
int ntfs_test_inode(struct inode *vi, ntfs_attr *na)
{
ntfs_inode *ni;
......@@ -150,7 +131,6 @@ static int ntfs_init_locked_inode(struct inode *vi, ntfs_attr *na)
return 0;
}
typedef int (*test_t)(struct inode *, void *);
typedef int (*set_t)(struct inode *, void *);
static int ntfs_read_locked_inode(struct inode *vi);
static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi);
......@@ -380,7 +360,7 @@ inline ntfs_inode *ntfs_new_extent_inode(struct super_block *sb,
* Search all file name attributes in the inode described by the attribute
* search context @ctx and check if any of the names are in the $Extend system
* directory.
*
*
* Return values:
* 1: file is in $Extend directory
* 0: file is not in $Extend directory
......@@ -590,21 +570,18 @@ static int ntfs_read_locked_inode(struct inode *vi)
* mtime is the last change of the data within the file. Not changed
* when only metadata is changed, e.g. a rename doesn't affect mtime.
*/
vi->i_mtime.tv_sec = ntfs2utc(si->last_data_change_time);
vi->i_mtime.tv_nsec = 0;
vi->i_mtime = ntfs2utc(si->last_data_change_time);
/*
* ctime is the last change of the metadata of the file. This obviously
* always changes, when mtime is changed. ctime can be changed on its
* own, mtime is then not changed, e.g. when a file is renamed.
*/
vi->i_ctime.tv_sec = ntfs2utc(si->last_mft_change_time);
vi->i_ctime.tv_nsec = 0;
vi->i_ctime = ntfs2utc(si->last_mft_change_time);
/*
* Last access to the data within the file. Not changed during a rename
* for example but changed whenever the file is written to.
*/
vi->i_atime.tv_sec = ntfs2utc(si->last_access_time);
vi->i_atime.tv_nsec = 0;
vi->i_atime = ntfs2utc(si->last_access_time);
/* Find the attribute list attribute if present. */
reinit_attr_search_ctx(ctx);
......@@ -1738,39 +1715,6 @@ void ntfs_read_inode_mount(struct inode *vi)
goto out_now;
}
/**
* ntfs_dirty_inode - mark the inode's metadata dirty
* @vi: inode to mark dirty
*
* This is called from fs/inode.c::__mark_inode_dirty(), when the inode itself
* is being marked dirty. An example is when update_atime() is invoked.
*
* We mark the inode dirty by setting both the page in which the mft record
* resides and the buffer heads in that page which correspond to the mft record
* dirty. This ensures that the changes will eventually be propagated to disk
* when the inode is set dirty.
*
* FIXME: Can we do that with the buffer heads? I am not too sure. Because if we
* do that we need to make sure that the kernel will not write out those buffer
* heads or we are screwed as it will write corrupt data to disk. The only way
* a mft record can be written correctly is by mst protecting it, writting it
* synchronously and fast mst deprotecting it. During this period, obviously,
* the mft record must be marked as not uptodate, be locked for writing or
* whatever, so that nobody attempts anything stupid.
*
* FIXME: Do we need to check that the fs is not mounted read only? And what
* about the inode? Anything else?
*
* FIXME: As we are only a read only driver it is safe to just return here for
* the moment.
*/
void ntfs_dirty_inode(struct inode *vi)
{
ntfs_debug("Entering for inode 0x%lx.", vi->i_ino);
NInoSetDirty(NTFS_I(vi));
return;
}
/**
* ntfs_commit_inode - write out a dirty inode
* @ni: inode to write out
......@@ -2029,4 +1973,3 @@ int ntfs_setattr(struct dentry *dentry, struct iattr *attr)
}
#endif
......@@ -2,7 +2,7 @@
* inode.h - Defines for inode structures NTFS Linux kernel driver. Part of
* the Linux-NTFS project.
*
* Copyright (c) 2001-2003 Anton Altaparmakov
* Copyright (c) 2001-2004 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
......@@ -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
*/
......@@ -181,8 +181,22 @@ static inline void NInoClear##flag(ntfs_inode *ni) \
clear_bit(NI_##flag, &(ni)->state); \
}
/*
* As above for NInoTestSetFoo() and NInoTestClearFoo().
*/
#define TAS_NINO_FNS(flag) \
static inline int NInoTestSet##flag(ntfs_inode *ni) \
{ \
return test_and_set_bit(NI_##flag, &(ni)->state); \
} \
static inline int NInoTestClear##flag(ntfs_inode *ni) \
{ \
return test_and_clear_bit(NI_##flag, &(ni)->state); \
}
/* Emit the ntfs inode bitops functions. */
NINO_FNS(Dirty)
TAS_NINO_FNS(Dirty)
NINO_FNS(AttrList)
NINO_FNS(AttrListNonResident)
NINO_FNS(Attr)
......@@ -219,6 +233,30 @@ static inline struct inode *VFS_I(ntfs_inode *ni)
return &((big_ntfs_inode *)ni)->vfs_inode;
}
/**
* ntfs_attr - ntfs in memory attribute structure
* @mft_no: mft record number of the base mft record of this attribute
* @name: Unicode name of the attribute (NULL if unnamed)
* @name_len: length of @name in Unicode characters (0 if unnamed)
* @type: attribute type (see layout.h)
*
* This structure exists only to provide a small structure for the
* ntfs_{attr_}iget()/ntfs_test_inode()/ntfs_init_locked_inode() mechanism.
*
* NOTE: Elements are ordered by size to make the structure as compact as
* possible on all architectures.
*/
typedef struct {
unsigned long mft_no;
uchar_t *name;
u32 name_len;
ATTR_TYPES type;
} ntfs_attr;
typedef int (*test_t)(struct inode *, void *);
extern int ntfs_test_inode(struct inode *vi, ntfs_attr *na);
extern struct inode *ntfs_iget(struct super_block *sb, unsigned long mft_no);
extern struct inode *ntfs_attr_iget(struct inode *base_vi, ATTR_TYPES type,
uchar_t *name, u32 name_len);
......@@ -233,8 +271,6 @@ extern void ntfs_clear_extent_inode(ntfs_inode *ni);
extern void ntfs_read_inode_mount(struct inode *vi);
extern void ntfs_dirty_inode(struct inode *vi);
extern void ntfs_put_inode(struct inode *vi);
extern int ntfs_show_options(struct seq_file *sf, struct vfsmount *mnt);
......@@ -245,7 +281,6 @@ extern void ntfs_truncate(struct inode *vi);
extern int ntfs_setattr(struct dentry *dentry, struct iattr *attr);
#endif
#endif /* _LINUX_NTFS_FS_INODE_H */
#endif /* NTFS_RW */
#endif /* _LINUX_NTFS_INODE_H */
......@@ -2,20 +2,20 @@
* mft.h - Defines for mft record handling in NTFS Linux kernel driver.
* 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
*/
......@@ -43,7 +43,9 @@ static inline void unmap_extent_mft_record(ntfs_inode *ni)
return;
}
/*
#ifdef NTFS_RW
/**
* flush_dcache_mft_record_page - flush_dcache_page() for mft records
* @ni: ntfs inode structure of mft record
*
......@@ -57,5 +59,6 @@ static inline void flush_dcache_mft_record_page(ntfs_inode *ni)
flush_dcache_page(ni->page);
}
#endif /* _LINUX_NTFS_MFT_H */
#endif /* NTFS_RW */
#endif /* _LINUX_NTFS_MFT_H */
......@@ -2,7 +2,7 @@
* ntfs.h - Defines for NTFS Linux kernel driver. Part of the Linux-NTFS
* project.
*
* Copyright (c) 2001,2002 Anton Altaparmakov.
* Copyright (c) 2001-2004 Anton Altaparmakov.
* Copyright (C) 2002 Richard Russon.
*
* This program/include file is free software; you can redistribute it and/or
......@@ -180,11 +180,6 @@ extern int post_read_mst_fixup(NTFS_RECORD *b, const u32 size);
extern int pre_write_mst_fixup(NTFS_RECORD *b, const u32 size);
extern void post_write_mst_fixup(NTFS_RECORD *b);
/* From fs/ntfs/time.c */
extern inline s64 utc2ntfs(const time_t time);
extern inline s64 get_current_ntfs_time(void);
extern time_t ntfs2utc(const s64 time);
/* From fs/ntfs/unistr.c */
extern BOOL ntfs_are_names_equal(const uchar_t *s1, size_t s1_len,
const uchar_t *s2, size_t s2_len,
......
......@@ -9,13 +9,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
*/
......@@ -102,7 +102,7 @@ static BOOL parse_options(ntfs_volume *vol, char *opt)
if (*v) \
goto needs_val; \
} \
}
}
#define NTFS_GETOPT(option, variable) \
if (!strcmp(p, option)) { \
if (!v || !*v) \
......@@ -110,14 +110,14 @@ static BOOL parse_options(ntfs_volume *vol, char *opt)
variable = simple_strtoul(ov = v, &v, 0); \
if (*v) \
goto needs_val; \
}
}
#define NTFS_GETOPT_BOOL(option, variable) \
if (!strcmp(p, option)) { \
BOOL val; \
if (!simple_getbool(v, &val)) \
goto needs_bool; \
variable = val; \
}
}
#define NTFS_GETOPT_OPTIONS_ARRAY(option, variable, opt_array) \
if (!strcmp(p, option)) { \
int _i; \
......@@ -400,7 +400,7 @@ static BOOL is_boot_sector_ntfs(const struct super_block *sb,
le32_to_cpu(b->bpb.large_sectors) || b->bpb.fats)
goto not_ntfs;
/* Check clusters per file mft record value is valid. */
if ((u8)b->clusters_per_mft_record < 0xe1 ||
if ((u8)b->clusters_per_mft_record < 0xe1 ||
(u8)b->clusters_per_mft_record > 0xf7)
switch (b->clusters_per_mft_record) {
case 1: case 2: case 4: case 8: case 16: case 32: case 64:
......@@ -409,7 +409,7 @@ static BOOL is_boot_sector_ntfs(const struct super_block *sb,
goto not_ntfs;
}
/* Check clusters per index block value is valid. */
if ((u8)b->clusters_per_index_record < 0xe1 ||
if ((u8)b->clusters_per_index_record < 0xe1 ||
(u8)b->clusters_per_index_record > 0xf7)
switch (b->clusters_per_index_record) {
case 1: case 2: case 4: case 8: case 16: case 32: case 64:
......@@ -529,7 +529,7 @@ static struct buffer_head *read_ntfs_boot_sector(struct super_block *sb,
* parse_ntfs_boot_sector - parse the boot sector and store the data in @vol
* @vol: volume structure to initialise with data from boot sector
* @b: boot sector to parse
*
*
* Parse the ntfs boot sector @b and store all imporant information therein in
* the ntfs super block @vol. Return TRUE on success and FALSE on error.
*/
......@@ -592,10 +592,10 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b)
ntfs_debug("vol->mft_record_size_mask = 0x%x",
vol->mft_record_size_mask);
ntfs_debug("vol->mft_record_size_bits = %i (0x%x)",
vol->mft_record_size_bits, vol->mft_record_size_bits);
vol->mft_record_size_bits, vol->mft_record_size_bits);
clusters_per_index_record = b->clusters_per_index_record;
ntfs_debug("clusters_per_index_record = %i (0x%x)",
clusters_per_index_record, clusters_per_index_record);
clusters_per_index_record, clusters_per_index_record);
if (clusters_per_index_record > 0)
vol->index_record_size = vol->cluster_size <<
(ffs(clusters_per_index_record) - 1);
......@@ -610,7 +610,7 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b)
vol->index_record_size_mask = vol->index_record_size - 1;
vol->index_record_size_bits = ffs(vol->index_record_size) - 1;
ntfs_debug("vol->index_record_size = %i (0x%x)",
vol->index_record_size, vol->index_record_size);
vol->index_record_size, vol->index_record_size);
ntfs_debug("vol->index_record_size_mask = 0x%x",
vol->index_record_size_mask);
ntfs_debug("vol->index_record_size_bits = %i (0x%x)",
......@@ -657,6 +657,22 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b)
}
vol->mftmirr_lcn = ll;
ntfs_debug("vol->mftmirr_lcn = 0x%Lx", (long long)vol->mftmirr_lcn);
#ifdef NTFS_RW
/*
* Work out the size of the mft mirror in number of mft records. If the
* cluster size is less than or equal to the size taken by four mft
* records, the mft mirror stores the first four mft records. If the
* cluster size is bigger than the size taken by four mft records, the
* mft mirror contains as many mft records as will fit into one
* cluster.
*/
if (vol->cluster_size <= (4 << vol->mft_record_size_bits))
vol->mftmirr_size = 4;
else
vol->mftmirr_size = vol->cluster_size >>
vol->mft_record_size_bits;
ntfs_debug("vol->mftmirr_size = %i", vol->mftmirr_size);
#endif /* NTFS_RW */
vol->serial_no = le64_to_cpu(b->volume_serial_number);
ntfs_debug("vol->serial_no = 0x%Lx",
(unsigned long long)vol->serial_no);
......@@ -690,12 +706,173 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b)
ntfs_debug("vol->mft_zone_start = 0x%Lx",
(long long)vol->mft_zone_start);
ntfs_debug("vol->mft_zone_end = 0x%Lx", (long long)vol->mft_zone_end);
/* And another misplaced defaults setting. */
if (!vol->on_errors)
vol->on_errors = ON_ERRORS_PANIC;
return TRUE;
}
#ifdef NTFS_RW
/**
* load_and_init_mft_mirror - load and setup the mft mirror inode for a volume
* @vol: ntfs super block describing device whose mft mirror to load
*
* Return TRUE on success or FALSE on error.
*/
static BOOL load_and_init_mft_mirror(ntfs_volume *vol)
{
struct inode *tmp_ino;
ntfs_inode *tmp_ni;
/* Get mft mirror inode. */
tmp_ino = ntfs_iget(vol->sb, FILE_MFTMirr);
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.");
return FALSE;
}
/*
* Re-initialize some specifics about $MFTMirr's inode as
* ntfs_read_inode() will have set up the default ones.
*/
/* Set uid and gid to root. */
tmp_ino->i_uid = tmp_ino->i_gid = 0;
/* Regular file. No access for anyone. */
tmp_ino->i_mode = S_IFREG;
/* No VFS initiated operations allowed for $MFTMirr. */
tmp_ino->i_op = &ntfs_empty_inode_ops;
tmp_ino->i_fop = &ntfs_empty_file_ops;
/* Put back our special address space operations. */
tmp_ino->i_mapping->a_ops = &ntfs_mft_aops;
tmp_ni = NTFS_I(tmp_ino);
/* The $MFTMirr, like the $MFT is multi sector transfer protected. */
NInoSetMstProtected(tmp_ni);
/*
* Set up our little cheat allowing us to reuse the async io
* completion handler for directories.
*/
tmp_ni->itype.index.block_size = vol->mft_record_size;
tmp_ni->itype.index.block_size_bits = vol->mft_record_size_bits;
vol->mftmirr_ino = tmp_ino;
return TRUE;
}
/**
* check_mft_mirror - compare contents of the mft mirror with the mft
* @vol: ntfs super block describing device whose mft mirror to check
*
* Return TRUE on success or FALSE on error.
*/
static BOOL check_mft_mirror(ntfs_volume *vol)
{
unsigned long index;
struct super_block *sb = vol->sb;
ntfs_inode *mirr_ni;
struct page *mft_page, *mirr_page;
u8 *kmft, *kmirr;
run_list_element *rl, rl2[2];
int mrecs_per_page, i;
/* Compare contents of $MFT and $MFTMirr. */
mrecs_per_page = PAGE_CACHE_SIZE / vol->mft_record_size;
BUG_ON(!mrecs_per_page);
BUG_ON(!vol->mftmirr_size);
mft_page = mirr_page = NULL;
kmft = kmirr = NULL;
index = i = 0;
do {
u32 bytes;
/* Switch pages if necessary. */
if (!(i % mrecs_per_page)) {
if (index) {
ntfs_unmap_page(mft_page);
ntfs_unmap_page(mirr_page);
}
/* Get the $MFT page. */
mft_page = ntfs_map_page(vol->mft_ino->i_mapping,
index);
if (IS_ERR(mft_page)) {
ntfs_error(sb, "Failed to read $MFT.");
return FALSE;
}
kmft = page_address(mft_page);
/* Get the $MFTMirr page. */
mirr_page = ntfs_map_page(vol->mftmirr_ino->i_mapping,
index);
if (IS_ERR(mirr_page)) {
ntfs_error(sb, "Failed to read $MFTMirr.");
goto mft_unmap_out;
}
kmirr = page_address(mirr_page);
++index;
}
/* Make sure the record is ok. */
if (is_baad_recordp(kmft)) {
ntfs_error(sb, "Incomplete multi sector transfer "
"detected in mft record %i.", i);
mm_unmap_out:
ntfs_unmap_page(mirr_page);
mft_unmap_out:
ntfs_unmap_page(mft_page);
return FALSE;
}
if (is_baad_recordp(kmirr)) {
ntfs_error(sb, "Incomplete multi sector transfer "
"detected in mft mirror record %i.", i);
goto mm_unmap_out;
}
/* Get the amount of data in the current record. */
bytes = le32_to_cpu(((MFT_RECORD*)kmft)->bytes_in_use);
if (!bytes || bytes > vol->mft_record_size) {
bytes = le32_to_cpu(((MFT_RECORD*)kmirr)->bytes_in_use);
if (!bytes || bytes > vol->mft_record_size)
bytes = vol->mft_record_size;
}
/* 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);
goto mm_unmap_out;
}
kmft += vol->mft_record_size;
kmirr += vol->mft_record_size;
} while (++i < vol->mftmirr_size);
/* Release the last pages. */
ntfs_unmap_page(mft_page);
ntfs_unmap_page(mirr_page);
/* Construct the mft mirror run list by hand. */
rl2[0].vcn = 0;
rl2[0].lcn = vol->mftmirr_lcn;
rl2[0].length = (vol->mftmirr_size * vol->mft_record_size +
vol->cluster_size - 1) / vol->cluster_size;
rl2[1].vcn = rl2[0].length;
rl2[1].lcn = LCN_ENOENT;
rl2[1].length = 0;
/*
* Because we have just read all of the mft mirror, we know we have
* mapped the full run list for it.
*/
mirr_ni = NTFS_I(vol->mftmirr_ino);
down_read(&mirr_ni->run_list.lock);
rl = mirr_ni->run_list.rl;
/* Compare the two run lists. They must be identical. */
i = 0;
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. "
"Run chkdsk.");
up_read(&mirr_ni->run_list.lock);
return FALSE;
}
} while (rl2[i++].length);
up_read(&mirr_ni->run_list.lock);
return TRUE;
}
#endif /* NTFS_RW */
/**
* load_and_init_upcase - load the upcase table for an ntfs volume
* @vol: ntfs super block describing device whose upcase to load
......@@ -816,28 +993,44 @@ static BOOL load_system_files(ntfs_volume *vol)
attr_search_context *ctx;
ntfs_debug("Entering.");
#ifdef NTFS_RW
/* Get mft mirror inode compare the contents of $MFT and $MFTMirr. */
if (!load_and_init_mft_mirror(vol) || !check_mft_mirror(vol)) {
static const char *es1 = "Failed to load $MFTMirr";
static const char *es2 = "$MFTMirr does not match $MFT";
static const char *es3 = ". Run ntfsfix and/or chkdsk.";
/* 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->mftmirr_ino ? es1 : es2,
es3);
goto iput_mirr_err_out;
}
sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME;
ntfs_error(sb, "%s. Mounting read-only%s",
!vol->mftmirr_ino ? es1 : es2, es3);
} else
ntfs_warning(sb, "%s. Will not be able to remount "
"read-write%s",
!vol->mftmirr_ino ? es1 : es2, es3);
/* This will prevent a read-write remount. */
NVolSetErrors(vol);
}
#endif /* NTFS_RW */
/* Get mft bitmap attribute inode. */
vol->mftbmp_ino = ntfs_attr_iget(vol->mft_ino, AT_BITMAP, NULL, 0);
if (IS_ERR(vol->mftbmp_ino)) {
ntfs_error(sb, "Failed to load $MFT/$BITMAP attribute.");
return FALSE;
}
/* Get mft mirror inode. */
vol->mftmirr_ino = ntfs_iget(sb, FILE_MFTMirr);
if (IS_ERR(vol->mftmirr_ino) || is_bad_inode(vol->mftmirr_ino)) {
if (!IS_ERR(vol->mftmirr_ino))
iput(vol->mftmirr_ino);
ntfs_error(sb, "Failed to load $MFTMirr.");
goto iput_mftbmp_err_out;
goto iput_mirr_err_out;
}
// FIXME: Compare mftmirr with mft and repair if appropriate and not
// a read-only mount.
/* Read upcase table and setup vol->upcase and vol->upcase_len. */
/* Read upcase table and setup @vol->upcase and @vol->upcase_len. */
if (!load_and_init_upcase(vol))
goto iput_mirr_err_out;
goto iput_mftbmp_err_out;
/*
* Get the cluster allocation bitmap inode and verify the size, no
* need for any locking at this stage as we are already running
......@@ -920,7 +1113,7 @@ static BOOL load_system_files(ntfs_volume *vol)
/*
* Get the inode for the attribute definitions file and parse the
* attribute definitions.
*/
*/
tmp_ino = ntfs_iget(sb, FILE_AttrDef);
if (IS_ERR(tmp_ino) || is_bad_inode(tmp_ino)) {
if (!IS_ERR(tmp_ino))
......@@ -974,10 +1167,13 @@ static BOOL load_system_files(ntfs_volume *vol)
iput(vol->vol_ino);
iput_lcnbmp_err_out:
iput(vol->lcnbmp_ino);
iput_mirr_err_out:
iput(vol->mftmirr_ino);
iput_mftbmp_err_out:
iput(vol->mftbmp_ino);
iput_mirr_err_out:
#ifdef NTFS_RW
if (vol->mftmirr_ino)
iput(vol->mftmirr_ino);
#endif /* NTFS_RW */
return FALSE;
}
......@@ -1015,8 +1211,12 @@ static void ntfs_put_super(struct super_block *vfs_sb)
vol->lcnbmp_ino = NULL;
up_write(&vol->lcnbmp_lock);
iput(vol->mftmirr_ino);
vol->mftmirr_ino = NULL;
#ifdef NTFS_RW
if (vol->mftmirr_ino) {
iput(vol->mftmirr_ino);
vol->mftmirr_ino = NULL;
}
#endif /* NTFS_RW */
down_write(&vol->mftbmp_lock);
iput(vol->mftbmp_ino);
......@@ -1321,24 +1521,36 @@ struct super_operations ntfs_mount_sops = {
struct super_operations ntfs_sops = {
.alloc_inode = ntfs_alloc_big_inode, /* VFS: Allocate new inode. */
.destroy_inode = ntfs_destroy_big_inode, /* VFS: Deallocate inode. */
//.dirty_inode = ntfs_dirty_inode, /* VFS: Called from
// __mark_inode_dirty(). */
//.write_inode = NULL, /* VFS: Write dirty inode to disk. */
.put_inode = ntfs_put_inode, /* VFS: Called just before the inode
reference count is decreased. */
//.delete_inode = NULL, /* VFS: Delete inode from disk. Called
// when i_count becomes 0 and i_nlink
// is also 0. */
.put_super = ntfs_put_super, /* Syscall: umount. */
//write_super = NULL, /* Flush dirty super block to disk. */
//write_super_lockfs = NULL, /* ? */
//unlockfs = NULL, /* ? */
.statfs = ntfs_statfs, /* Syscall: statfs */
.remount_fs = ntfs_remount, /* Syscall: mount -o remount. */
.put_inode = ntfs_put_inode, /* VFS: Called just before
the inode reference count
is decreased. */
#ifdef NTFS_RW
//.dirty_inode = NULL, /* VFS: Called from
// __mark_inode_dirty(). */
//.write_inode = NULL, /* VFS: Write dirty inode to
// disk. */
//.drop_inode = NULL, /* VFS: Called just after the
// inode reference count has
// been decreased to zero.
// NOTE: The inode lock is
// held. See fs/inode.c::
// generic_drop_inode(). */
//.delete_inode = NULL, /* VFS: Delete inode from disk.
// Called when i_count becomes
// 0 and i_nlink is also 0. */
//.write_super = NULL, /* Flush dirty super block to
// disk. */
//.write_super_lockfs = NULL, /* ? */
//.unlockfs = NULL, /* ? */
#endif /* NTFS_RW */
.put_super = ntfs_put_super, /* Syscall: umount. */
.statfs = ntfs_statfs, /* Syscall: statfs */
.remount_fs = ntfs_remount, /* Syscall: mount -o remount. */
.clear_inode = ntfs_clear_big_inode, /* VFS: Called when an inode is
removed from memory. */
//.umount_begin = NULL, /* Forced umount. */
.show_options = ntfs_show_options, /* Show mount options in proc. */
//.umount_begin = NULL, /* Forced umount. */
.show_options = ntfs_show_options, /* Show mount options in
proc. */
};
......@@ -1424,7 +1636,9 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
vol->mft_ino = NULL;
vol->mftbmp_ino = NULL;
init_rwsem(&vol->mftbmp_lock);
#ifdef NTFS_RW
vol->mftmirr_ino = NULL;
#endif /* NTFS_RW */
vol->lcnbmp_ino = NULL;
init_rwsem(&vol->lcnbmp_lock);
vol->vol_ino = NULL;
......@@ -1474,7 +1688,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
ntfs_error(sb, "Not an NTFS volume.");
goto err_out_now;
}
/*
* Extract the data from the boot sector and setup the ntfs super block
* using it.
......@@ -1489,7 +1703,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
goto err_out_now;
}
/*
/*
* TODO: When we start coping with sector sizes different from
* NTFS_BLOCK_SIZE, we now probably need to set the blocksize of the
* device (probably to NTFS_BLOCK_SIZE).
......@@ -1500,7 +1714,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
/*
* Ntfs allows 63 bits for the file size, i.e. correct would be:
* sb->s_maxbytes = ~0ULL >> 1;
* sb->s_maxbytes = ~0ULL >> 1;
* But the kernel uses a long as the page cache page index which on
* 32-bit architectures is only 32-bits. MAX_LFS_FILESIZE is kernel
* defined to the maximum the page cache page index can cope with
......@@ -1601,8 +1815,10 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
vol->root_ino = NULL;
iput(vol->lcnbmp_ino);
vol->lcnbmp_ino = NULL;
#ifdef NTFS_RW
iput(vol->mftmirr_ino);
vol->mftmirr_ino = NULL;
#endif /* NTFS_RW */
iput(vol->mftbmp_ino);
vol->mftbmp_ino = NULL;
vol->upcase_len = 0;
......@@ -1757,7 +1973,7 @@ static int __init init_ntfs_fs(void)
}
ntfs_inode_cache = kmem_cache_create(ntfs_inode_cache_name,
sizeof(ntfs_inode), 0,
sizeof(ntfs_inode), 0,
SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, NULL, NULL);
if (!ntfs_inode_cache) {
printk(KERN_CRIT "NTFS: Failed to create %s!\n",
......@@ -1766,7 +1982,7 @@ static int __init init_ntfs_fs(void)
}
ntfs_big_inode_cache = kmem_cache_create(ntfs_big_inode_cache_name,
sizeof(big_ntfs_inode), 0,
sizeof(big_ntfs_inode), 0,
SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
ntfs_big_inode_init_once, NULL);
if (!ntfs_big_inode_cache) {
......
/*
* time.c - NTFS time conversion functions. Part of the Linux-NTFS project.
* time.h - NTFS time conversion functions. 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
* 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
*/
#include <linux/sched.h> /* For CURRENT_TIME. */
#ifndef _LINUX_NTFS_TIME_H
#define _LINUX_NTFS_TIME_H
#include <linux/time.h> /* For current_kernel_time(). */
#include <asm/div64.h> /* For do_div(). */
#include "ntfs.h"
#include "endian.h"
#define NTFS_TIME_OFFSET ((s64)(369 * 365 + 89) * 24 * 3600 * 10000000)
/**
* utc2ntfs - convert Linux time to NTFS time
* @time: Linux time to convert to NTFS
* utc2ntfs - convert Linux UTC time to NTFS time
* @ts: Linux UTC time to convert to NTFS time
*
* Convert the Linux time @time to its corresponding NTFS time and return that
* in little endian format.
* Convert the Linux UTC time @ts to its corresponding NTFS time and return
* that in little endian format.
*
* Linux stores time in a long at present and measures it as the number of
* 1-second intervals since 1st January 1970, 00:00:00 UTC.
* Linux stores time in a struct timespec consisting of a time_t (long at
* present) tv_sec and a long tv_nsec where tv_sec is the number of 1-second
* intervals since 1st January 1970, 00:00:00 UTC and tv_nsec is the number of
* 1-nano-second intervals since the value of tv_sec.
*
* NTFS uses Microsoft's standard time format which is stored in a s64 and is
* measured as the number of 100 nano-second intervals since 1st January 1601,
* measured as the number of 100-nano-second intervals since 1st January 1601,
* 00:00:00 UTC.
*/
inline s64 utc2ntfs(const time_t time)
static inline s64 utc2ntfs(const struct timespec ts)
{
/* Convert to 100ns intervals and then add the NTFS time offset. */
return cpu_to_sle64((s64)time * 10000000 + NTFS_TIME_OFFSET);
/*
* Convert the seconds to 100ns intervals, add the nano-seconds
* converted to 100ns intervals, and then add the NTFS time offset.
*/
return cpu_to_sle64((s64)ts.tv_sec * 10000000 + ts.tv_nsec / 100 +
NTFS_TIME_OFFSET);
}
/**
......@@ -52,31 +61,40 @@ inline s64 utc2ntfs(const time_t time)
* Get the current time from the Linux kernel, convert it to its corresponding
* NTFS time and return that in little endian format.
*/
inline s64 get_current_ntfs_time(void)
static inline s64 get_current_ntfs_time(void)
{
/* ignores leap second */
return utc2ntfs(get_seconds()) + xtime.tv_nsec/1000;
return utc2ntfs(current_kernel_time());
}
/**
* ntfs2utc - convert NTFS time to Linux time
* @time: NTFS time (little endian) to convert to Linux
* @time: NTFS time (little endian) to convert to Linux UTC
*
* Convert the little endian NTFS time @time to its corresponding Linux time
* and return that in cpu format.
* Convert the little endian NTFS time @time to its corresponding Linux UTC
* time and return that in cpu format.
*
* Linux stores time in a long at present and measures it as the number of
* 1-second intervals since 1st January 1970, 00:00:00 UTC.
* Linux stores time in a struct timespec consisting of a time_t (long at
* present) tv_sec and a long tv_nsec where tv_sec is the number of 1-second
* intervals since 1st January 1970, 00:00:00 UTC and tv_nsec is the number of
* 1-nano-second intervals since the value of tv_sec.
*
* NTFS uses Microsoft's standard time format which is stored in a s64 and is
* measured as the number of 100 nano-second intervals since 1st January 1601,
* 00:00:00 UTC.
*/
inline time_t ntfs2utc(const s64 time)
static inline struct timespec ntfs2utc(const s64 time)
{
/* Subtract the NTFS time offset, then convert to 1s intervals. */
struct timespec ts;
/* Subtract the NTFS time offset. */
s64 t = sle64_to_cpu(time) - NTFS_TIME_OFFSET;
do_div(t, 10000000);
return (time_t)t;
/*
* Convert the time to 1-second intervals and the remainder to
* 1-nano-second intervals.
*/
ts.tv_nsec = do_div(t, 10000000) * 100;
ts.tv_sec = t;
return ts;
}
#endif /* _LINUX_NTFS_TIME_H */
......@@ -2,7 +2,7 @@
* volume.h - Defines for volume structures in NTFS Linux kernel driver. Part
* of the Linux-NTFS project.
*
* Copyright (c) 2001,2002 Anton Altaparmakov.
* Copyright (c) 2001-2004 Anton Altaparmakov.
* Copyright (c) 2002 Richard Russon.
*
* This program/include file is free software; you can redistribute it and/or
......@@ -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
*/
......@@ -25,6 +25,7 @@
#define _LINUX_NTFS_VOLUME_H
#include "types.h"
#include "layout.h"
/*
* The NTFS in memory super block structure.
......@@ -44,7 +45,7 @@ typedef struct {
LCN nr_blocks; /* Number of NTFS_BLOCK_SIZE bytes
sized blocks on the device. */
/* Configuration provided by user at mount time. */
unsigned long flags; /* Miscellaneous flags, see above. */
unsigned long flags; /* Miscellaneous flags, see below. */
uid_t uid; /* uid that files will be mounted as. */
gid_t gid; /* gid that files will be mounted as. */
mode_t fmask; /* The mask for file permissions. */
......@@ -82,14 +83,20 @@ typedef struct {
unsigned long nr_mft_records; /* Number of mft records == number of
bits in mft bitmap. */
#ifdef NTFS_RW
struct inode *mftmirr_ino; /* The VFS inode of $MFTMirr. */
int mftmirr_size; /* Size of mft mirror in mft records. */
#endif /* NTFS_RW */
struct inode *lcnbmp_ino; /* The VFS inode of $Bitmap. */
struct rw_semaphore lcnbmp_lock; /* Lock for serializing accesses to the
cluster bitmap ($Bitmap/$DATA). */
struct inode *vol_ino; /* The VFS inode of $Volume. */
unsigned long vol_flags; /* Volume flags (VOLUME_*). */
VOLUME_FLAGS vol_flags; /* Volume flags. */
u8 major_ver; /* Ntfs major version of volume. */
u8 minor_ver; /* Ntfs minor version of volume. */
struct inode *root_ino; /* The VFS inode of the root
directory. */
struct inode *secure_ino; /* The VFS inode of $Secure (NTFS3.0+
......@@ -133,4 +140,3 @@ NVOL_FNS(ShowSystemFiles)
NVOL_FNS(CaseSensitive)
#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