Commit 6bb39cd9 authored by Anton Altaparmakov's avatar Anton Altaparmakov

NTFS: 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.
parent 24255033
...@@ -247,6 +247,9 @@ ChangeLog ...@@ -247,6 +247,9 @@ 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.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
......
...@@ -21,7 +21,34 @@ ToDo: ...@@ -21,7 +21,34 @@ ToDo:
several copies of almost identicall functions and the functions are several copies of almost identicall functions and the functions are
quite big. Modularising them a bit, e.g. a-la get_block(), will make quite big. Modularising them a bit, e.g. a-la get_block(), will make
them cleaner and make code reuse easier. them cleaner and make code reuse easier.
- Want to use dummy inodes for address space i/o. - Enable NFS exporting of NTFS.
- Use iget5_locked() and friends instead of conventional iget().
- Use fake inodes for address space i/o.
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 +65,10 @@ ToDo: ...@@ -38,7 +65,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.11\"
ifeq ($(CONFIG_NTFS_DEBUG),y) ifeq ($(CONFIG_NTFS_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG EXTRA_CFLAGS += -DDEBUG
......
...@@ -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);
......
...@@ -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