Commit 66b0ca10 authored by Anton Altaparmakov's avatar Anton Altaparmakov

Merge cantab.net:/usr/src/bklinux-2.5

into cantab.net:/usr/src/tng-2.0.12
parents 4a91b05f b30de928
...@@ -247,6 +247,12 @@ ChangeLog ...@@ -247,6 +247,12 @@ ChangeLog
Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog. Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
2.0.12:
- Internal cleanups in address space operations made possible by the
changes introduced in the previous release.
2.0.11:
- Internal updates and cleanups introducing the first step towards
fake inode based attribute i/o.
2.0.10: 2.0.10:
- Microsoft says that the maximum number of inodes is 2^32 - 1. Update - Microsoft says that the maximum number of inodes is 2^32 - 1. Update
the driver accordingly to only use 32-bits to store inode numbers on the driver accordingly to only use 32-bits to store inode numbers on
......
...@@ -6,7 +6,7 @@ ToDo: ...@@ -6,7 +6,7 @@ ToDo:
user open()s a file with i_size > s_maxbytes? Should read_inode() user open()s a file with i_size > s_maxbytes? Should read_inode()
truncate the visible i_size? Will the user just get -E2BIG (or truncate the visible i_size? Will the user just get -E2BIG (or
whatever) on open()? Or will (s)he be able to open() but lseek() and whatever) on open()? Or will (s)he be able to open() but lseek() and
read() will fail when s_maxbytes is reached? -> Investigate this! read() will fail when s_maxbytes is reached? -> Investigate this.
- Implement/allow non-resident index bitmaps in dir.c::ntfs_readdir() - Implement/allow non-resident index bitmaps in dir.c::ntfs_readdir()
and then also consider initialized_size w.r.t. the bitmaps, etc. and then also consider initialized_size w.r.t. the bitmaps, etc.
- vcn_to_lcn() should somehow return the correct pointer within the - vcn_to_lcn() should somehow return the correct pointer within the
...@@ -17,11 +17,52 @@ ToDo: ...@@ -17,11 +17,52 @@ ToDo:
- Consider if ntfs_file_read_compressed_block() shouldn't be coping - Consider if ntfs_file_read_compressed_block() shouldn't be coping
with initialized_size < data_size. I don't think it can happen but with initialized_size < data_size. I don't think it can happen but
it requires more careful consideration. it requires more careful consideration.
- CLEANUP: Modularise and reuse code in aops.c. At the moment we have - CLEANUP: At the moment we have two copies of almost identical
several copies of almost identicall functions and the functions are functions in aops.c, can merge them once fake inode address space
quite big. Modularising them a bit, e.g. a-la get_block(), will make based attribute i/o is further developed.
them cleaner and make code reuse easier. - CLEANUP: Modularising code in aops.c a bit, e.g. a-la get_block(),
- Want to use dummy inodes for address space i/o. will be cleaner and make code reuse easier.
- Enable NFS exporting of NTFS.
- Use iget5_locked() and friends instead of conventional iget().
- Use fake inodes for address space i/o.
2.0.12 - Initial cleanup of address space operations following 2.0.11 changes.
- Merge fs/ntfs/aops.c::end_buffer_read_mst_async() and
fs/ntfs/aops.c::end_buffer_read_file_async() into one function
fs/ntfs/aops.c::end_buffer_read_attr_async() using NInoMstProtected()
to determine whether to apply mst fixups or not.
- Above change allows merging fs/ntfs/aops.c::ntfs_file_read_block()
and fs/ntfs/aops.c::ntfs_mst_readpage() into one function
fs/ntfs/aops.c::ntfs_attr_read_block(). Also, create a tiny wrapper
fs/ntfs/aops.c::ntfs_mst_readpage() to transform the parameters from
the VFS readpage function prototype to the ntfs_attr_read_block()
function prototype.
2.0.11 - Initial preparations for fake inode based attribute i/o.
- Move definition of ntfs_inode_state_bits to fs/ntfs/inode.h and
do some macro magic (adapted from include/linux/buffer_head.h) to
expand all the helper functions NInoFoo(), NInoSetFoo(), and
NInoClearFoo().
- Add new flag to ntfs_inode_state_bits: NI_Sparse.
- Add new fields to ntfs_inode structure to allow use of fake inodes
for attribute i/o: type, name, name_len. Also add new state bits:
NI_Attr, which, if set, indicates the inode is a fake inode, and
NI_MstProtected, which, if set, indicates the attribute uses multi
sector transfer protection, i.e. fixups need to be applied after
reads and before/after writes.
- Rename fs/ntfs/inode.c::ntfs_{new,clear,destroy}_inode() to
ntfs_{new,clear,destroy}_extent_inode() and update callers.
- Use ntfs_clear_extent_inode() in fs/ntfs/inode.c::__ntfs_clear_inode()
instead of ntfs_destroy_extent_inode().
- Cleanup memory deallocations in {__,}ntfs_clear_{,big_}inode().
- Make all operations on ntfs inode state bits use the NIno* functions.
- Set up the new ntfs inode fields and state bits in
fs/ntfs/inode.c::ntfs_read_inode() and add appropriate cleanup of
allocated memory to __ntfs_clear_inode().
- Cleanup ntfs_inode structure a bit for better ordering of elements
w.r.t. their size to allow better packing of the structure in memory.
2.0.10 - There can only be 2^32 - 1 inodes on an NTFS volume. 2.0.10 - There can only be 2^32 - 1 inodes on an NTFS volume.
...@@ -38,7 +79,10 @@ ToDo: ...@@ -38,7 +79,10 @@ ToDo:
- Change decompression engine to use a single buffer protected by a - Change decompression engine to use a single buffer protected by a
spin lock instead of per-CPU buffers. (Rusty Russell) spin lock instead of per-CPU buffers. (Rusty Russell)
- Switch to using the new KM_BIO_SRC_IRQ for atomic kmaps. (Andrew - Do not update cb_pos when handling a partial final page during
decompression of a sparse compression block, as the value is later
reset without being read/used. (Rusty Russell)
- Switch to using the new KM_BIO_SRC_IRQ for atomic kmap()s. (Andrew
Morton) Morton)
- Change buffer size in ntfs_readdir()/ntfs_filldir() to use - Change buffer size in ntfs_readdir()/ntfs_filldir() to use
NLS_MAX_CHARSET_SIZE which makes the buffers almost 1kiB each but NLS_MAX_CHARSET_SIZE which makes the buffers almost 1kiB each but
......
...@@ -5,7 +5,7 @@ obj-$(CONFIG_NTFS_FS) += ntfs.o ...@@ -5,7 +5,7 @@ obj-$(CONFIG_NTFS_FS) += ntfs.o
ntfs-objs := aops.o attrib.o compress.o debug.o dir.o file.o inode.o mft.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 time.o unistr.o upcase.o
EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.10\" EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.12\"
ifeq ($(CONFIG_NTFS_DEBUG),y) ifeq ($(CONFIG_NTFS_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG EXTRA_CFLAGS += -DDEBUG
......
This diff is collapsed.
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
/** /**
* The little endian Unicode string $I30 as a global constant. * The little endian Unicode string $I30 as a global constant.
*/ */
const uchar_t I30[5] = { const_cpu_to_le16('$'), const_cpu_to_le16('I'), uchar_t I30[5] = { const_cpu_to_le16('$'), const_cpu_to_le16('I'),
const_cpu_to_le16('3'), const_cpu_to_le16('0'), const_cpu_to_le16('3'), const_cpu_to_le16('0'),
const_cpu_to_le16(0) }; const_cpu_to_le16(0) };
......
...@@ -38,7 +38,7 @@ typedef struct { ...@@ -38,7 +38,7 @@ typedef struct {
} __attribute__ ((__packed__)) ntfs_name; } __attribute__ ((__packed__)) ntfs_name;
/* The little endian Unicode string $I30 as a global constant. */ /* The little endian Unicode string $I30 as a global constant. */
extern const uchar_t I30[5]; extern uchar_t I30[5];
extern MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, extern MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni,
const uchar_t *uname, const int uname_len, ntfs_name **res); const uchar_t *uname, const int uname_len, ntfs_name **res);
......
...@@ -49,7 +49,7 @@ void ntfs_destroy_big_inode(struct inode *inode) ...@@ -49,7 +49,7 @@ void ntfs_destroy_big_inode(struct inode *inode)
kmem_cache_free(ntfs_big_inode_cache, NTFS_I(inode)); kmem_cache_free(ntfs_big_inode_cache, NTFS_I(inode));
} }
ntfs_inode *ntfs_alloc_inode(void) ntfs_inode *ntfs_alloc_extent_inode(void)
{ {
ntfs_inode *ni = (ntfs_inode *)kmem_cache_alloc(ntfs_inode_cache, ntfs_inode *ni = (ntfs_inode *)kmem_cache_alloc(ntfs_inode_cache,
SLAB_NOFS); SLAB_NOFS);
...@@ -59,7 +59,7 @@ ntfs_inode *ntfs_alloc_inode(void) ...@@ -59,7 +59,7 @@ ntfs_inode *ntfs_alloc_inode(void)
return ni; return ni;
} }
void ntfs_destroy_inode(ntfs_inode *ni) void ntfs_destroy_extent_inode(ntfs_inode *ni)
{ {
ntfs_debug("Entering."); ntfs_debug("Entering.");
BUG_ON(atomic_read(&ni->mft_count) || !atomic_dec_and_test(&ni->count)); BUG_ON(atomic_read(&ni->mft_count) || !atomic_dec_and_test(&ni->count));
...@@ -102,9 +102,9 @@ static void ntfs_init_big_inode(struct inode *vi) ...@@ -102,9 +102,9 @@ static void ntfs_init_big_inode(struct inode *vi)
return; return;
} }
ntfs_inode *ntfs_new_inode(struct super_block *sb) ntfs_inode *ntfs_new_extent_inode(struct super_block *sb)
{ {
ntfs_inode *ni = ntfs_alloc_inode(); ntfs_inode *ni = ntfs_alloc_extent_inode();
ntfs_debug("Entering."); ntfs_debug("Entering.");
if (ni) if (ni)
...@@ -239,7 +239,8 @@ void ntfs_read_inode(struct inode *vi) ...@@ -239,7 +239,8 @@ void ntfs_read_inode(struct inode *vi)
/* /*
* Initialize the ntfs specific part of @vi special casing * Initialize the ntfs specific part of @vi special casing
* FILE_MFT which we need to do at mount time. * FILE_MFT which we need to do at mount time. This also sets
* ni->mft_no to vi->i_ino.
*/ */
if (vi->i_ino != FILE_MFT) if (vi->i_ino != FILE_MFT)
ntfs_init_big_inode(vi); ntfs_init_big_inode(vi);
...@@ -358,13 +359,14 @@ void ntfs_read_inode(struct inode *vi) ...@@ -358,13 +359,14 @@ void ntfs_read_inode(struct inode *vi)
if (vi->i_ino == FILE_MFT) if (vi->i_ino == FILE_MFT)
goto skip_attr_list_load; goto skip_attr_list_load;
ntfs_debug("Attribute list found in inode 0x%lx.", vi->i_ino); ntfs_debug("Attribute list found in inode 0x%lx.", vi->i_ino);
ni->state |= 1 << NI_AttrList; NInoSetAttrList(ni);
if (ctx->attr->flags & ATTR_IS_ENCRYPTED || if (ctx->attr->flags & ATTR_IS_ENCRYPTED ||
ctx->attr->flags & ATTR_COMPRESSION_MASK) { ctx->attr->flags & ATTR_COMPRESSION_MASK ||
ctx->attr->flags & ATTR_IS_SPARSE) {
ntfs_error(vi->i_sb, "Attribute list attribute is " ntfs_error(vi->i_sb, "Attribute list attribute is "
"compressed/encrypted. Not allowed. " "compressed/encrypted/sparse. Not "
"Corrupt inode. You should run " "allowed. Corrupt inode. You should "
"chkdsk."); "run chkdsk.");
goto put_unm_err_out; goto put_unm_err_out;
} }
/* Now allocate memory for the attribute list. */ /* Now allocate memory for the attribute list. */
...@@ -377,7 +379,7 @@ void ntfs_read_inode(struct inode *vi) ...@@ -377,7 +379,7 @@ void ntfs_read_inode(struct inode *vi)
goto ec_put_unm_err_out; goto ec_put_unm_err_out;
} }
if (ctx->attr->non_resident) { if (ctx->attr->non_resident) {
ni->state |= 1 << NI_AttrListNonResident; NInoSetAttrListNonResident(ni);
if (ctx->attr->_ANR(lowest_vcn)) { if (ctx->attr->_ANR(lowest_vcn)) {
ntfs_error(vi->i_sb, "Attribute list has non " ntfs_error(vi->i_sb, "Attribute list has non "
"zero lowest_vcn. Inode is " "zero lowest_vcn. Inode is "
...@@ -459,7 +461,7 @@ void ntfs_read_inode(struct inode *vi) ...@@ -459,7 +461,7 @@ void ntfs_read_inode(struct inode *vi)
* encrypted. * encrypted.
*/ */
if (ctx->attr->flags & ATTR_COMPRESSION_MASK) if (ctx->attr->flags & ATTR_COMPRESSION_MASK)
ni->state |= 1 << NI_Compressed; NInoSetCompressed(ni);
if (ctx->attr->flags & ATTR_IS_ENCRYPTED) { if (ctx->attr->flags & ATTR_IS_ENCRYPTED) {
if (ctx->attr->flags & ATTR_COMPRESSION_MASK) { if (ctx->attr->flags & ATTR_COMPRESSION_MASK) {
ntfs_error(vi->i_sb, "Found encrypted and " ntfs_error(vi->i_sb, "Found encrypted and "
...@@ -467,8 +469,10 @@ void ntfs_read_inode(struct inode *vi) ...@@ -467,8 +469,10 @@ void ntfs_read_inode(struct inode *vi)
"allowed."); "allowed.");
goto put_unm_err_out; goto put_unm_err_out;
} }
ni->state |= 1 << NI_Encrypted; NInoSetEncrypted(ni);
} }
if (ctx->attr->flags & ATTR_IS_SPARSE)
NInoSetSparse(ni);
ir = (INDEX_ROOT*)((char*)ctx->attr + ir = (INDEX_ROOT*)((char*)ctx->attr +
le16_to_cpu(ctx->attr->_ARA(value_offset))); le16_to_cpu(ctx->attr->_ARA(value_offset)));
ir_end = (char*)ir + le32_to_cpu(ctx->attr->_ARA(value_length)); ir_end = (char*)ir + le32_to_cpu(ctx->attr->_ARA(value_length));
...@@ -530,12 +534,19 @@ void ntfs_read_inode(struct inode *vi) ...@@ -530,12 +534,19 @@ void ntfs_read_inode(struct inode *vi)
ni->_IDM(index_vcn_size) = vol->sector_size; ni->_IDM(index_vcn_size) = vol->sector_size;
ni->_IDM(index_vcn_size_bits) = vol->sector_size_bits; ni->_IDM(index_vcn_size_bits) = vol->sector_size_bits;
} }
/* Setup the index allocation attribute, even if not present. */
NInoSetMstProtected(ni);
ni->type = AT_INDEX_ALLOCATION;
ni->name = I30;
ni->name_len = 4;
if (!(ir->index.flags & LARGE_INDEX)) { if (!(ir->index.flags & LARGE_INDEX)) {
/* No index allocation. */ /* No index allocation. */
vi->i_size = ni->initialized_size = 0; vi->i_size = ni->initialized_size = 0;
goto skip_large_dir_stuff; goto skip_large_dir_stuff;
} /* LARGE_INDEX: Index allocation present. Setup state. */ } /* LARGE_INDEX: Index allocation present. Setup state. */
ni->state |= 1 << NI_NonResident; NInoSetIndexAllocPresent(ni);
/* Find index allocation attribute. */ /* Find index allocation attribute. */
reinit_attr_search_ctx(ctx); reinit_attr_search_ctx(ctx);
if (!lookup_attr(AT_INDEX_ALLOCATION, I30, 4, CASE_SENSITIVE, if (!lookup_attr(AT_INDEX_ALLOCATION, I30, 4, CASE_SENSITIVE,
...@@ -555,6 +566,11 @@ void ntfs_read_inode(struct inode *vi) ...@@ -555,6 +566,11 @@ void ntfs_read_inode(struct inode *vi)
"is encrypted."); "is encrypted.");
goto put_unm_err_out; goto put_unm_err_out;
} }
if (ctx->attr->flags & ATTR_IS_SPARSE) {
ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
"is sparse.");
goto put_unm_err_out;
}
if (ctx->attr->flags & ATTR_COMPRESSION_MASK) { if (ctx->attr->flags & ATTR_COMPRESSION_MASK) {
ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute " ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
"is compressed."); "is compressed.");
...@@ -581,13 +597,13 @@ void ntfs_read_inode(struct inode *vi) ...@@ -581,13 +597,13 @@ void ntfs_read_inode(struct inode *vi)
goto put_unm_err_out; goto put_unm_err_out;
} }
if (ctx->attr->flags & (ATTR_COMPRESSION_MASK | if (ctx->attr->flags & (ATTR_COMPRESSION_MASK |
ATTR_IS_ENCRYPTED)) { ATTR_IS_ENCRYPTED | ATTR_IS_SPARSE)) {
ntfs_error(vi->i_sb, "$BITMAP attribute is compressed " ntfs_error(vi->i_sb, "$BITMAP attribute is compressed "
"and/or encrypted."); "and/or encrypted and/or sparse.");
goto put_unm_err_out; goto put_unm_err_out;
} }
if (ctx->attr->non_resident) { if (ctx->attr->non_resident) {
ni->state |= 1 << NI_BmpNonResident; NInoSetBmpNonResident(ni);
if (ctx->attr->_ANR(lowest_vcn)) { if (ctx->attr->_ANR(lowest_vcn)) {
ntfs_error(vi->i_sb, "First extent of $BITMAP " ntfs_error(vi->i_sb, "First extent of $BITMAP "
"attribute has non zero " "attribute has non zero "
...@@ -647,6 +663,12 @@ void ntfs_read_inode(struct inode *vi) ...@@ -647,6 +663,12 @@ void ntfs_read_inode(struct inode *vi)
} else { } else {
/* It is a file: find first extent of unnamed data attribute. */ /* It is a file: find first extent of unnamed data attribute. */
reinit_attr_search_ctx(ctx); reinit_attr_search_ctx(ctx);
/* Setup the data attribute, even if not present. */
ni->type = AT_DATA;
ni->name = NULL;
ni->name_len = 0;
if (!lookup_attr(AT_DATA, NULL, 0, 0, 0, NULL, 0, ctx)) { if (!lookup_attr(AT_DATA, NULL, 0, 0, 0, NULL, 0, ctx)) {
vi->i_size = ni->initialized_size = vi->i_size = ni->initialized_size =
ni->allocated_size = 0LL; ni->allocated_size = 0LL;
...@@ -675,9 +697,9 @@ void ntfs_read_inode(struct inode *vi) ...@@ -675,9 +697,9 @@ void ntfs_read_inode(struct inode *vi)
} }
/* Setup the state. */ /* Setup the state. */
if (ctx->attr->non_resident) { if (ctx->attr->non_resident) {
ni->state |= 1 << NI_NonResident; NInoSetNonResident(ni);
if (ctx->attr->flags & ATTR_COMPRESSION_MASK) { if (ctx->attr->flags & ATTR_COMPRESSION_MASK) {
ni->state |= 1 << NI_Compressed; NInoSetCompressed(ni);
if (vol->cluster_size > 4096) { if (vol->cluster_size > 4096) {
ntfs_error(vi->i_sb, "Found " ntfs_error(vi->i_sb, "Found "
"compressed data but " "compressed data but "
...@@ -707,8 +729,9 @@ void ntfs_read_inode(struct inode *vi) ...@@ -707,8 +729,9 @@ void ntfs_read_inode(struct inode *vi)
goto ec_put_unm_err_out; goto ec_put_unm_err_out;
} }
ni->_ICF(compression_block_size) = 1U << ( ni->_ICF(compression_block_size) = 1U << (
ctx->attr->_ANR(compression_unit) ctx->attr->_ANR(
+ vol->cluster_size_bits); compression_unit) +
vol->cluster_size_bits);
ni->_ICF(compression_block_size_bits) = ffs( ni->_ICF(compression_block_size_bits) = ffs(
ni->_ICF(compression_block_size)) - 1; ni->_ICF(compression_block_size)) - 1;
} }
...@@ -718,8 +741,10 @@ void ntfs_read_inode(struct inode *vi) ...@@ -718,8 +741,10 @@ void ntfs_read_inode(struct inode *vi)
"and compressed data."); "and compressed data.");
goto put_unm_err_out; goto put_unm_err_out;
} }
ni->state |= 1 << NI_Encrypted; NInoSetEncrypted(ni);
} }
if (ctx->attr->flags & ATTR_IS_SPARSE)
NInoSetSparse(ni);
if (ctx->attr->_ANR(lowest_vcn)) { if (ctx->attr->_ANR(lowest_vcn)) {
ntfs_error(vi->i_sb, "First extent of $DATA " ntfs_error(vi->i_sb, "First extent of $DATA "
"attribute has non zero " "attribute has non zero "
...@@ -861,6 +886,13 @@ void ntfs_read_inode_mount(struct inode *vi) ...@@ -861,6 +886,13 @@ void ntfs_read_inode_mount(struct inode *vi)
goto err_out; goto err_out;
} }
/* Setup the data attribute. It is special as it is mst protected. */
NInoSetNonResident(ni);
NInoSetMstProtected(ni);
ni->type = AT_DATA;
ni->name = NULL;
ni->name_len = 0;
/* /*
* This sets up our little cheat allowing us to reuse the async io * This sets up our little cheat allowing us to reuse the async io
* completion handler for directories. * completion handler for directories.
...@@ -930,13 +962,14 @@ void ntfs_read_inode_mount(struct inode *vi) ...@@ -930,13 +962,14 @@ void ntfs_read_inode_mount(struct inode *vi)
u8 *al_end; u8 *al_end;
ntfs_debug("Attribute list attribute found in $MFT."); ntfs_debug("Attribute list attribute found in $MFT.");
ni->state |= 1 << NI_AttrList; NInoSetAttrList(ni);
if (ctx->attr->flags & ATTR_IS_ENCRYPTED || if (ctx->attr->flags & ATTR_IS_ENCRYPTED ||
ctx->attr->flags & ATTR_COMPRESSION_MASK) { ctx->attr->flags & ATTR_COMPRESSION_MASK ||
ctx->attr->flags & ATTR_IS_SPARSE) {
ntfs_error(sb, "Attribute list attribute is " ntfs_error(sb, "Attribute list attribute is "
"compressed/encrypted. Not allowed. " "compressed/encrypted/sparse. Not "
"$MFT is corrupt. You should run " "allowed. $MFT is corrupt. You should "
"chkdsk."); "run chkdsk.");
goto put_err_out; goto put_err_out;
} }
/* Now allocate memory for the attribute list. */ /* Now allocate memory for the attribute list. */
...@@ -948,7 +981,7 @@ void ntfs_read_inode_mount(struct inode *vi) ...@@ -948,7 +981,7 @@ void ntfs_read_inode_mount(struct inode *vi)
goto put_err_out; goto put_err_out;
} }
if (ctx->attr->non_resident) { if (ctx->attr->non_resident) {
ni->state |= 1 << NI_AttrListNonResident; NInoSetAttrListNonResident(ni);
if (ctx->attr->_ANR(lowest_vcn)) { if (ctx->attr->_ANR(lowest_vcn)) {
ntfs_error(sb, "Attribute list has non zero " ntfs_error(sb, "Attribute list has non zero "
"lowest_vcn. $MFT is corrupt. " "lowest_vcn. $MFT is corrupt. "
...@@ -1071,11 +1104,13 @@ void ntfs_read_inode_mount(struct inode *vi) ...@@ -1071,11 +1104,13 @@ void ntfs_read_inode_mount(struct inode *vi)
} }
/* $MFT must be uncompressed and unencrypted. */ /* $MFT must be uncompressed and unencrypted. */
if (attr->flags & ATTR_COMPRESSION_MASK || if (attr->flags & ATTR_COMPRESSION_MASK ||
attr->flags & ATTR_IS_ENCRYPTED) { attr->flags & ATTR_IS_ENCRYPTED ||
ntfs_error(sb, "$MFT must be uncompressed and " attr->flags & ATTR_IS_SPARSE) {
"unencrypted but a compressed/" ntfs_error(sb, "$MFT must be uncompressed, "
"encrypted extent was found. " "non-sparse, and unencrypted but a "
"$MFT is corrupt. Run chkdsk."); "compressed/sparse/encrypted extent "
"was found. $MFT is corrupt. Run "
"chkdsk.");
goto put_err_out; goto put_err_out;
} }
/* /*
...@@ -1296,29 +1331,42 @@ void __ntfs_clear_inode(ntfs_inode *ni) ...@@ -1296,29 +1331,42 @@ void __ntfs_clear_inode(ntfs_inode *ni)
// FIXME: Handle dirty case for each extent inode! // FIXME: Handle dirty case for each extent inode!
for (i = 0; i < ni->nr_extents; i++) for (i = 0; i < ni->nr_extents; i++)
ntfs_destroy_inode(ni->_INE(extent_ntfs_inos)[i]); ntfs_clear_extent_inode(ni->_INE(extent_ntfs_inos)[i]);
kfree(ni->_INE(extent_ntfs_inos)); kfree(ni->_INE(extent_ntfs_inos));
} }
/* Free all alocated memory. */ /* Free all alocated memory. */
down_write(&ni->run_list.lock); down_write(&ni->run_list.lock);
ntfs_free(ni->run_list.rl); if (ni->run_list.rl) {
ni->run_list.rl = NULL; ntfs_free(ni->run_list.rl);
ni->run_list.rl = NULL;
}
up_write(&ni->run_list.lock); up_write(&ni->run_list.lock);
ntfs_free(ni->attr_list); if (ni->attr_list) {
ntfs_free(ni->attr_list);
ni->attr_list = NULL;
}
down_write(&ni->attr_list_rl.lock); down_write(&ni->attr_list_rl.lock);
ntfs_free(ni->attr_list_rl.rl); if (ni->attr_list_rl.rl) {
ni->attr_list_rl.rl = NULL; ntfs_free(ni->attr_list_rl.rl);
ni->attr_list_rl.rl = NULL;
}
up_write(&ni->attr_list_rl.lock); up_write(&ni->attr_list_rl.lock);
if (ni->name_len && ni->name != I30) {
/* Catch bugs... */
BUG_ON(!ni->name);
kfree(ni->name);
}
} }
void ntfs_clear_inode(ntfs_inode *ni) void ntfs_clear_extent_inode(ntfs_inode *ni)
{ {
__ntfs_clear_inode(ni); __ntfs_clear_inode(ni);
/* Bye, bye... */ /* Bye, bye... */
ntfs_destroy_inode(ni); ntfs_destroy_extent_inode(ni);
} }
/** /**
...@@ -1339,7 +1387,8 @@ void ntfs_clear_big_inode(struct inode *vi) ...@@ -1339,7 +1387,8 @@ void ntfs_clear_big_inode(struct inode *vi)
if (S_ISDIR(vi->i_mode)) { if (S_ISDIR(vi->i_mode)) {
down_write(&ni->_IDM(bmp_rl).lock); down_write(&ni->_IDM(bmp_rl).lock);
ntfs_free(ni->_IDM(bmp_rl).rl); if (ni->_IDM(bmp_rl).rl)
ntfs_free(ni->_IDM(bmp_rl).rl);
up_write(&ni->_IDM(bmp_rl).lock); up_write(&ni->_IDM(bmp_rl).lock);
} }
return; return;
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* the Linux-NTFS project. * the Linux-NTFS project.
* *
* Copyright (c) 2001,2002 Anton Altaparmakov. * Copyright (c) 2001,2002 Anton Altaparmakov.
* Copyright (C) 2002 Richard Russon. * Copyright (c) 2002 Richard Russon.
* *
* This program/include file is free software; you can redistribute it and/or * 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 * modify it under the terms of the GNU General Public License as published
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include "layout.h"
#include "volume.h" #include "volume.h"
typedef struct _ntfs_inode ntfs_inode; typedef struct _ntfs_inode ntfs_inode;
...@@ -38,21 +39,39 @@ struct _ntfs_inode { ...@@ -38,21 +39,39 @@ struct _ntfs_inode {
s64 initialized_size; /* Copy from $DATA/$INDEX_ALLOCATION. */ s64 initialized_size; /* Copy from $DATA/$INDEX_ALLOCATION. */
s64 allocated_size; /* Copy from $DATA/$INDEX_ALLOCATION. */ s64 allocated_size; /* Copy from $DATA/$INDEX_ALLOCATION. */
unsigned long state; /* NTFS specific flags describing this inode. unsigned long state; /* NTFS specific flags describing this inode.
See fs/ntfs/ntfs.h:ntfs_inode_state_bits. */ See ntfs_inode_state_bits below. */
unsigned long mft_no; /* Number of the mft record / inode. */ unsigned long mft_no; /* Number of the mft record / inode. */
u16 seq_no; /* Sequence number of the mft record. */ u16 seq_no; /* Sequence number of the mft record. */
atomic_t count; /* Inode reference count for book keeping. */ atomic_t count; /* Inode reference count for book keeping. */
ntfs_volume *vol; /* Pointer to the ntfs volume of this inode. */ ntfs_volume *vol; /* Pointer to the ntfs volume of this inode. */
/*
* If NInoAttr() is true, the below fields describe the attribute which
* this fake inode belongs to. The actual inode of this attribute is
* pointed to by base_ntfs_ino and nr_extents is always set to -1 (see
* below). For real inodes, we also set the type (AT_DATA for files and
* AT_INDEX_ALLOCATION for directories), with the name = NULL and
* name_len = 0 for files and name = I30 (global constant) and
* name_len = 4 for directories.
*/
ATTR_TYPES type; /* Attribute type of this fake inode. */
uchar_t *name; /* Attribute name of this fake inode. */
u32 name_len; /* Attribute name length of this fake inode. */
run_list run_list; /* If state has the NI_NonResident bit set, run_list run_list; /* If state has the NI_NonResident bit set,
the run list of the unnamed data attribute the run list of the unnamed data attribute
(if a file) or of the index allocation (if a file) or of the index allocation
attribute (directory). If run_list.rl is attribute (directory) or of the attribute
NULL, the run list has not been read in or described by the fake inode (if NInoAttr()).
has been unmapped. If NI_NonResident is If run_list.rl is NULL, the run list has not
clear, the unnamed data attribute is been read in yet or has been unmapped. If
resident (file) or there is no $I30 index NI_NonResident is clear, the attribute is
allocation attribute (directory). In that resident (file and fake inode) or there is
case run_list.rl is always NULL.*/ no $I30 index allocation attribute
(small directory). In the latter case
run_list.rl is always NULL.*/
/*
* The following fields are only valid for real inodes and extent
* inodes.
*/
struct rw_semaphore mrec_lock; /* Lock for serializing access to the struct rw_semaphore mrec_lock; /* Lock for serializing access to the
mft record belonging to this inode. */ mft record belonging to this inode. */
atomic_t mft_count; /* Mapping reference count for book keeping. */ atomic_t mft_count; /* Mapping reference count for book keeping. */
...@@ -74,17 +93,18 @@ struct _ntfs_inode { ...@@ -74,17 +93,18 @@ struct _ntfs_inode {
union { union {
struct { /* It is a directory or $MFT. */ struct { /* It is a directory or $MFT. */
u32 index_block_size; /* Size of an index block. */ u32 index_block_size; /* Size of an index block. */
u8 index_block_size_bits; /* Log2 of the above. */
u32 index_vcn_size; /* Size of a vcn in this u32 index_vcn_size; /* Size of a vcn in this
directory index. */ directory index. */
u8 index_vcn_size_bits; /* Log2 of the above. */
s64 bmp_size; /* Size of the $I30 bitmap. */ s64 bmp_size; /* Size of the $I30 bitmap. */
s64 bmp_initialized_size; /* Copy from $I30 bitmap. */ s64 bmp_initialized_size; /* Copy from $I30 bitmap. */
s64 bmp_allocated_size; /* Copy from $I30 bitmap. */ s64 bmp_allocated_size; /* Copy from $I30 bitmap. */
run_list bmp_rl; /* Run list for the $I30 bitmap run_list bmp_rl; /* Run list for the $I30 bitmap
if it is non-resident. */ if it is non-resident. */
u8 index_block_size_bits; /* Log2 of the above. */
u8 index_vcn_size_bits; /* Log2 of the above. */
} SN(idm); } SN(idm);
struct { /* It is a compressed file. */ struct { /* It is a compressed file or fake inode. */
s64 compressed_size; /* Copy from $DATA. */
u32 compression_block_size; /* Size of a compression u32 compression_block_size; /* Size of a compression
block (cb). */ block (cb). */
u8 compression_block_size_bits; /* Log2 of the size of u8 compression_block_size_bits; /* Log2 of the size of
...@@ -92,13 +112,13 @@ struct _ntfs_inode { ...@@ -92,13 +112,13 @@ struct _ntfs_inode {
u8 compression_block_clusters; /* Number of clusters u8 compression_block_clusters; /* Number of clusters
per compression per compression
block. */ block. */
s64 compressed_size; /* Copy from $DATA. */
} SN(icf); } SN(icf);
} SN(idc); } SN(idc);
struct semaphore extent_lock; /* Lock for accessing/modifying the struct semaphore extent_lock; /* Lock for accessing/modifying the
below . */ below . */
s32 nr_extents; /* For a base mft record, the number of attached extent s32 nr_extents; /* For a base mft record, the number of attached extent
inodes (0 if none), for extent records this is -1. */ inodes (0 if none), for extent records and for fake
inodes describing an attribute this is -1. */
union { /* This union is only used if nr_extents != 0. */ union { /* This union is only used if nr_extents != 0. */
ntfs_inode **extent_ntfs_inos; /* For nr_extents > 0, array of ntfs_inode **extent_ntfs_inos; /* For nr_extents > 0, array of
the ntfs inodes of the extent the ntfs inodes of the extent
...@@ -107,7 +127,9 @@ struct _ntfs_inode { ...@@ -107,7 +127,9 @@ struct _ntfs_inode {
been loaded. */ been loaded. */
ntfs_inode *base_ntfs_ino; /* For nr_extents == -1, the ntfs_inode *base_ntfs_ino; /* For nr_extents == -1, the
ntfs inode of the base mft ntfs inode of the base mft
record. */ record. For fake inodes, the
real (base) inode to which
the attribute belongs. */
} SN(ine); } SN(ine);
}; };
...@@ -115,6 +137,79 @@ struct _ntfs_inode { ...@@ -115,6 +137,79 @@ struct _ntfs_inode {
#define _ICF(X) SC(idc.icf,X) #define _ICF(X) SC(idc.icf,X)
#define _INE(X) SC(ine,X) #define _INE(X) SC(ine,X)
/*
* Defined bits for the state field in the ntfs_inode structure.
* (f) = files only, (d) = directories only, (a) = attributes/fake inodes only
*/
typedef enum {
NI_Dirty, /* 1: Mft record needs to be written to disk. */
NI_AttrList, /* 1: Mft record contains an attribute list. */
NI_AttrListNonResident, /* 1: Attribute list is non-resident. Implies
NI_AttrList is set. */
NI_Attr, /* 1: Fake inode for attribute i/o.
0: Real inode or extent inode. */
NI_MstProtected, /* 1: Attribute is protected by MST fixups.
0: Attribute is not protected by fixups. */
NI_NonResident, /* 1: Unnamed data attr is non-resident (f).
1: Attribute is non-resident (a). */
NI_IndexAllocPresent = NI_NonResident, /* 1: $I30 index alloc attr is
present (d). */
NI_Compressed, /* 1: Unnamed data attr is compressed (f).
1: Create compressed files by default (d).
1: Attribute is compressed (a). */
NI_Encrypted, /* 1: Unnamed data attr is encrypted (f).
1: Create encrypted files by default (d).
1: Attribute is encrypted (a). */
NI_Sparse, /* 1: Unnamed data attr is sparse (f).
1: Create sparse files by default (d).
1: Attribute is sparse (a). */
NI_BmpNonResident, /* 1: $I30 bitmap attr is non resident (d). */
} ntfs_inode_state_bits;
/*
* NOTE: We should be adding dirty mft records to a list somewhere and they
* should be independent of the (ntfs/vfs) inode structure so that an inode can
* be removed but the record can be left dirty for syncing later.
*/
/*
* Macro tricks to expand the NInoFoo(), NInoSetFoo(), and NInoClearFoo()
* functions.
*/
#define NINO_FNS(flag) \
static inline int NIno##flag(ntfs_inode *ni) \
{ \
return test_bit(NI_##flag, &(ni)->state); \
} \
static inline void NInoSet##flag(ntfs_inode *ni) \
{ \
set_bit(NI_##flag, &(ni)->state); \
} \
static inline void NInoClear##flag(ntfs_inode *ni) \
{ \
clear_bit(NI_##flag, &(ni)->state); \
}
/* Emit the ntfs inode bitops functions. */
NINO_FNS(Dirty)
NINO_FNS(AttrList)
NINO_FNS(AttrListNonResident)
NINO_FNS(Attr)
NINO_FNS(MstProtected)
NINO_FNS(NonResident)
NINO_FNS(IndexAllocPresent)
NINO_FNS(Compressed)
NINO_FNS(Encrypted)
NINO_FNS(Sparse)
NINO_FNS(BmpNonResident)
/*
* The full structure containing a ntfs_inode and a vfs struct inode. Used for
* all real and fake inodes but not for extent inodes which lack the vfs struct
* inode.
*/
typedef struct { typedef struct {
ntfs_inode ntfs_inode; ntfs_inode ntfs_inode;
struct inode vfs_inode; /* The vfs inode structure. */ struct inode vfs_inode; /* The vfs inode structure. */
...@@ -140,8 +235,8 @@ extern struct inode *ntfs_alloc_big_inode(struct super_block *sb); ...@@ -140,8 +235,8 @@ extern struct inode *ntfs_alloc_big_inode(struct super_block *sb);
extern void ntfs_destroy_big_inode(struct inode *inode); extern void ntfs_destroy_big_inode(struct inode *inode);
extern void ntfs_clear_big_inode(struct inode *vi); extern void ntfs_clear_big_inode(struct inode *vi);
extern ntfs_inode *ntfs_new_inode(struct super_block *sb); extern ntfs_inode *ntfs_new_extent_inode(struct super_block *sb);
extern void ntfs_clear_inode(ntfs_inode *ni); extern void ntfs_clear_extent_inode(ntfs_inode *ni);
extern void ntfs_read_inode(struct inode *vi); extern void ntfs_read_inode(struct inode *vi);
extern void ntfs_read_inode_mount(struct inode *vi); extern void ntfs_read_inode_mount(struct inode *vi);
......
...@@ -102,7 +102,7 @@ extern int ntfs_mst_readpage(struct file *, struct page *); ...@@ -102,7 +102,7 @@ extern int ntfs_mst_readpage(struct file *, struct page *);
* ntfs_mft_aops - address space operations for access to $MFT * ntfs_mft_aops - address space operations for access to $MFT
* *
* Address space operations for access to $MFT. This allows us to simply use * Address space operations for access to $MFT. This allows us to simply use
* read_cache_page() in map_mft_record(). * ntfs_map_page() in map_mft_record_page().
*/ */
struct address_space_operations ntfs_mft_aops = { struct address_space_operations ntfs_mft_aops = {
writepage: NULL, /* Write dirty page to disk. */ writepage: NULL, /* Write dirty page to disk. */
...@@ -334,9 +334,9 @@ void unmap_mft_record(const int rw, ntfs_inode *ni) ...@@ -334,9 +334,9 @@ void unmap_mft_record(const int rw, ntfs_inode *ni)
/* /*
* If pure ntfs_inode, i.e. no vfs inode attached, we leave it to * If pure ntfs_inode, i.e. no vfs inode attached, we leave it to
* ntfs_clear_inode() in the extent inode case, and to the caller in * ntfs_clear_extent_inode() in the extent inode case, and to the
* the non-extent, yet pure ntfs inode case, to do the actual tear * caller in the non-extent, yet pure ntfs inode case, to do the actual
* down of all structures and freeing of all allocated memory. * tear down of all structures and freeing of all allocated memory.
*/ */
return; return;
} }
...@@ -417,7 +417,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref, ...@@ -417,7 +417,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
return m; return m;
} }
/* Record wasn't there. Get a new ntfs inode and initialize it. */ /* Record wasn't there. Get a new ntfs inode and initialize it. */
ni = ntfs_new_inode(base_ni->vol->sb); ni = ntfs_new_extent_inode(base_ni->vol->sb);
if (!ni) { if (!ni) {
up(&base_ni->extent_lock); up(&base_ni->extent_lock);
atomic_dec(&base_ni->count); atomic_dec(&base_ni->count);
...@@ -433,7 +433,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref, ...@@ -433,7 +433,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
if (IS_ERR(m)) { if (IS_ERR(m)) {
up(&base_ni->extent_lock); up(&base_ni->extent_lock);
atomic_dec(&base_ni->count); atomic_dec(&base_ni->count);
ntfs_clear_inode(ni); ntfs_clear_extent_inode(ni);
goto map_err_out; goto map_err_out;
} }
/* Verify the sequence number. */ /* Verify the sequence number. */
...@@ -479,7 +479,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref, ...@@ -479,7 +479,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
* release it or we will leak memory. * release it or we will leak memory.
*/ */
if (destroy_ni) if (destroy_ni)
ntfs_clear_inode(ni); ntfs_clear_extent_inode(ni);
return m; return m;
} }
...@@ -53,41 +53,6 @@ typedef enum { ...@@ -53,41 +53,6 @@ typedef enum {
NTFS_MAX_NAME_LEN = 255, NTFS_MAX_NAME_LEN = 255,
} NTFS_CONSTANTS; } NTFS_CONSTANTS;
/*
* Defined bits for the state field in the ntfs_inode structure.
* (f) = files only, (d) = directories only
*/
typedef enum {
NI_Dirty, /* 1: Mft record needs to be written to disk. */
NI_AttrList, /* 1: Mft record contains an attribute list. */
NI_AttrListNonResident, /* 1: Attribute list is non-resident. Implies
NI_AttrList is set. */
NI_NonResident, /* 1: Unnamed data attr is non-resident (f).
1: $I30 index alloc attr is present (d). */
NI_Compressed, /* 1: Unnamed data attr is compressed (f).
1: Create compressed files by default (d). */
NI_Encrypted, /* 1: Unnamed data attr is encrypted (f).
1: Create encrypted files by default (d). */
NI_BmpNonResident, /* 1: $I30 bitmap attr is non resident (d). */
} ntfs_inode_state_bits;
/*
* NOTE: We should be adding dirty mft records to a list somewhere and they
* should be independent of the (ntfs/vfs) inode structure so that an inode can
* be removed but the record can be left dirty for syncing later.
*/
#define NInoDirty(n_ino) test_bit(NI_Dirty, &(n_ino)->state)
#define NInoSetDirty(n_ino) set_bit(NI_Dirty, &(n_ino)->state)
#define NInoClearDirty(n_ino) clear_bit(NI_Dirty, &(n_ino)->state)
#define NInoAttrList(n_ino) test_bit(NI_AttrList, &(n_ino)->state)
#define NInoNonResident(n_ino) test_bit(NI_NonResident, &(n_ino)->state)
#define NInoIndexAllocPresent(n_ino) test_bit(NI_NonResident, &(n_ino)->state)
#define NInoCompressed(n_ino) test_bit(NI_Compressed, &(n_ino)->state)
#define NInoEncrypted(n_ino) test_bit(NI_Encrypted, &(n_ino)->state)
#define NInoBmpNonResident(n_ino) test_bit(NI_BmpNonResident, &(n_ino)->state)
/* Global variables. */ /* Global variables. */
/* Slab caches (from super.c). */ /* Slab caches (from super.c). */
......
...@@ -1709,10 +1709,11 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) ...@@ -1709,10 +1709,11 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
} }
#undef OGIN #undef OGIN
/* /*
* This is needed to get ntfs_clear_inode() called for each inode we * This is needed to get ntfs_clear_extent_inode() called for each
* have ever called iget()/iput() on, otherwise we A) leak resources * inode we have ever called iget()/iput() on, otherwise we A) leak
* and B) a subsequent mount fails automatically due to iget() never * resources and B) a subsequent mount fails automatically due to
* calling down into our ntfs_read_inode{_mount}() methods again... * iget() never calling down into our ntfs_read_inode{_mount}() methods
* again...
*/ */
if (invalidate_inodes(sb)) { if (invalidate_inodes(sb)) {
ntfs_error(sb, "Busy inodes left. This is most likely a NTFS " ntfs_error(sb, "Busy inodes left. This is most likely a NTFS "
......
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