| From: |
| Anton Altaparmakov <aia21@cantab.net> |
| To: |
| torvalds@transmeta.com (Linus Torvalds) |
| Subject: |
| NTFS: 2.0.15 - Fake inodes based attribute i/o via the page cache, fixes, cleanups |
| Date: |
| Mon, 8 Jul 2002 18:47:31 +0100 (BST) |
| Cc: |
| linux-kernel@vger.kernel.org (Linux Kernel) |
Linus, please do a
bk pull http://linux-ntfs.bkbits.net/ntfs-tng-2.5
Thanks!
Fake inode based i/o is now fully implemented. Only cleanups left to do
but the patch was getting big so I stopped here...
Best regards,
Anton
--
Anton Altaparmakov <aia21 at cantab.net> (replace at with @)
Linux NTFS maintainer / IRC: #ntfs on irc.openprojects.net
WWW: http://linux-ntfs.sf.net/, http://www-stu.christs.cam.ac.uk/~aia21/
===================================================================
This will update the following files:
Documentation/filesystems/ntfs.txt | 5
fs/ntfs/ChangeLog | 29 +++
fs/ntfs/Makefile | 2
fs/ntfs/aops.c | 135 +++++----------
fs/ntfs/attrib.c | 55 +-----
fs/ntfs/compress.c | 5
fs/ntfs/inode.c | 321 ++++++++++++++++++++++++++++++++++++-
fs/ntfs/mft.c | 18 +-
fs/ntfs/ntfs.h | 19 +-
fs/ntfs/super.c | 13 -
fs/ntfs/volume.h | 58 +++---
11 files changed, 481 insertions(+), 179 deletions(-)
through these ChangeSets:
<aia21@cantab.net> (02/07/08 1.617)
NTFS: 2.0.15 - Fake inodes based attribute i/o via the pagecache, fixes, cleanups.
- Fix silly bug in fs/ntfs/super.c::parse_options() which was causing
remounts to fail when the partition had an entry in /etc/fstab and
the entry specified the nls= option.
- Apply same macro magic used in fs/ntfs/inode.h to fs/ntfs/volume.h to
expand all the helper functions NVolFoo(), NVolSetFoo(), and
NVolClearFoo().
- Move copyright statement from driver initialisation message to
module description (fs/super.c). This makes the initialisation
message fit on one line and fits in better with rest of kernel.
- Update fs/ntfs/attrib.c::map_run_list() to work on both real and
attribute inodes, and both for files and directories.
- Implement fake attribute inodes allowing all attribute i/o to go via
the page cache and to use all the normal vfs/mm functionality:
- Add ntfs_attr_iget() and its helper ntfs_read_locked_attr_inode()
to fs/ntfs/inode.c.
- Add needed cleanup code to ntfs_clear_big_inode().
- Merge address space operations for files and directories (aops.c),
now just have ntfs_aops:
- Rename:
end_buffer_read_attr_async() -> ntfs_end_buffer_read_async(),
ntfs_attr_read_block() -> ntfs_read_block(),
ntfs_file_read_page() -> ntfs_readpage().
- Rewrite fs/ntfs/aops.c::ntfs_readpage() to work on both real and
attribute inodes, and both for files and directories.
- Remove obsolete fs/ntfs/aops.c::ntfs_mst_readpage().
diff -Nru a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt
--- a/Documentation/filesystems/ntfs.txt Mon Jul 8 18:41:18 2002
+++ b/Documentation/filesystems/ntfs.txt Mon Jul 8 18:41:18 2002
@@ -247,6 +247,11 @@
Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
+2.0.15:
+ - Bug fix in parsing of remount options.
+ - Internal changes implementing attribute (fake) inodes allowing all
+ attribute i/o to go via the page cache and to use all the normal
+ vfs/mm functionality.
2.0.14:
- Internal changes improving run list merging code and minor locking
change to not rely on BKL in ntfs_statfs().
diff -Nru a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog
--- a/fs/ntfs/ChangeLog Mon Jul 8 18:41:18 2002
+++ b/fs/ntfs/ChangeLog Mon Jul 8 18:41:18 2002
@@ -26,7 +26,34 @@
callers, i.e. ntfs_iget(), to pass that error code up instead of just
using -EIO.
- Enable NFS exporting of NTFS.
- - Use fake inodes for address space i/o.
+
+2.0.15 - Fake inodes based attribute i/o via the pagecache, fixes and cleanups.
+
+ - Fix silly bug in fs/ntfs/super.c::parse_options() which was causing
+ remounts to fail when the partition had an entry in /etc/fstab and
+ the entry specified the nls= option.
+ - Apply same macro magic used in fs/ntfs/inode.h to fs/ntfs/volume.h to
+ expand all the helper functions NVolFoo(), NVolSetFoo(), and
+ NVolClearFoo().
+ - Move copyright statement from driver initialisation message to
+ module description (fs/super.c). This makes the initialisation
+ message fit on one line and fits in better with rest of kernel.
+ - Update fs/ntfs/attrib.c::map_run_list() to work on both real and
+ attribute inodes, and both for files and directories.
+ - Implement fake attribute inodes allowing all attribute i/o to go via
+ the page cache and to use all the normal vfs/mm functionality:
+ - Add ntfs_attr_iget() and its helper ntfs_read_locked_attr_inode()
+ to fs/ntfs/inode.c.
+ - Add needed cleanup code to ntfs_clear_big_inode().
+ - Merge address space operations for files and directories (aops.c),
+ now just have ntfs_aops:
+ - Rename:
+ end_buffer_read_attr_async() -> ntfs_end_buffer_read_async(),
+ ntfs_attr_read_block() -> ntfs_read_block(),
+ ntfs_file_read_page() -> ntfs_readpage().
+ - Rewrite fs/ntfs/aops.c::ntfs_readpage() to work on both real and
+ attribute inodes, and both for files and directories.
+ - Remove obsolete fs/ntfs/aops.c::ntfs_mst_readpage().
2.0.14 - Run list merging code cleanup, minor locking changes, typo fixes.
diff -Nru a/fs/ntfs/Makefile b/fs/ntfs/Makefile
--- a/fs/ntfs/Makefile Mon Jul 8 18:41:18 2002
+++ b/fs/ntfs/Makefile Mon Jul 8 18:41:18 2002
@@ -5,7 +5,7 @@
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
-EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.14\"
+EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.15\"
ifeq ($(CONFIG_NTFS_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
diff -Nru a/fs/ntfs/aops.c b/fs/ntfs/aops.c
--- a/fs/ntfs/aops.c Mon Jul 8 18:41:18 2002
+++ b/fs/ntfs/aops.c Mon Jul 8 18:41:18 2002
@@ -30,7 +30,7 @@
#include "ntfs.h"
/**
- * end_buffer_read_attr_async - async io completion for reading attributes
+ * ntfs_end_buffer_read_async - async io completion for reading attributes
* @bh: buffer head on which io is completed
* @uptodate: whether @bh is now uptodate or not
*
@@ -45,7 +45,7 @@
* record size, and index_block_size_bits, to the log(base 2) of the ntfs
* record size.
*/
-static void end_buffer_read_attr_async(struct buffer_head *bh, int uptodate)
+static void ntfs_end_buffer_read_async(struct buffer_head *bh, int uptodate)
{
static spinlock_t page_uptodate_lock = SPIN_LOCK_UNLOCKED;
unsigned long flags;
@@ -143,12 +143,12 @@
}
/**
- * ntfs_attr_read_block - fill a @page of an address space with data
+ * ntfs_read_block - fill a @page of an address space with data
* @page: page cache page to fill with data
*
* Fill the page @page of the address space belonging to the @page->host inode.
* We read each buffer asynchronously and when all buffers are read in, our io
- * completion handler end_buffer_read_attr_async(), if required, automatically
+ * completion handler ntfs_end_buffer_read_async(), if required, automatically
* applies the mst fixups to the page before finally marking it uptodate and
* unlocking it.
*
@@ -156,7 +156,7 @@
*
* Contains an adapted version of fs/buffer.c::block_read_full_page().
*/
-static int ntfs_attr_read_block(struct page *page)
+static int ntfs_read_block(struct page *page)
{
VCN vcn;
LCN lcn;
@@ -267,7 +267,7 @@
for (i = 0; i < nr; i++) {
struct buffer_head *tbh = arr[i];
lock_buffer(tbh);
- tbh->b_end_io = end_buffer_read_attr_async;
+ tbh->b_end_io = ntfs_end_buffer_read_async;
set_buffer_async_read(tbh);
}
/* Finally, start i/o on the buffers. */
@@ -285,27 +285,27 @@
}
/**
- * ntfs_file_readpage - fill a @page of a @file with data from the device
+ * ntfs_readpage - fill a @page of a @file with data from the device
* @file: open file to which the page @page belongs or NULL
* @page: page cache page to fill with data
*
- * For non-resident attributes, ntfs_file_readpage() fills the @page of the open
+ * For non-resident attributes, ntfs_readpage() fills the @page of the open
* file @file by calling the ntfs version of the generic block_read_full_page()
- * function provided by the kernel, ntfs_attr_read_block(), which in turn
- * creates and reads in the buffers associated with the page asynchronously.
+ * function, ntfs_read_block(), which in turn creates and reads in the buffers
+ * associated with the page asynchronously.
*
- * For resident attributes, OTOH, ntfs_file_readpage() fills @page by copying
- * the data from the mft record (which at this stage is most likely in memory)
- * and fills the remainder with zeroes. Thus, in this case, I/O is synchronous,
- * as even if the mft record is not cached at this point in time, we need to
- * wait for it to be read in before we can do the copy.
+ * For resident attributes, OTOH, ntfs_readpage() fills @page by copying the
+ * data from the mft record (which at this stage is most likely in memory) and
+ * fills the remainder with zeroes. Thus, in this case, I/O is synchronous, as
+ * even if the mft record is not cached at this point in time, we need to wait
+ * for it to be read in before we can do the copy.
*
- * Return 0 on success or -errno on error.
+ * Return 0 on success and -errno on error.
*/
-static int ntfs_file_readpage(struct file *file, struct page *page)
+int ntfs_readpage(struct file *file, struct page *page)
{
s64 attr_pos;
- ntfs_inode *ni;
+ ntfs_inode *ni, *base_ni;
char *addr;
attr_search_context *ctx;
MFT_RECORD *mrec;
@@ -317,40 +317,45 @@
ni = NTFS_I(page->mapping->host);
- /* Is the unnamed $DATA attribute resident? */
if (NInoNonResident(ni)) {
- /* Attribute is not resident. */
-
- /* If the file is encrypted, we deny access, just like NT4. */
- if (NInoEncrypted(ni)) {
- err = -EACCES;
- goto unl_err_out;
- }
- /* Compressed data stream. Handled in compress.c. */
- if (NInoCompressed(ni))
- return ntfs_file_read_compressed_block(page);
+ /*
+ * Only unnamed $DATA attributes can be compressed or
+ * encrypted.
+ */
+ if (ni->type == AT_DATA && !ni->name_len) {
+ /* If file is encrypted, deny access, just like NT4. */
+ if (NInoEncrypted(ni)) {
+ err = -EACCES;
+ goto err_out;
+ }
+ /* Compressed data streams are handled in compress.c. */
+ if (NInoCompressed(ni))
+ return ntfs_file_read_compressed_block(page);
+ }
/* Normal data stream. */
- return ntfs_attr_read_block(page);
+ return ntfs_read_block(page);
}
/* Attribute is resident, implying it is not compressed or encrypted. */
+ if (!NInoAttr(ni))
+ base_ni = ni;
+ else
+ base_ni = ni->_INE(base_ntfs_ino);
/* Map, pin and lock the mft record for reading. */
- mrec = map_mft_record(READ, ni);
+ mrec = map_mft_record(READ, base_ni);
if (unlikely(IS_ERR(mrec))) {
err = PTR_ERR(mrec);
- goto unl_err_out;
+ goto err_out;
}
-
- ctx = get_attr_search_ctx(ni, mrec);
+ ctx = get_attr_search_ctx(base_ni, mrec);
if (unlikely(!ctx)) {
err = -ENOMEM;
- goto unm_unl_err_out;
+ goto unm_err_out;
}
-
- /* Find the data attribute in the mft record. */
- if (unlikely(!lookup_attr(AT_DATA, NULL, 0, 0, 0, NULL, 0, ctx))) {
+ if (unlikely(!lookup_attr(ni->type, ni->name, ni->name_len,
+ IGNORE_CASE, 0, NULL, 0, ctx))) {
err = -ENOENT;
- goto put_unm_unl_err_out;
+ goto put_unm_err_out;
}
/* Starting position of the page within the attribute value. */
@@ -377,35 +382,16 @@
kunmap(page);
SetPageUptodate(page);
-put_unm_unl_err_out:
+put_unm_err_out:
put_attr_search_ctx(ctx);
-unm_unl_err_out:
- unmap_mft_record(READ, ni);
-unl_err_out:
+unm_err_out:
+ unmap_mft_record(READ, base_ni);
+err_out:
unlock_page(page);
return err;
}
/**
- * ntfs_mst_readpage - fill a @page of the mft or a directory with data
- * @file: open file/directory to which the @page belongs or NULL
- * @page: page cache page to fill with data
- *
- * Readpage method for the VFS address space operations of directory inodes
- * and the $MFT/$DATA attribute.
- *
- * We just call ntfs_attr_read_block() here, in fact we only need this wrapper
- * because of the difference in function parameters.
- */
-int ntfs_mst_readpage(struct file *file, struct page *page)
-{
- if (unlikely(!PageLocked(page)))
- PAGE_BUG(page);
-
- return ntfs_attr_read_block(page);
-}
-
-/**
* end_buffer_read_mftbmp_async -
*
* Async io completion handler for accessing mft bitmap. Adapted from
@@ -473,7 +459,7 @@
/**
* ntfs_mftbmp_readpage -
*
- * Readpage for accessing mft bitmap. Adapted from ntfs_mst_readpage().
+ * Readpage for accessing mft bitmap.
*/
static int ntfs_mftbmp_readpage(ntfs_volume *vol, struct page *page)
{
@@ -587,11 +573,11 @@
}
/**
- * ntfs_file_aops - address space operations for accessing normal file data
+ * ntfs_aops - general address space operations for inodes and attributes
*/
-struct address_space_operations ntfs_file_aops = {
+struct address_space_operations ntfs_aops = {
writepage: NULL, /* Write dirty page to disk. */
- readpage: ntfs_file_readpage, /* Fill page with data. */
+ readpage: ntfs_readpage, /* Fill page with data. */
sync_page: block_sync_page, /* Currently, just unplugs the
disk request queue. */
prepare_write: NULL, /* . */
@@ -607,23 +593,6 @@
writepage: NULL, /* Write dirty page to disk. */
readpage: (readpage_t*)ntfs_mftbmp_readpage, /* Fill page with
data. */
- sync_page: block_sync_page, /* Currently, just unplugs the
- disk request queue. */
- prepare_write: NULL, /* . */
- commit_write: NULL, /* . */
-};
-
-/**
- * ntfs_dir_aops -
- *
- * Address space operations for accessing normal directory data (i.e. index
- * allocation attribute). We can't just use the same operations as for files
- * because 1) the attribute is different and even more importantly 2) the index
- * records have to be multi sector transfer deprotected (i.e. fixed-up).
- */
-struct address_space_operations ntfs_dir_aops = {
- writepage: NULL, /* Write dirty page to disk. */
- readpage: ntfs_mst_readpage, /* Fill page with data. */
sync_page: block_sync_page, /* Currently, just unplugs the
disk request queue. */
prepare_write: NULL, /* . */
diff -Nru a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c
--- a/fs/ntfs/attrib.c Mon Jul 8 18:41:18 2002
+++ b/fs/ntfs/attrib.c Mon Jul 8 18:41:18 2002
@@ -935,78 +935,51 @@
*/
int map_run_list(ntfs_inode *ni, VCN vcn)
{
+ ntfs_inode *base_ni;
attr_search_context *ctx;
MFT_RECORD *mrec;
- const uchar_t *name;
- u32 name_len;
- ATTR_TYPES at;
int err = 0;
ntfs_debug("Mapping run list part containing vcn 0x%Lx.",
(long long)vcn);
- /* Map, pin and lock the mft record for reading. */
- mrec = map_mft_record(READ, ni);
+ if (!NInoAttr(ni))
+ base_ni = ni;
+ else
+ base_ni = ni->_INE(base_ntfs_ino);
+
+ mrec = map_mft_record(READ, base_ni);
if (IS_ERR(mrec))
return PTR_ERR(mrec);
-
- ctx = get_attr_search_ctx(ni, mrec);
+ ctx = get_attr_search_ctx(base_ni, mrec);
if (!ctx) {
err = -ENOMEM;
- goto unm_err_out;
- }
-
- /* The attribute type is determined from the inode type. */
- if (S_ISDIR(VFS_I(ni)->i_mode)) {
- at = AT_INDEX_ALLOCATION;
- name = I30;
- name_len = 4;
- } else {
- at = AT_DATA;
- name = NULL;
- name_len = 0;
+ goto err_out;
}
-
- /* Find the attribute in the mft record. */
- if (!lookup_attr(at, name, name_len, CASE_SENSITIVE, vcn, NULL, 0,
- ctx)) {
+ if (!lookup_attr(ni->type, ni->name, ni->name_len, IGNORE_CASE, vcn,
+ NULL, 0, ctx)) {
put_attr_search_ctx(ctx);
err = -ENOENT;
- goto unm_err_out;
+ goto err_out;
}
- /* Lock the run list. */
down_write(&ni->run_list.lock);
-
/* Make sure someone else didn't do the work while we were spinning. */
if (likely(vcn_to_lcn(ni->run_list.rl, vcn) <= LCN_RL_NOT_MAPPED)) {
run_list_element *rl;
- /* Decode the run list. */
rl = decompress_mapping_pairs(ni->vol, ctx->attr,
ni->run_list.rl);
-
- /* Flag any errors or set the run list if successful. */
if (unlikely(IS_ERR(rl)))
err = PTR_ERR(rl);
else
ni->run_list.rl = rl;
}
-
- /* Unlock the run list. */
up_write(&ni->run_list.lock);
put_attr_search_ctx(ctx);
-
- /* Unlock, unpin and release the mft record. */
- unmap_mft_record(READ, ni);
-
- /* If an error occured, return it. */
- ntfs_debug("Done.");
- return err;
-
-unm_err_out:
- unmap_mft_record(READ, ni);
+err_out:
+ unmap_mft_record(READ, base_ni);
return err;
}
diff -Nru a/fs/ntfs/compress.c b/fs/ntfs/compress.c
--- a/fs/ntfs/compress.c Mon Jul 8 18:41:18 2002
+++ b/fs/ntfs/compress.c Mon Jul 8 18:41:18 2002
@@ -462,6 +462,11 @@
ntfs_debug("Entering, page->index = 0x%lx, cb_size = 0x%x, nr_pages = "
"%i.", index, cb_size, nr_pages);
+ /*
+ * Bad things happen if we get here for anything that is not an
+ * unnamed $DATA attribute.
+ */
+ BUG_ON(ni->type != AT_DATA || ni->name_len);
pages = kmalloc(nr_pages * sizeof(struct page *), GFP_NOFS);
diff -Nru a/fs/ntfs/inode.c b/fs/ntfs/inode.c
--- a/fs/ntfs/inode.c Mon Jul 8 18:41:18 2002
+++ b/fs/ntfs/inode.c Mon Jul 8 18:41:18 2002
@@ -35,7 +35,7 @@
* @type: attribute type (see layout.h)
*
* This structure exists only to provide a small structure for the
- * ntfs_iget()/ntfs_test_inode()/ntfs_init_locked_inode() mechanism.
+ * ntfs_{attr_}iget()/ntfs_test_inode()/ntfs_init_locked_inode() mechanism.
*
* NOTE: Elements are ordered by size to make the structure as compact as
* possible on all architectures.
@@ -112,14 +112,21 @@
ntfs_inode *ni = NTFS_I(vi);
vi->i_ino = na->mft_no;
+
ni->type = na->type;
+ if (na->type == AT_INDEX_ALLOCATION)
+ NInoSetMstProtected(ni);
+
ni->name = na->name;
ni->name_len = na->name_len;
+
/* If initializing a normal inode, we are done. */
if (likely(na->type == AT_UNUSED))
return 0;
+
/* It is a fake inode. */
NInoSetAttr(ni);
+
/*
* We have I30 global constant as an optimization as it is the name
* in >99.9% of named attributes! The other <0.1% incur a GFP_ATOMIC
@@ -143,6 +150,7 @@
typedef int (*test_t)(struct inode *, void *);
typedef int (*set_t)(struct inode *, void *);
static void ntfs_read_locked_inode(struct inode *vi);
+static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi);
/**
* ntfs_iget - obtain a struct inode corresponding to a specific normal inode
@@ -197,6 +205,62 @@
return vi;
}
+/**
+ * ntfs_attr_iget - obtain a struct inode corresponding to an attribute
+ * @base_vi: vfs base inode containing the attribute
+ * @type: attribute type
+ * @name: Unicode name of the attribute (NULL if unnamed)
+ * @name_len: length of @name in Unicode characters (0 if unnamed)
+ *
+ * Obtain the (fake) struct inode corresponding to the attribute specified by
+ * @type, @name, and @name_len, which is present in the base mft record
+ * specified by the vfs inode @base_vi.
+ *
+ * If the attribute inode is in the cache, it is just returned with an
+ * increased reference count. Otherwise, a new struct inode is allocated and
+ * initialized, and finally ntfs_read_locked_attr_inode() is called to read the
+ * attribute and fill in the inode structure.
+ *
+ * Return the struct inode of the attribute inode on success. Check the return
+ * value with IS_ERR() and if true, the function failed and the error code is
+ * obtained from PTR_ERR().
+ */
+struct inode *ntfs_attr_iget(struct inode *base_vi, ATTR_TYPES type,
+ uchar_t *name, u32 name_len)
+{
+ struct inode *vi;
+ ntfs_attr na;
+ int err;
+
+ na.mft_no = base_vi->i_ino;
+ na.type = type;
+ na.name = name;
+ na.name_len = name_len;
+
+ vi = iget5_locked(base_vi->i_sb, na.mft_no, (test_t)ntfs_test_inode,
+ (set_t)ntfs_init_locked_inode, &na);
+ if (!vi)
+ return ERR_PTR(-ENOMEM);
+
+ err = 0;
+
+ /* If this is a freshly allocated inode, need to read it now. */
+ if (vi->i_state & I_NEW) {
+ err = ntfs_read_locked_attr_inode(base_vi, vi);
+ unlock_new_inode(vi);
+ }
+ /*
+ * There is no point in keeping bad attribute inodes around. This also
+ * simplifies things in that we never need to check for bad attribute
+ * inodes elsewhere.
+ */
+ if (err) {
+ iput(vi);
+ vi = ERR_PTR(-EIO);
+ }
+ return vi;
+}
+
struct inode *ntfs_alloc_big_inode(struct super_block *sb)
{
ntfs_inode *ni;
@@ -685,9 +749,8 @@
goto put_unm_err_out;
}
if (ir->type != AT_FILE_NAME) {
- ntfs_error(vi->i_sb, __FUNCTION__ "(): Indexed "
- "attribute is not $FILE_NAME. Not "
- "allowed.");
+ ntfs_error(vi->i_sb, "Indexed attribute is not "
+ "$FILE_NAME. Not allowed.");
goto put_unm_err_out;
}
if (ir->collation_rule != COLLATION_FILE_NAME) {
@@ -856,7 +919,7 @@
/* Setup the operations for this inode. */
vi->i_op = &ntfs_dir_inode_ops;
vi->i_fop = &ntfs_dir_ops;
- vi->i_mapping->a_ops = &ntfs_dir_aops;
+ vi->i_mapping->a_ops = &ntfs_aops;
} else {
/* It is a file. */
reinit_attr_search_ctx(ctx);
@@ -995,7 +1058,7 @@
/* Setup the operations for this inode. */
vi->i_op = &ntfs_file_inode_ops;
vi->i_fop = &ntfs_file_ops;
- vi->i_mapping->a_ops = &ntfs_file_aops;
+ vi->i_mapping->a_ops = &ntfs_aops;
}
/*
* The number of 512-byte blocks used on disk (for stat). This is in so
@@ -1034,6 +1097,245 @@
}
/**
+ * ntfs_read_locked_attr_inode - read an attribute inode from its base inode
+ * @base_vi: base inode
+ * @vi: attribute inode to read
+ *
+ * ntfs_read_locked_attr_inode() is called from the ntfs_attr_iget() to read
+ * the attribute inode described by @vi into memory from the base mft record
+ * described by @base_ni.
+ *
+ * ntfs_read_locked_attr_inode() maps, pins and locks the base inode for
+ * reading and looks up the attribute described by @vi before setting up the
+ * necessary fields in @vi as well as initializing the ntfs inode.
+ *
+ * Q: What locks are held when the function is called?
+ * A: i_state has I_LOCK set, hence the inode is locked, also
+ * i_count is set to 1, so it is not going to go away
+ */
+static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
+{
+ ntfs_volume *vol = NTFS_SB(vi->i_sb);
+ ntfs_inode *ni, *base_ni;
+ MFT_RECORD *m;
+ attr_search_context *ctx;
+ int err = 0;
+
+ ntfs_debug("Entering for i_ino 0x%lx.", vi->i_ino);
+
+ ntfs_init_big_inode(vi);
+
+ ni = NTFS_I(vi);
+ base_ni = NTFS_I(base_vi);
+
+ /* Just mirror the values from the base inode. */
+ vi->i_blksize = base_vi->i_blksize;
+ vi->i_version = base_vi->i_version;
+ vi->i_uid = base_vi->i_uid;
+ vi->i_gid = base_vi->i_gid;
+ vi->i_nlink = base_vi->i_nlink;
+ vi->i_mtime = base_vi->i_mtime;
+ vi->i_ctime = base_vi->i_ctime;
+ vi->i_atime = base_vi->i_atime;
+ ni->seq_no = base_ni->seq_no;
+
+ /* Set inode type to zero but preserve permissions. */
+ vi->i_mode = base_vi->i_mode & ~S_IFMT;
+
+ m = map_mft_record(READ, base_ni);
+ if (IS_ERR(m)) {
+ err = PTR_ERR(m);
+ goto err_out;
+ }
+ ctx = get_attr_search_ctx(base_ni, m);
+ if (!ctx) {
+ err = -ENOMEM;
+ goto unm_err_out;
+ }
+
+ /* Find the attribute. */
+ if (!lookup_attr(ni->type, ni->name, ni->name_len, IGNORE_CASE, 0,
+ NULL, 0, ctx))
+ goto unm_err_out;
+
+ if (!ctx->attr->non_resident) {
+ if (NInoMstProtected(ni) || ctx->attr->flags) {
+ ntfs_error(vi->i_sb, "Found mst protected attribute "
+ "or attribute with non-zero flags but "
+ "the attribute is resident (mft_no "
+ "0x%lx, type 0x%x, name_len %i). "
+ "Please report you saw this message "
+ "to linux-ntfs-dev@lists.sf.net",
+ vi->i_ino, ni->type, ni->name_len);
+ goto unm_err_out;
+ }
+ /*
+ * Resident attribute. Make all sizes equal for simplicity in
+ * read code paths.
+ */
+ vi->i_size = ni->initialized_size = ni->allocated_size =
+ le32_to_cpu(ctx->attr->_ARA(value_length));
+ } else {
+ NInoSetNonResident(ni);
+ if (ctx->attr->flags & ATTR_COMPRESSION_MASK) {
+ if (NInoMstProtected(ni)) {
+ ntfs_error(vi->i_sb, "Found mst protected "
+ "attribute but the attribute "
+ "is compressed (mft_no 0x%lx, "
+ "type 0x%x, name_len %i). "
+ "Please report you saw this "
+ "message to linux-ntfs-dev@"
+ "lists.sf.net", vi->i_ino,
+ ni->type, ni->name_len);
+ goto unm_err_out;
+ }
+ NInoSetCompressed(ni);
+ if ((ni->type != AT_DATA) || (ni->type == AT_DATA &&
+ ni->name_len)) {
+ ntfs_error(vi->i_sb, "Found compressed non-"
+ "data or named data attribute "
+ "(mft_no 0x%lx, type 0x%x, "
+ "name_len %i). Please report "
+ "you saw this message to "
+ "linux-ntfs-dev@lists.sf.net",
+ vi->i_ino, ni->type,
+ ni->name_len);
+ goto unm_err_out;
+ }
+ if (vol->cluster_size > 4096) {
+ ntfs_error(vi->i_sb, "Found "
+ "compressed attribute but "
+ "compression is disabled due "
+ "to cluster size (%i) > 4kiB.",
+ vol->cluster_size);
+ goto unm_err_out;
+ }
+ if ((ctx->attr->flags & ATTR_COMPRESSION_MASK)
+ != ATTR_IS_COMPRESSED) {
+ ntfs_error(vi->i_sb, "Found unknown "
+ "compression method or "
+ "corrupt file.");
+ goto unm_err_out;
+ }
+ ni->_ICF(compression_block_clusters) = 1U <<
+ ctx->attr->_ANR(compression_unit);
+ if (ctx->attr->_ANR(compression_unit) != 4) {
+ ntfs_error(vi->i_sb, "Found "
+ "nonstandard compression unit "
+ "(%u instead of 4). Cannot "
+ "handle this. This might "
+ "indicate corruption so you "
+ "should run chkdsk.",
+ ctx->attr->_ANR(compression_unit));
+ err = -EOPNOTSUPP;
+ goto unm_err_out;
+ }
+ ni->_ICF(compression_block_size) = 1U << (
+ ctx->attr->_ANR(
+ compression_unit) +
+ vol->cluster_size_bits);
+ ni->_ICF(compression_block_size_bits) = ffs(
+ ni->_ICF(compression_block_size)) - 1;
+ }
+ if (ctx->attr->flags & ATTR_IS_ENCRYPTED) {
+ if (ctx->attr->flags & ATTR_COMPRESSION_MASK) {
+ ntfs_error(vi->i_sb, "Found encrypted "
+ "and compressed data.");
+ goto unm_err_out;
+ }
+ if (NInoMstProtected(ni)) {
+ ntfs_error(vi->i_sb, "Found mst protected "
+ "attribute but the attribute "
+ "is encrypted (mft_no 0x%lx, "
+ "type 0x%x, name_len %i). "
+ "Please report you saw this "
+ "message to linux-ntfs-dev@"
+ "lists.sf.net", vi->i_ino,
+ ni->type, ni->name_len);
+ goto unm_err_out;
+ }
+ NInoSetEncrypted(ni);
+ }
+ if (ctx->attr->flags & ATTR_IS_SPARSE) {
+ if (NInoMstProtected(ni)) {
+ ntfs_error(vi->i_sb, "Found mst protected "
+ "attribute but the attribute "
+ "is sparse (mft_no 0x%lx, "
+ "type 0x%x, name_len %i). "
+ "Please report you saw this "
+ "message to linux-ntfs-dev@"
+ "lists.sf.net", vi->i_ino,
+ ni->type, ni->name_len);
+ goto unm_err_out;
+ }
+ NInoSetSparse(ni);
+ }
+ if (ctx->attr->_ANR(lowest_vcn)) {
+ ntfs_error(vi->i_sb, "First extent of attribute has "
+ "non-zero lowest_vcn. Inode is "
+ "corrupt. You should run chkdsk.");
+ goto unm_err_out;
+ }
+ /* Setup all the sizes. */
+ vi->i_size = sle64_to_cpu(ctx->attr->_ANR(data_size));
+ ni->initialized_size = sle64_to_cpu(
+ ctx->attr->_ANR(initialized_size));
+ ni->allocated_size = sle64_to_cpu(
+ ctx->attr->_ANR(allocated_size));
+ if (NInoCompressed(ni)) {
+ ni->_ICF(compressed_size) = sle64_to_cpu(
+ ctx->attr->_ANR(compressed_size));
+ if (vi->i_size != ni->initialized_size)
+ ntfs_warning(vi->i_sb, "Compressed attribute "
+ "with data_size unequal to "
+ "initialized size found. This "
+ "will probably cause problems "
+ "when trying to access the "
+ "file. Please notify "
+ "linux-ntfs-dev@ lists.sf.net "
+ "that you saw this message.");
+ }
+ }
+
+ /* Setup the operations for this attribute inode. */
+ vi->i_op = NULL;
+ vi->i_fop = NULL;
+ vi->i_mapping->a_ops = &ntfs_aops;
+
+ if (!NInoCompressed(ni))
+ vi->i_blocks = ni->allocated_size >> 9;
+ else
+ vi->i_blocks = ni->_ICF(compressed_size) >> 9;
+
+ /*
+ * Make sure the base inode doesn't go away and attach it to the
+ * attribute inode.
+ */
+ igrab(base_vi);
+ ni->_INE(base_ntfs_ino) = base_ni;
+ ni->nr_extents = -1;
+
+ put_attr_search_ctx(ctx);
+ unmap_mft_record(READ, ni);
+
+ ntfs_debug("Done.");
+ return 0;
+
+unm_err_out:
+ if (!err)
+ err = -EIO;
+ if (ctx)
+ put_attr_search_ctx(ctx);
+ unmap_mft_record(READ, base_ni);
+err_out:
+ ntfs_error(vi->i_sb, "Failed with error code %i while reading "
+ "attribute inode (mft_no 0x%lx, type 0x%x, name_len "
+ "%i.", -err, vi->i_ino, ni->type, ni->name_len);
+ make_bad_inode(vi);
+ return err;
+}
+
+/**
* ntfs_read_inode_mount - special read_inode for mount time use only
* @vi: inode to read
*
@@ -1590,6 +1892,13 @@
if (ni->_IDM(bmp_rl).rl)
ntfs_free(ni->_IDM(bmp_rl).rl);
up_write(&ni->_IDM(bmp_rl).lock);
+ } else if (NInoAttr(ni)) {
+ /* Release the base inode if we are holding it. */
+ if (ni->nr_extents == -1) {
+ iput(VFS_I(ni->_INE(base_ntfs_ino)));
+ ni->nr_extents = 0;
+ ni->_INE(base_ntfs_ino) = NULL;
+ }
}
return;
}
diff -Nru a/fs/ntfs/mft.c b/fs/ntfs/mft.c
--- a/fs/ntfs/mft.c Mon Jul 8 18:41:18 2002
+++ b/fs/ntfs/mft.c Mon Jul 8 18:41:18 2002
@@ -95,8 +95,10 @@
return 0;
}
-/* From fs/ntfs/aops.c */
-extern int ntfs_mst_readpage(struct file *, struct page *);
+/**
+ * From fs/ntfs/aops.c
+ */
+extern int ntfs_readpage(struct file *, struct page *);
/**
* ntfs_mft_aops - address space operations for access to $MFT
@@ -106,7 +108,7 @@
*/
struct address_space_operations ntfs_mft_aops = {
writepage: NULL, /* Write dirty page to disk. */
- readpage: ntfs_mst_readpage, /* Fill page with data. */
+ readpage: ntfs_readpage, /* Fill page with data. */
sync_page: block_sync_page, /* Currently, just unplugs the
disk request queue. */
prepare_write: NULL, /* . */
@@ -214,11 +216,11 @@
* necessary, increments the use count on the page so that it cannot disappear
* under us and returns a reference to the page cache page).
*
- * If read_cache_page() invokes ntfs_mst_readpage() to load the page from disk,
- * it sets PG_locked and clears PG_uptodate on the page. Once I/O has
- * completed and the post-read mst fixups on each mft record in the page have
- * been performed, the page gets PG_uptodate set and PG_locked cleared (this is
- * done in our asynchronous I/O completion handler end_buffer_read_mft_async()).
+ * If read_cache_page() invokes ntfs_readpage() to load the page from disk, it
+ * sets PG_locked and clears PG_uptodate on the page. Once I/O has completed
+ * and the post-read mst fixups on each mft record in the page have been
+ * performed, the page gets PG_uptodate set and PG_locked cleared (this is done
+ * in our asynchronous I/O completion handler end_buffer_read_mft_async()).
* ntfs_map_page() waits for PG_locked to become clear and checks if
* PG_uptodate is set and returns an error code if not. This provides
* sufficient protection against races when reading/using the page.
diff -Nru a/fs/ntfs/ntfs.h b/fs/ntfs/ntfs.h
--- a/fs/ntfs/ntfs.h Mon Jul 8 18:41:18 2002
+++ b/fs/ntfs/ntfs.h Mon Jul 8 18:41:18 2002
@@ -62,18 +62,21 @@
extern kmem_cache_t *ntfs_attr_ctx_cache;
/* The various operations structs defined throughout the driver files. */
-extern struct super_operations ntfs_mount_sops;
extern struct super_operations ntfs_sops;
-extern struct file_operations ntfs_file_ops;
+extern struct super_operations ntfs_mount_sops;
+
+extern struct address_space_operations ntfs_aops;
+extern struct address_space_operations ntfs_mft_aops;
+extern struct address_space_operations ntfs_mftbmp_aops;
+
+extern struct file_operations ntfs_file_ops;
extern struct inode_operations ntfs_file_inode_ops;
-extern struct address_space_operations ntfs_file_aops;
-extern struct file_operations ntfs_dir_ops;
+
+extern struct file_operations ntfs_dir_ops;
extern struct inode_operations ntfs_dir_inode_ops;
-extern struct address_space_operations ntfs_dir_aops;
-extern struct file_operations ntfs_empty_file_ops;
+
+extern struct file_operations ntfs_empty_file_ops;
extern struct inode_operations ntfs_empty_inode_ops;
-extern struct address_space_operations ntfs_mft_aops;
-extern struct address_space_operations ntfs_mftbmp_aops;
/* Generic macro to convert pointers to values for comparison purposes. */
#ifndef p2n
diff -Nru a/fs/ntfs/super.c b/fs/ntfs/super.c
--- a/fs/ntfs/super.c Mon Jul 8 18:41:18 2002
+++ b/fs/ntfs/super.c Mon Jul 8 18:41:18 2002
@@ -135,6 +135,7 @@
}
if (!opt || !*opt)
goto no_mount_options;
+ ntfs_debug("Entering with mount options string: %s", opt);
while ((p = strsep(&opt, ","))) {
if ((v = strchr(p, '=')))
*v++ = '\0';
@@ -217,7 +218,7 @@
}
}
if (nls_map) {
- if (vol->nls_map) {
+ if (vol->nls_map && vol->nls_map != nls_map) {
ntfs_error(vol->sb, "Cannot change NLS character set "
"on remount.");
return FALSE;
@@ -249,8 +250,8 @@
mft_zone_multiplier = 1;
}
vol->mft_zone_multiplier = mft_zone_multiplier;
- } if (!vol->mft_zone_multiplier)
- /* Not specified and it is the first mount, so set default. */
+ }
+ if (!vol->mft_zone_multiplier)
vol->mft_zone_multiplier = 1;
if (on_errors != -1)
vol->on_errors = on_errors;
@@ -304,7 +305,7 @@
{
ntfs_volume *vol = NTFS_SB(sb);
- ntfs_debug("Entering.");
+ ntfs_debug("Entering with remount options string: %s", opt);
// FIXME/TODO: If left like this we will have problems with rw->ro and
// ro->rw, as well as with sync->async and vice versa remounts.
@@ -1799,7 +1800,7 @@
#ifdef MODULE
" MODULE"
#endif
- "]. Copyright (c) 2001,2002 Anton Altaparmakov.\n");
+ "].\n");
ntfs_debug("Debug messages are enabled.");
@@ -1899,7 +1900,7 @@
}
MODULE_AUTHOR("Anton Altaparmakov <aia21@cantab.net>");
-MODULE_DESCRIPTION("NTFS 1.2/3.x driver");
+MODULE_DESCRIPTION("NTFS 1.2/3.x driver - Copyright (c) 2001-2002 Anton Altaparmakov");
MODULE_LICENSE("GPL");
#ifdef DEBUG
MODULE_PARM(debug_msgs, "i");
diff -Nru a/fs/ntfs/volume.h b/fs/ntfs/volume.h
--- a/fs/ntfs/volume.h Mon Jul 8 18:41:18 2002
+++ b/fs/ntfs/volume.h Mon Jul 8 18:41:18 2002
@@ -27,31 +27,6 @@
#include "types.h"
/*
- * Defined bits for the flags field in the ntfs_volume structure.
- */
-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. */
-} ntfs_volume_flags;
-
-#define NVolShowSystemFiles(n_vol) test_bit(NV_ShowSystemFiles, \
- &(n_vol)->flags)
-#define NVolSetShowSystemFiles(n_vol) set_bit(NV_ShowSystemFiles, \
- &(n_vol)->flags)
-#define NVolClearShowSystemFiles(n_vol) clear_bit(NV_ShowSystemFiles, \
- &(n_vol)->flags)
-
-#define NVolCaseSensitive(n_vol) test_bit(NV_CaseSensitive, \
- &(n_vol)->flags)
-#define NVolSetCaseSensitive(n_vol) set_bit(NV_CaseSensitive, \
- &(n_vol)->flags)
-#define NVolClearCaseSensitive(n_vol) clear_bit(NV_CaseSensitive, \
- &(n_vol)->flags)
-
-/*
* The NTFS in memory super block structure.
*/
typedef struct {
@@ -123,6 +98,39 @@
only, otherwise NULL). */
struct nls_table *nls_map;
} ntfs_volume;
+
+/*
+ * Defined bits for the flags field in the ntfs_volume structure.
+ */
+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. */
+} ntfs_volume_flags;
+
+/*
+ * Macro tricks to expand the NVolFoo(), NVolSetFoo(), and NVolClearFoo()
+ * functions.
+ */
+#define NVOL_FNS(flag) \
+static inline int NVol##flag(ntfs_volume *vol) \
+{ \
+ return test_bit(NV_##flag, &(vol)->flags); \
+} \
+static inline void NVolSet##flag(ntfs_volume *vol) \
+{ \
+ set_bit(NV_##flag, &(vol)->flags); \
+} \
+static inline void NVolClear##flag(ntfs_volume *vol) \
+{ \
+ clear_bit(NV_##flag, &(vol)->flags); \
+}
+
+/* Emit the ntfs volume bitops functions. */
+NVOL_FNS(ShowSystemFiles)
+NVOL_FNS(CaseSensitive)
#endif /* _LINUX_NTFS_VOLUME_H */
===================================================================
This BitKeeper patch contains the following changesets:
aia21@cantab.net|ChangeSet|20020708174011|11655
aia21@cantab.net|ChangeSet|20020706233736|11639
aia21@cantab.net|ChangeSet|20020705235849|62477
aia21@cantab.net|ChangeSet|20020705200106|53559
aia21@cantab.net|ChangeSet|20020705120813|47863
aia21@cantab.net|ChangeSet|20020704223115|00790
## Wrapped with gzip_uu ##
begin 664 bkpatch634
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
AJLDW!@M4D[]'B-CV,)Z];XX.1K<'0VOS?]87H6TU<0``
`
end
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/