Merge git://git.kernel.org/pub/scm/linux/kernel/git/aia21/ntfs-2.6
This commit is contained in:
commit
2cb5b6beef
|
@ -457,6 +457,12 @@ ChangeLog
|
|||
|
||||
Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
|
||||
|
||||
2.1.26:
|
||||
- Implement support for sector sizes above 512 bytes (up to the maximum
|
||||
supported by NTFS which is 4096 bytes).
|
||||
- Enhance support for NTFS volumes which were supported by Windows but
|
||||
not by Linux due to invalid attribute list attribute flags.
|
||||
- A few minor updates and bug fixes.
|
||||
2.1.25:
|
||||
- Write support is now extended with write(2) being able to both
|
||||
overwrite existing file data and to extend files. Also, if a write
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
ToDo/Notes:
|
||||
- Find and fix bugs.
|
||||
- The only places in the kernel where a file is resized are
|
||||
ntfs_file_write*() and ntfs_truncate() for both of which i_sem is
|
||||
ntfs_file_write*() and ntfs_truncate() for both of which i_mutex is
|
||||
held. Just have to be careful in read-/writepage and other helpers
|
||||
not running under i_sem that we play nice... Also need to be careful
|
||||
not running under i_mutex that we play nice. Also need to be careful
|
||||
with initialized_size extension in ntfs_file_write*() and writepage.
|
||||
UPDATE: The only things that need to be checked are the compressed
|
||||
write and the other attribute resize/write cases like index
|
||||
|
@ -19,6 +19,24 @@ ToDo/Notes:
|
|||
- Enable the code for setting the NT4 compatibility flag when we start
|
||||
making NTFS 1.2 specific modifications.
|
||||
|
||||
2.1.26 - Minor bug fixes and updates.
|
||||
|
||||
- Fix a potential overflow in file.c where a cast to s64 was missing in
|
||||
a left shift of a page index.
|
||||
- The struct inode has had its i_sem semaphore changed to a mutex named
|
||||
i_mutex.
|
||||
- We have struct kmem_cache now so use it instead of the typedef
|
||||
kmem_cache_t. (Pekka Enberg)
|
||||
- Implement support for sector sizes above 512 bytes (up to the maximum
|
||||
supported by NTFS which is 4096 bytes).
|
||||
- Do more detailed reporting of why we cannot mount read-write by
|
||||
special casing the VOLUME_MODIFIED_BY_CHKDSK flag.
|
||||
- Miscellaneous updates to layout.h.
|
||||
- Cope with attribute list attribute having invalid flags. Windows
|
||||
copes with this and even chkdsk does not detect or fix this so we
|
||||
have to cope with it, too. Thanks to Pawel Kot for reporting the
|
||||
problem.
|
||||
|
||||
2.1.25 - (Almost) fully implement write(2) and truncate(2).
|
||||
|
||||
- Change ntfs_map_runlist_nolock(), ntfs_attr_find_vcn_nolock() and
|
||||
|
@ -373,7 +391,7 @@ ToDo/Notes:
|
|||
single one of them had an mst error. (Thanks to Ken MacFerrin for
|
||||
the bug report.)
|
||||
- Fix error handling in fs/ntfs/quota.c::ntfs_mark_quotas_out_of_date()
|
||||
where we failed to release i_sem on the $Quota/$Q attribute inode.
|
||||
where we failed to release i_mutex on the $Quota/$Q attribute inode.
|
||||
- Fix bug in handling of bad inodes in fs/ntfs/namei.c::ntfs_lookup().
|
||||
- Add mapping of unmapped buffers to all remaining code paths, i.e.
|
||||
fs/ntfs/aops.c::ntfs_write_mst_block(), mft.c::ntfs_sync_mft_mirror(),
|
||||
|
@ -874,7 +892,7 @@ ToDo/Notes:
|
|||
clusters. (Philipp Thomas)
|
||||
- attrib.c::load_attribute_list(): Fix bug when initialized_size is a
|
||||
multiple of the block_size but not the cluster size. (Szabolcs
|
||||
Szakacsits <szaka@sienet.hu>)
|
||||
Szakacsits)
|
||||
|
||||
2.1.2 - Important bug fixes aleviating the hangs in statfs.
|
||||
|
||||
|
@ -884,7 +902,7 @@ ToDo/Notes:
|
|||
|
||||
- Add handling for initialized_size != data_size in compressed files.
|
||||
- Reduce function local stack usage from 0x3d4 bytes to just noise in
|
||||
fs/ntfs/upcase.c. (Randy Dunlap <rdunlap@xenotime.net>)
|
||||
fs/ntfs/upcase.c. (Randy Dunlap)
|
||||
- Remove compiler warnings for newer gcc.
|
||||
- Pages are no longer kmapped by mm/filemap.c::generic_file_write()
|
||||
around calls to ->{prepare,commit}_write. Adapt NTFS appropriately
|
||||
|
@ -1201,11 +1219,11 @@ ToDo/Notes:
|
|||
the kernel. We probably want a kernel generic init_address_space()
|
||||
function...
|
||||
- Drop BKL from ntfs_readdir() after consultation with Al Viro. The
|
||||
only caller of ->readdir() is vfs_readdir() which holds i_sem during
|
||||
the call, and i_sem is sufficient protection against changes in the
|
||||
directory inode (including ->i_size).
|
||||
only caller of ->readdir() is vfs_readdir() which holds i_mutex
|
||||
during the call, and i_mutex is sufficient protection against changes
|
||||
in the directory inode (including ->i_size).
|
||||
- Use generic_file_llseek() for directories (as opposed to
|
||||
default_llseek()) as this downs i_sem instead of the BKL which is
|
||||
default_llseek()) as this downs i_mutex instead of the BKL which is
|
||||
what we now need for exclusion against ->f_pos changes considering we
|
||||
no longer take the BKL in ntfs_readdir().
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ ntfs-objs := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \
|
|||
index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \
|
||||
unistr.o upcase.o
|
||||
|
||||
EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.25\"
|
||||
EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.26\"
|
||||
|
||||
ifeq ($(CONFIG_NTFS_DEBUG),y)
|
||||
EXTRA_CFLAGS += -DDEBUG
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* aops.c - NTFS kernel address space operations and page cache handling.
|
||||
* Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2001-2006 Anton Altaparmakov
|
||||
* Copyright (c) 2002 Richard Russon
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
|
@ -200,8 +200,8 @@ static int ntfs_read_block(struct page *page)
|
|||
/* $MFT/$DATA must have its complete runlist in memory at all times. */
|
||||
BUG_ON(!ni->runlist.rl && !ni->mft_no && !NInoAttr(ni));
|
||||
|
||||
blocksize_bits = VFS_I(ni)->i_blkbits;
|
||||
blocksize = 1 << blocksize_bits;
|
||||
blocksize = vol->sb->s_blocksize;
|
||||
blocksize_bits = vol->sb->s_blocksize_bits;
|
||||
|
||||
if (!page_has_buffers(page)) {
|
||||
create_empty_buffers(page, blocksize, 0);
|
||||
|
@ -569,10 +569,8 @@ static int ntfs_write_block(struct page *page, struct writeback_control *wbc)
|
|||
|
||||
BUG_ON(!NInoNonResident(ni));
|
||||
BUG_ON(NInoMstProtected(ni));
|
||||
|
||||
blocksize_bits = vi->i_blkbits;
|
||||
blocksize = 1 << blocksize_bits;
|
||||
|
||||
blocksize = vol->sb->s_blocksize;
|
||||
blocksize_bits = vol->sb->s_blocksize_bits;
|
||||
if (!page_has_buffers(page)) {
|
||||
BUG_ON(!PageUptodate(page));
|
||||
create_empty_buffers(page, blocksize,
|
||||
|
@ -949,8 +947,8 @@ static int ntfs_write_mst_block(struct page *page,
|
|||
*/
|
||||
BUG_ON(!(is_mft || S_ISDIR(vi->i_mode) ||
|
||||
(NInoAttr(ni) && ni->type == AT_INDEX_ALLOCATION)));
|
||||
bh_size_bits = vi->i_blkbits;
|
||||
bh_size = 1 << bh_size_bits;
|
||||
bh_size = vol->sb->s_blocksize;
|
||||
bh_size_bits = vol->sb->s_blocksize_bits;
|
||||
max_bhs = PAGE_CACHE_SIZE / bh_size;
|
||||
BUG_ON(!max_bhs);
|
||||
BUG_ON(max_bhs > MAX_BUF_PER_PAGE);
|
||||
|
@ -1596,7 +1594,7 @@ void mark_ntfs_record_dirty(struct page *page, const unsigned int ofs) {
|
|||
|
||||
BUG_ON(!PageUptodate(page));
|
||||
end = ofs + ni->itype.index.block_size;
|
||||
bh_size = 1 << VFS_I(ni)->i_blkbits;
|
||||
bh_size = VFS_I(ni)->i_sb->s_blocksize;
|
||||
spin_lock(&mapping->private_lock);
|
||||
if (unlikely(!page_has_buffers(page))) {
|
||||
spin_unlock(&mapping->private_lock);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* file.c - NTFS kernel file operations. Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2001-2006 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
|
||||
|
@ -248,7 +248,7 @@ do_non_resident_extend:
|
|||
* enough to make ntfs_writepage() work.
|
||||
*/
|
||||
write_lock_irqsave(&ni->size_lock, flags);
|
||||
ni->initialized_size = (index + 1) << PAGE_CACHE_SHIFT;
|
||||
ni->initialized_size = (s64)(index + 1) << PAGE_CACHE_SHIFT;
|
||||
if (ni->initialized_size > new_init_size)
|
||||
ni->initialized_size = new_init_size;
|
||||
write_unlock_irqrestore(&ni->size_lock, flags);
|
||||
|
@ -529,8 +529,8 @@ static int ntfs_prepare_pages_for_non_resident_write(struct page **pages,
|
|||
"index 0x%lx, nr_pages 0x%x, pos 0x%llx, bytes 0x%zx.",
|
||||
vi->i_ino, ni->type, pages[0]->index, nr_pages,
|
||||
(long long)pos, bytes);
|
||||
blocksize_bits = vi->i_blkbits;
|
||||
blocksize = 1 << blocksize_bits;
|
||||
blocksize = vol->sb->s_blocksize;
|
||||
blocksize_bits = vol->sb->s_blocksize_bits;
|
||||
u = 0;
|
||||
do {
|
||||
struct page *page = pages[u];
|
||||
|
@ -1525,7 +1525,7 @@ static inline int ntfs_commit_pages_after_non_resident_write(
|
|||
|
||||
vi = pages[0]->mapping->host;
|
||||
ni = NTFS_I(vi);
|
||||
blocksize = 1 << vi->i_blkbits;
|
||||
blocksize = vi->i_sb->s_blocksize;
|
||||
end = pos + bytes;
|
||||
u = 0;
|
||||
do {
|
||||
|
|
|
@ -677,13 +677,28 @@ static int ntfs_read_locked_inode(struct inode *vi)
|
|||
ntfs_debug("Attribute list found in inode 0x%lx.", vi->i_ino);
|
||||
NInoSetAttrList(ni);
|
||||
a = ctx->attr;
|
||||
if (a->flags & ATTR_IS_ENCRYPTED ||
|
||||
a->flags & ATTR_COMPRESSION_MASK ||
|
||||
a->flags & ATTR_IS_SPARSE) {
|
||||
if (a->flags & ATTR_COMPRESSION_MASK) {
|
||||
ntfs_error(vi->i_sb, "Attribute list attribute is "
|
||||
"compressed/encrypted/sparse.");
|
||||
"compressed.");
|
||||
goto unm_err_out;
|
||||
}
|
||||
if (a->flags & ATTR_IS_ENCRYPTED ||
|
||||
a->flags & ATTR_IS_SPARSE) {
|
||||
if (a->non_resident) {
|
||||
ntfs_error(vi->i_sb, "Non-resident attribute "
|
||||
"list attribute is encrypted/"
|
||||
"sparse.");
|
||||
goto unm_err_out;
|
||||
}
|
||||
ntfs_warning(vi->i_sb, "Resident attribute list "
|
||||
"attribute in inode 0x%lx is marked "
|
||||
"encrypted/sparse which is not true. "
|
||||
"However, Windows allows this and "
|
||||
"chkdsk does not detect or correct it "
|
||||
"so we will just ignore the invalid "
|
||||
"flags and pretend they are not set.",
|
||||
vi->i_ino);
|
||||
}
|
||||
/* Now allocate memory for the attribute list. */
|
||||
ni->attr_list_size = (u32)ntfs_attr_size(a);
|
||||
ni->attr_list = ntfs_malloc_nofs(ni->attr_list_size);
|
||||
|
@ -1809,19 +1824,33 @@ int ntfs_read_inode_mount(struct inode *vi)
|
|||
} else /* if (!err) */ {
|
||||
ATTR_LIST_ENTRY *al_entry, *next_al_entry;
|
||||
u8 *al_end;
|
||||
static const char *es = " Not allowed. $MFT is corrupt. "
|
||||
"You should run chkdsk.";
|
||||
|
||||
ntfs_debug("Attribute list attribute found in $MFT.");
|
||||
NInoSetAttrList(ni);
|
||||
a = ctx->attr;
|
||||
if (a->flags & ATTR_IS_ENCRYPTED ||
|
||||
a->flags & ATTR_COMPRESSION_MASK ||
|
||||
a->flags & ATTR_IS_SPARSE) {
|
||||
if (a->flags & ATTR_COMPRESSION_MASK) {
|
||||
ntfs_error(sb, "Attribute list attribute is "
|
||||
"compressed/encrypted/sparse. Not "
|
||||
"allowed. $MFT is corrupt. You should "
|
||||
"run chkdsk.");
|
||||
"compressed.%s", es);
|
||||
goto put_err_out;
|
||||
}
|
||||
if (a->flags & ATTR_IS_ENCRYPTED ||
|
||||
a->flags & ATTR_IS_SPARSE) {
|
||||
if (a->non_resident) {
|
||||
ntfs_error(sb, "Non-resident attribute list "
|
||||
"attribute is encrypted/"
|
||||
"sparse.%s", es);
|
||||
goto put_err_out;
|
||||
}
|
||||
ntfs_warning(sb, "Resident attribute list attribute "
|
||||
"in $MFT system file is marked "
|
||||
"encrypted/sparse which is not true. "
|
||||
"However, Windows allows this and "
|
||||
"chkdsk does not detect or correct it "
|
||||
"so we will just ignore the invalid "
|
||||
"flags and pretend they are not set.");
|
||||
}
|
||||
/* Now allocate memory for the attribute list. */
|
||||
ni->attr_list_size = (u32)ntfs_attr_size(a);
|
||||
ni->attr_list = ntfs_malloc_nofs(ni->attr_list_size);
|
||||
|
|
|
@ -838,15 +838,19 @@ enum {
|
|||
F_A_DEVICE, F_A_DIRECTORY, F_A_SPARSE_FILE, F_A_REPARSE_POINT,
|
||||
F_A_COMPRESSED, and F_A_ENCRYPTED and preserves the rest. This mask
|
||||
is used to to obtain all flags that are valid for setting. */
|
||||
|
||||
/*
|
||||
* The following flags are only present in the FILE_NAME attribute (in
|
||||
* The following flag is only present in the FILE_NAME attribute (in
|
||||
* the field file_attributes).
|
||||
*/
|
||||
FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT = const_cpu_to_le32(0x10000000),
|
||||
/* Note, this is a copy of the corresponding bit from the mft record,
|
||||
telling us whether this is a directory or not, i.e. whether it has
|
||||
an index root attribute or not. */
|
||||
/*
|
||||
* The following flag is present both in the STANDARD_INFORMATION
|
||||
* attribute and in the FILE_NAME attribute (in the field
|
||||
* file_attributes).
|
||||
*/
|
||||
FILE_ATTR_DUP_VIEW_INDEX_PRESENT = const_cpu_to_le32(0x20000000),
|
||||
/* Note, this is a copy of the corresponding bit from the mft record,
|
||||
telling us whether this file has a view index present (eg. object id
|
||||
|
@ -1071,9 +1075,15 @@ typedef struct {
|
|||
modified. */
|
||||
/* 20*/ sle64 last_access_time; /* Time this mft record was last
|
||||
accessed. */
|
||||
/* 28*/ sle64 allocated_size; /* Byte size of allocated space for the
|
||||
data attribute. NOTE: Is a multiple
|
||||
of the cluster size. */
|
||||
/* 28*/ sle64 allocated_size; /* Byte size of on-disk allocated space
|
||||
for the data attribute. So for
|
||||
normal $DATA, this is the
|
||||
allocated_size from the unnamed
|
||||
$DATA attribute and for compressed
|
||||
and/or sparse $DATA, this is the
|
||||
compressed_size from the unnamed
|
||||
$DATA attribute. NOTE: This is a
|
||||
multiple of the cluster size. */
|
||||
/* 30*/ sle64 data_size; /* Byte size of actual data in data
|
||||
attribute. */
|
||||
/* 38*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */
|
||||
|
@ -1904,12 +1914,13 @@ enum {
|
|||
VOLUME_DELETE_USN_UNDERWAY = const_cpu_to_le16(0x0010),
|
||||
VOLUME_REPAIR_OBJECT_ID = const_cpu_to_le16(0x0020),
|
||||
|
||||
VOLUME_CHKDSK_UNDERWAY = const_cpu_to_le16(0x4000),
|
||||
VOLUME_MODIFIED_BY_CHKDSK = const_cpu_to_le16(0x8000),
|
||||
|
||||
VOLUME_FLAGS_MASK = const_cpu_to_le16(0x803f),
|
||||
VOLUME_FLAGS_MASK = const_cpu_to_le16(0xc03f),
|
||||
|
||||
/* To make our life easier when checking if we must mount read-only. */
|
||||
VOLUME_MUST_MOUNT_RO_MASK = const_cpu_to_le16(0x8027),
|
||||
VOLUME_MUST_MOUNT_RO_MASK = const_cpu_to_le16(0xc027),
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
typedef le16 VOLUME_FLAGS;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* mft.c - NTFS kernel mft record operations. Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2001-2006 Anton Altaparmakov
|
||||
* Copyright (c) 2002 Richard Russon
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
|
@ -473,7 +473,7 @@ int ntfs_sync_mft_mirror(ntfs_volume *vol, const unsigned long mft_no,
|
|||
runlist_element *rl;
|
||||
unsigned int block_start, block_end, m_start, m_end, page_ofs;
|
||||
int i_bhs, nr_bhs, err = 0;
|
||||
unsigned char blocksize_bits = vol->mftmirr_ino->i_blkbits;
|
||||
unsigned char blocksize_bits = vol->sb->s_blocksize_bits;
|
||||
|
||||
ntfs_debug("Entering for inode 0x%lx.", mft_no);
|
||||
BUG_ON(!max_bhs);
|
||||
|
@ -672,8 +672,8 @@ int write_mft_record_nolock(ntfs_inode *ni, MFT_RECORD *m, int sync)
|
|||
{
|
||||
ntfs_volume *vol = ni->vol;
|
||||
struct page *page = ni->page;
|
||||
unsigned char blocksize_bits = vol->mft_ino->i_blkbits;
|
||||
unsigned int blocksize = 1 << blocksize_bits;
|
||||
unsigned int blocksize = vol->sb->s_blocksize;
|
||||
unsigned char blocksize_bits = vol->sb->s_blocksize_bits;
|
||||
int max_bhs = vol->mft_record_size / blocksize;
|
||||
struct buffer_head *bhs[max_bhs];
|
||||
struct buffer_head *bh, *head;
|
||||
|
|
|
@ -50,11 +50,11 @@ typedef enum {
|
|||
/* Global variables. */
|
||||
|
||||
/* Slab caches (from super.c). */
|
||||
extern kmem_cache_t *ntfs_name_cache;
|
||||
extern kmem_cache_t *ntfs_inode_cache;
|
||||
extern kmem_cache_t *ntfs_big_inode_cache;
|
||||
extern kmem_cache_t *ntfs_attr_ctx_cache;
|
||||
extern kmem_cache_t *ntfs_index_ctx_cache;
|
||||
extern struct kmem_cache *ntfs_name_cache;
|
||||
extern struct kmem_cache *ntfs_inode_cache;
|
||||
extern struct kmem_cache *ntfs_big_inode_cache;
|
||||
extern struct kmem_cache *ntfs_attr_ctx_cache;
|
||||
extern struct kmem_cache *ntfs_index_ctx_cache;
|
||||
|
||||
/* The various operations structs defined throughout the driver files. */
|
||||
extern struct address_space_operations ntfs_aops;
|
||||
|
|
197
fs/ntfs/super.c
197
fs/ntfs/super.c
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* super.c - NTFS kernel super block handling. Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2001-2006 Anton Altaparmakov
|
||||
* Copyright (c) 2001,2002 Richard Russon
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/blkdev.h> /* For bdev_hardsect_size(). */
|
||||
|
@ -471,9 +472,16 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt)
|
|||
ntfs_error(sb, "Volume is dirty and read-only%s", es);
|
||||
return -EROFS;
|
||||
}
|
||||
if (vol->vol_flags & VOLUME_MODIFIED_BY_CHKDSK) {
|
||||
ntfs_error(sb, "Volume has been modified by chkdsk "
|
||||
"and is read-only%s", es);
|
||||
return -EROFS;
|
||||
}
|
||||
if (vol->vol_flags & VOLUME_MUST_MOUNT_RO_MASK) {
|
||||
ntfs_error(sb, "Volume has unsupported flags set and "
|
||||
"is read-only%s", es);
|
||||
ntfs_error(sb, "Volume has unsupported flags set "
|
||||
"(0x%x) and is read-only%s",
|
||||
(unsigned)le16_to_cpu(vol->vol_flags),
|
||||
es);
|
||||
return -EROFS;
|
||||
}
|
||||
if (ntfs_set_volume_flags(vol, VOLUME_IS_DIRTY)) {
|
||||
|
@ -641,7 +649,7 @@ static struct buffer_head *read_ntfs_boot_sector(struct super_block *sb,
|
|||
{
|
||||
const char *read_err_str = "Unable to read %s boot sector.";
|
||||
struct buffer_head *bh_primary, *bh_backup;
|
||||
long nr_blocks = NTFS_SB(sb)->nr_blocks;
|
||||
sector_t nr_blocks = NTFS_SB(sb)->nr_blocks;
|
||||
|
||||
/* Try to read primary boot sector. */
|
||||
if ((bh_primary = sb_bread(sb, 0))) {
|
||||
|
@ -688,13 +696,18 @@ hotfix_primary_boot_sector:
|
|||
/*
|
||||
* If we managed to read sector zero and the volume is not
|
||||
* read-only, copy the found, valid backup boot sector to the
|
||||
* primary boot sector.
|
||||
* primary boot sector. Note we only copy the actual boot
|
||||
* sector structure, not the actual whole device sector as that
|
||||
* may be bigger and would potentially damage the $Boot system
|
||||
* file (FIXME: Would be nice to know if the backup boot sector
|
||||
* on a large sector device contains the whole boot loader or
|
||||
* just the first 512 bytes).
|
||||
*/
|
||||
if (!(sb->s_flags & MS_RDONLY)) {
|
||||
ntfs_warning(sb, "Hot-fix: Recovering invalid primary "
|
||||
"boot sector from backup copy.");
|
||||
memcpy(bh_primary->b_data, bh_backup->b_data,
|
||||
sb->s_blocksize);
|
||||
NTFS_BLOCK_SIZE);
|
||||
mark_buffer_dirty(bh_primary);
|
||||
sync_dirty_buffer(bh_primary);
|
||||
if (buffer_uptodate(bh_primary)) {
|
||||
|
@ -733,9 +746,13 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b)
|
|||
vol->sector_size);
|
||||
ntfs_debug("vol->sector_size_bits = %i (0x%x)", vol->sector_size_bits,
|
||||
vol->sector_size_bits);
|
||||
if (vol->sector_size != vol->sb->s_blocksize)
|
||||
ntfs_warning(vol->sb, "The boot sector indicates a sector size "
|
||||
"different from the device sector size.");
|
||||
if (vol->sector_size < vol->sb->s_blocksize) {
|
||||
ntfs_error(vol->sb, "Sector size (%i) is smaller than the "
|
||||
"device block size (%lu). This is not "
|
||||
"supported. Sorry.", vol->sector_size,
|
||||
vol->sb->s_blocksize);
|
||||
return FALSE;
|
||||
}
|
||||
ntfs_debug("sectors_per_cluster = 0x%x", b->bpb.sectors_per_cluster);
|
||||
sectors_per_cluster_bits = ffs(b->bpb.sectors_per_cluster) - 1;
|
||||
ntfs_debug("sectors_per_cluster_bits = 0x%x",
|
||||
|
@ -748,16 +765,11 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b)
|
|||
ntfs_debug("vol->cluster_size = %i (0x%x)", vol->cluster_size,
|
||||
vol->cluster_size);
|
||||
ntfs_debug("vol->cluster_size_mask = 0x%x", vol->cluster_size_mask);
|
||||
ntfs_debug("vol->cluster_size_bits = %i (0x%x)",
|
||||
vol->cluster_size_bits, vol->cluster_size_bits);
|
||||
if (vol->sector_size > vol->cluster_size) {
|
||||
ntfs_error(vol->sb, "Sector sizes above the cluster size are "
|
||||
"not supported. Sorry.");
|
||||
return FALSE;
|
||||
}
|
||||
if (vol->sb->s_blocksize > vol->cluster_size) {
|
||||
ntfs_error(vol->sb, "Cluster sizes smaller than the device "
|
||||
"sector size are not supported. Sorry.");
|
||||
ntfs_debug("vol->cluster_size_bits = %i", vol->cluster_size_bits);
|
||||
if (vol->cluster_size < vol->sector_size) {
|
||||
ntfs_error(vol->sb, "Cluster size (%i) is smaller than the "
|
||||
"sector size (%i). This is not supported. "
|
||||
"Sorry.", vol->cluster_size, vol->sector_size);
|
||||
return FALSE;
|
||||
}
|
||||
clusters_per_mft_record = b->clusters_per_mft_record;
|
||||
|
@ -786,11 +798,18 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b)
|
|||
* we store $MFT/$DATA, the table of mft records in the page cache.
|
||||
*/
|
||||
if (vol->mft_record_size > PAGE_CACHE_SIZE) {
|
||||
ntfs_error(vol->sb, "Mft record size %i (0x%x) exceeds the "
|
||||
"page cache size on your system %lu (0x%lx). "
|
||||
ntfs_error(vol->sb, "Mft record size (%i) exceeds the "
|
||||
"PAGE_CACHE_SIZE on your system (%lu). "
|
||||
"This is not supported. Sorry.",
|
||||
vol->mft_record_size, vol->mft_record_size,
|
||||
PAGE_CACHE_SIZE, PAGE_CACHE_SIZE);
|
||||
vol->mft_record_size, PAGE_CACHE_SIZE);
|
||||
return FALSE;
|
||||
}
|
||||
/* We cannot support mft record sizes below the sector size. */
|
||||
if (vol->mft_record_size < vol->sector_size) {
|
||||
ntfs_error(vol->sb, "Mft record size (%i) is smaller than the "
|
||||
"sector size (%i). This is not supported. "
|
||||
"Sorry.", vol->mft_record_size,
|
||||
vol->sector_size);
|
||||
return FALSE;
|
||||
}
|
||||
clusters_per_index_record = b->clusters_per_index_record;
|
||||
|
@ -816,6 +835,14 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b)
|
|||
ntfs_debug("vol->index_record_size_bits = %i (0x%x)",
|
||||
vol->index_record_size_bits,
|
||||
vol->index_record_size_bits);
|
||||
/* We cannot support index record sizes below the sector size. */
|
||||
if (vol->index_record_size < vol->sector_size) {
|
||||
ntfs_error(vol->sb, "Index record size (%i) is smaller than "
|
||||
"the sector size (%i). This is not "
|
||||
"supported. Sorry.", vol->index_record_size,
|
||||
vol->sector_size);
|
||||
return FALSE;
|
||||
}
|
||||
/*
|
||||
* Get the size of the volume in clusters and check for 64-bit-ness.
|
||||
* Windows currently only uses 32 bits to save the clusters so we do
|
||||
|
@ -845,15 +872,18 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b)
|
|||
}
|
||||
ll = sle64_to_cpu(b->mft_lcn);
|
||||
if (ll >= vol->nr_clusters) {
|
||||
ntfs_error(vol->sb, "MFT LCN is beyond end of volume. Weird.");
|
||||
ntfs_error(vol->sb, "MFT LCN (%lli, 0x%llx) is beyond end of "
|
||||
"volume. Weird.", (unsigned long long)ll,
|
||||
(unsigned long long)ll);
|
||||
return FALSE;
|
||||
}
|
||||
vol->mft_lcn = ll;
|
||||
ntfs_debug("vol->mft_lcn = 0x%llx", (long long)vol->mft_lcn);
|
||||
ll = sle64_to_cpu(b->mftmirr_lcn);
|
||||
if (ll >= vol->nr_clusters) {
|
||||
ntfs_error(vol->sb, "MFTMirr LCN is beyond end of volume. "
|
||||
"Weird.");
|
||||
ntfs_error(vol->sb, "MFTMirr LCN (%lli, 0x%llx) is beyond end "
|
||||
"of volume. Weird.", (unsigned long long)ll,
|
||||
(unsigned long long)ll);
|
||||
return FALSE;
|
||||
}
|
||||
vol->mftmirr_lcn = ll;
|
||||
|
@ -1822,11 +1852,24 @@ get_ctx_vol_failed:
|
|||
/* Make sure that no unsupported volume flags are set. */
|
||||
if (vol->vol_flags & VOLUME_MUST_MOUNT_RO_MASK) {
|
||||
static const char *es1a = "Volume is dirty";
|
||||
static const char *es1b = "Volume has unsupported flags set";
|
||||
static const char *es2 = ". Run chkdsk and mount in Windows.";
|
||||
const char *es1;
|
||||
|
||||
es1 = vol->vol_flags & VOLUME_IS_DIRTY ? es1a : es1b;
|
||||
static const char *es1b = "Volume has been modified by chkdsk";
|
||||
static const char *es1c = "Volume has unsupported flags set";
|
||||
static const char *es2a = ". Run chkdsk and mount in Windows.";
|
||||
static const char *es2b = ". Mount in Windows.";
|
||||
const char *es1, *es2;
|
||||
|
||||
es2 = es2a;
|
||||
if (vol->vol_flags & VOLUME_IS_DIRTY)
|
||||
es1 = es1a;
|
||||
else if (vol->vol_flags & VOLUME_MODIFIED_BY_CHKDSK) {
|
||||
es1 = es1b;
|
||||
es2 = es2b;
|
||||
} else {
|
||||
es1 = es1c;
|
||||
ntfs_warning(sb, "Unsupported volume flags 0x%x "
|
||||
"encountered.",
|
||||
(unsigned)le16_to_cpu(vol->vol_flags));
|
||||
}
|
||||
/* 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 |
|
||||
|
@ -2685,7 +2728,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
|
|||
ntfs_volume *vol;
|
||||
struct buffer_head *bh;
|
||||
struct inode *tmp_ino;
|
||||
int result;
|
||||
int blocksize, result;
|
||||
|
||||
ntfs_debug("Entering.");
|
||||
#ifndef NTFS_RW
|
||||
|
@ -2724,60 +2767,85 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
|
|||
if (!parse_options(vol, (char*)opt))
|
||||
goto err_out_now;
|
||||
|
||||
/* We support sector sizes up to the PAGE_CACHE_SIZE. */
|
||||
if (bdev_hardsect_size(sb->s_bdev) > PAGE_CACHE_SIZE) {
|
||||
if (!silent)
|
||||
ntfs_error(sb, "Device has unsupported sector size "
|
||||
"(%i). The maximum supported sector "
|
||||
"size on this architecture is %lu "
|
||||
"bytes.",
|
||||
bdev_hardsect_size(sb->s_bdev),
|
||||
PAGE_CACHE_SIZE);
|
||||
goto err_out_now;
|
||||
}
|
||||
/*
|
||||
* TODO: Fail safety check. In the future we should really be able to
|
||||
* cope with this being the case, but for now just bail out.
|
||||
* Setup the device access block size to NTFS_BLOCK_SIZE or the hard
|
||||
* sector size, whichever is bigger.
|
||||
*/
|
||||
if (bdev_hardsect_size(sb->s_bdev) > NTFS_BLOCK_SIZE) {
|
||||
blocksize = sb_min_blocksize(sb, NTFS_BLOCK_SIZE);
|
||||
if (blocksize < NTFS_BLOCK_SIZE) {
|
||||
if (!silent)
|
||||
ntfs_error(sb, "Device has unsupported hardsect_size.");
|
||||
ntfs_error(sb, "Unable to set device block size.");
|
||||
goto err_out_now;
|
||||
}
|
||||
|
||||
/* Setup the device access block size to NTFS_BLOCK_SIZE. */
|
||||
if (sb_set_blocksize(sb, NTFS_BLOCK_SIZE) != NTFS_BLOCK_SIZE) {
|
||||
BUG_ON(blocksize != sb->s_blocksize);
|
||||
ntfs_debug("Set device block size to %i bytes (block size bits %i).",
|
||||
blocksize, sb->s_blocksize_bits);
|
||||
/* Determine the size of the device in units of block_size bytes. */
|
||||
if (!i_size_read(sb->s_bdev->bd_inode)) {
|
||||
if (!silent)
|
||||
ntfs_error(sb, "Unable to set block size.");
|
||||
ntfs_error(sb, "Unable to determine device size.");
|
||||
goto err_out_now;
|
||||
}
|
||||
|
||||
/* Get the size of the device in units of NTFS_BLOCK_SIZE bytes. */
|
||||
vol->nr_blocks = i_size_read(sb->s_bdev->bd_inode) >>
|
||||
NTFS_BLOCK_SIZE_BITS;
|
||||
|
||||
sb->s_blocksize_bits;
|
||||
/* Read the boot sector and return unlocked buffer head to it. */
|
||||
if (!(bh = read_ntfs_boot_sector(sb, silent))) {
|
||||
if (!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
|
||||
* Extract the data from the boot sector and setup the ntfs volume
|
||||
* using it.
|
||||
*/
|
||||
result = parse_ntfs_boot_sector(vol, (NTFS_BOOT_SECTOR*)bh->b_data);
|
||||
|
||||
/* Initialize the cluster and mft allocators. */
|
||||
ntfs_setup_allocators(vol);
|
||||
|
||||
brelse(bh);
|
||||
|
||||
if (!result) {
|
||||
if (!silent)
|
||||
ntfs_error(sb, "Unsupported NTFS filesystem.");
|
||||
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).
|
||||
* If the boot sector indicates a sector size bigger than the current
|
||||
* device block size, switch the device block size to the sector size.
|
||||
* TODO: It may be possible to support this case even when the set
|
||||
* below fails, we would just be breaking up the i/o for each sector
|
||||
* into multiple blocks for i/o purposes but otherwise it should just
|
||||
* work. However it is safer to leave disabled until someone hits this
|
||||
* error message and then we can get them to try it without the setting
|
||||
* so we know for sure that it works.
|
||||
*/
|
||||
|
||||
if (vol->sector_size > blocksize) {
|
||||
blocksize = sb_set_blocksize(sb, vol->sector_size);
|
||||
if (blocksize != vol->sector_size) {
|
||||
if (!silent)
|
||||
ntfs_error(sb, "Unable to set device block "
|
||||
"size to sector size (%i).",
|
||||
vol->sector_size);
|
||||
goto err_out_now;
|
||||
}
|
||||
BUG_ON(blocksize != sb->s_blocksize);
|
||||
vol->nr_blocks = i_size_read(sb->s_bdev->bd_inode) >>
|
||||
sb->s_blocksize_bits;
|
||||
ntfs_debug("Changed device block size to %i bytes (block size "
|
||||
"bits %i) to match volume sector size.",
|
||||
blocksize, sb->s_blocksize_bits);
|
||||
}
|
||||
/* Initialize the cluster and mft allocators. */
|
||||
ntfs_setup_allocators(vol);
|
||||
/* Setup remaining fields in the super block. */
|
||||
sb->s_magic = NTFS_SB_MAGIC;
|
||||
|
||||
/*
|
||||
* Ntfs allows 63 bits for the file size, i.e. correct would be:
|
||||
* sb->s_maxbytes = ~0ULL >> 1;
|
||||
|
@ -2787,9 +2855,8 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
|
|||
* without overflowing the index or to 2^63 - 1, whichever is smaller.
|
||||
*/
|
||||
sb->s_maxbytes = MAX_LFS_FILESIZE;
|
||||
|
||||
/* Ntfs measures time in 100ns intervals. */
|
||||
sb->s_time_gran = 100;
|
||||
|
||||
/*
|
||||
* Now load the metadata required for the page cache and our address
|
||||
* space operations to function. We do this by setting up a specialised
|
||||
|
@ -2987,14 +3054,14 @@ err_out_now:
|
|||
* strings of the maximum length allowed by NTFS, which is NTFS_MAX_NAME_LEN
|
||||
* (255) Unicode characters + a terminating NULL Unicode character.
|
||||
*/
|
||||
kmem_cache_t *ntfs_name_cache;
|
||||
struct kmem_cache *ntfs_name_cache;
|
||||
|
||||
/* Slab caches for efficient allocation/deallocation of inodes. */
|
||||
kmem_cache_t *ntfs_inode_cache;
|
||||
kmem_cache_t *ntfs_big_inode_cache;
|
||||
struct kmem_cache *ntfs_inode_cache;
|
||||
struct kmem_cache *ntfs_big_inode_cache;
|
||||
|
||||
/* Init once constructor for the inode slab cache. */
|
||||
static void ntfs_big_inode_init_once(void *foo, kmem_cache_t *cachep,
|
||||
static void ntfs_big_inode_init_once(void *foo, struct kmem_cache *cachep,
|
||||
unsigned long flags)
|
||||
{
|
||||
ntfs_inode *ni = (ntfs_inode *)foo;
|
||||
|
@ -3008,8 +3075,8 @@ static void ntfs_big_inode_init_once(void *foo, kmem_cache_t *cachep,
|
|||
* Slab caches to optimize allocations and deallocations of attribute search
|
||||
* contexts and index contexts, respectively.
|
||||
*/
|
||||
kmem_cache_t *ntfs_attr_ctx_cache;
|
||||
kmem_cache_t *ntfs_index_ctx_cache;
|
||||
struct kmem_cache *ntfs_attr_ctx_cache;
|
||||
struct kmem_cache *ntfs_index_ctx_cache;
|
||||
|
||||
/* Driver wide semaphore. */
|
||||
DECLARE_MUTEX(ntfs_lock);
|
||||
|
|
|
@ -3,10 +3,7 @@
|
|||
* Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001 Richard Russon <ntfs@flatcap.org>
|
||||
* Copyright (c) 2001-2004 Anton Altaparmakov
|
||||
*
|
||||
* Modified for mkntfs inclusion 9 June 2001 by Anton Altaparmakov.
|
||||
* Modified for kernel inclusion 10 September 2001 by Anton Altparmakov.
|
||||
* Copyright (c) 2001-2006 Anton Altaparmakov
|
||||
*
|
||||
* This program 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
|
||||
|
@ -75,12 +72,13 @@ ntfschar *generate_default_upcase(void)
|
|||
if (!uc)
|
||||
return uc;
|
||||
memset(uc, 0, default_upcase_len * sizeof(ntfschar));
|
||||
/* Generate the little endian Unicode upcase table used by ntfs. */
|
||||
for (i = 0; i < default_upcase_len; i++)
|
||||
uc[i] = cpu_to_le16(i);
|
||||
for (r = 0; uc_run_table[r][0]; r++)
|
||||
for (i = uc_run_table[r][0]; i < uc_run_table[r][1]; i++)
|
||||
uc[i] = cpu_to_le16((le16_to_cpu(uc[i]) +
|
||||
uc_run_table[r][2]));
|
||||
uc[i] = cpu_to_le16(le16_to_cpu(uc[i]) +
|
||||
uc_run_table[r][2]);
|
||||
for (r = 0; uc_dup_table[r][0]; r++)
|
||||
for (i = uc_dup_table[r][0]; i < uc_dup_table[r][1]; i += 2)
|
||||
uc[i + 1] = cpu_to_le16(le16_to_cpu(uc[i + 1]) - 1);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* volume.h - Defines for volume structures in NTFS Linux kernel driver. Part
|
||||
* of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2001-2006 Anton Altaparmakov
|
||||
* Copyright (c) 2002 Richard Russon
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
|
@ -41,10 +41,8 @@ typedef struct {
|
|||
* structure has stabilized... (AIA)
|
||||
*/
|
||||
/* Device specifics. */
|
||||
struct super_block *sb; /* Pointer back to the super_block,
|
||||
so we don't have to get the offset
|
||||
every time. */
|
||||
LCN nr_blocks; /* Number of NTFS_BLOCK_SIZE bytes
|
||||
struct super_block *sb; /* Pointer back to the super_block. */
|
||||
LCN nr_blocks; /* Number of sb->s_blocksize bytes
|
||||
sized blocks on the device. */
|
||||
/* Configuration provided by user at mount time. */
|
||||
unsigned long flags; /* Miscellaneous flags, see below. */
|
||||
|
@ -141,8 +139,8 @@ typedef enum {
|
|||
NV_ShowSystemFiles, /* 1: Return system files in ntfs_readdir(). */
|
||||
NV_CaseSensitive, /* 1: Treat file names as case sensitive and
|
||||
create filenames in the POSIX namespace.
|
||||
Otherwise be case insensitive and create
|
||||
file names in WIN32 namespace. */
|
||||
Otherwise be case insensitive but still
|
||||
create file names in POSIX namespace. */
|
||||
NV_LogFileEmpty, /* 1: $LogFile journal is empty. */
|
||||
NV_QuotaOutOfDate, /* 1: $Quota is out of date. */
|
||||
NV_UsnJrnlStamped, /* 1: $UsnJrnl has been stamped. */
|
||||
|
@ -153,7 +151,7 @@ typedef enum {
|
|||
* Macro tricks to expand the NVolFoo(), NVolSetFoo(), and NVolClearFoo()
|
||||
* functions.
|
||||
*/
|
||||
#define NVOL_FNS(flag) \
|
||||
#define DEFINE_NVOL_BIT_OPS(flag) \
|
||||
static inline int NVol##flag(ntfs_volume *vol) \
|
||||
{ \
|
||||
return test_bit(NV_##flag, &(vol)->flags); \
|
||||
|
@ -168,12 +166,12 @@ static inline void NVolClear##flag(ntfs_volume *vol) \
|
|||
}
|
||||
|
||||
/* Emit the ntfs volume bitops functions. */
|
||||
NVOL_FNS(Errors)
|
||||
NVOL_FNS(ShowSystemFiles)
|
||||
NVOL_FNS(CaseSensitive)
|
||||
NVOL_FNS(LogFileEmpty)
|
||||
NVOL_FNS(QuotaOutOfDate)
|
||||
NVOL_FNS(UsnJrnlStamped)
|
||||
NVOL_FNS(SparseEnabled)
|
||||
DEFINE_NVOL_BIT_OPS(Errors)
|
||||
DEFINE_NVOL_BIT_OPS(ShowSystemFiles)
|
||||
DEFINE_NVOL_BIT_OPS(CaseSensitive)
|
||||
DEFINE_NVOL_BIT_OPS(LogFileEmpty)
|
||||
DEFINE_NVOL_BIT_OPS(QuotaOutOfDate)
|
||||
DEFINE_NVOL_BIT_OPS(UsnJrnlStamped)
|
||||
DEFINE_NVOL_BIT_OPS(SparseEnabled)
|
||||
|
||||
#endif /* _LINUX_NTFS_VOLUME_H */
|
||||
|
|
Loading…
Reference in a new issue