2002-08-04 23:10:29

by Anton Altaparmakov

[permalink] [raw]
Subject: [BK-2.5-PATCH] NTFS: 2.0.23 - Major bug fixes (races, deadlocks, non-i386 architectures)

Linus, please do a

bk pull http://linux-ntfs.bkbits.net/ntfs-tng-2.5

Thanks!

This is quite a massive bug fix update. I have a dual athlon with 3G RAM
to play with at the moment so have been able to iron out a lot of races,
recursive locking, and subsequent deadlocks.

This should also fix the reported ntfs over loopback i/o error problems.
At least I can no longer reproduce the errors after I added the optimization
barrier() in fs/ntfs/compress.c. I suspect gcc screws up without it...

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 | 8 +
fs/ntfs/ChangeLog | 14 ++
fs/ntfs/Makefile | 2
fs/ntfs/aops.c | 10 -
fs/ntfs/attrib.c | 8 -
fs/ntfs/compress.c | 23 +++-
fs/ntfs/dir.c | 202 +++++++++++++++++++------------------
fs/ntfs/inode.c | 47 +++++---
fs/ntfs/inode.h | 3
fs/ntfs/malloc.h | 17 ---
fs/ntfs/mft.c | 197 +++++++++++++-----------------------
fs/ntfs/mft.h | 6 -
fs/ntfs/namei.c | 38 +++---
fs/ntfs/super.c | 6 -
14 files changed, 295 insertions(+), 286 deletions(-)

through these ChangeSets:

<[email protected]> (02/08/05 1.458)
NTFS: 2.0.23 - Major bug fixes (races, deadlocks, non-i386 architectures).
- Massive internal locking changes to mft record locking. Fixes lock
recursion and replaces the mrec_lock read/write semaphore with a
mutex. Also removes the now superfluous mft_count. This fixes several
race conditions and deadlocks, especially in the future write code.
- Fix ntfs over loopback for compressed files by adding an
optimization barrier. (gcc was screwing up otherwise ?)
- Miscellaneous cleanups all over the code and a fix or two in error
handling code paths.
Thanks go to Christoph Hellwig for pointing out the following two:
- Remove now unused function fs/ntfs/malloc.h::vmalloc_nofs().
- Fix ntfs_free() for ia64 and parisc by checking for VMALLOC_END, too.


diff -Nru a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt
--- a/Documentation/filesystems/ntfs.txt Mon Aug 5 00:08:29 2002
+++ b/Documentation/filesystems/ntfs.txt Mon Aug 5 00:08:29 2002
@@ -247,6 +247,14 @@

Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.

+2.0.23:
+ - Massive internal locking changes to mft record locking. Fixes
+ various race conditions and deadlocks.
+ - Fix ntfs over loopback for compressed files by adding an
+ optimization barrier. (gcc was screwing up otherwise ?)
+ Thanks go to Christoph Hellwig for pointing these two out:
+ - Remove now unused function fs/ntfs/malloc.h::vmalloc_nofs().
+ - Fix ntfs_free() for ia64 and parisc.
2.0.22:
- Small internal cleanups.
2.0.21:
diff -Nru a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog
--- a/fs/ntfs/ChangeLog Mon Aug 5 00:08:29 2002
+++ b/fs/ntfs/ChangeLog Mon Aug 5 00:08:29 2002
@@ -2,6 +2,20 @@
- Find and fix bugs.
- Enable NFS exporting of NTFS.

+2.0.23 - Major bug fixes (races, deadlocks, non-i386 architectures).
+
+ - Massive internal locking changes to mft record locking. Fixes lock
+ recursion and replaces the mrec_lock read/write semaphore with a
+ mutex. Also removes the now superfluous mft_count. This fixes several
+ race conditions and deadlocks, especially in the future write code.
+ - Fix ntfs over loopback for compressed files by adding an
+ optimization barrier. (gcc was screwing up otherwise ?)
+ - Miscellaneous cleanups all over the code and a fix or two in error
+ handling code paths.
+ Thanks go to Christoph Hellwig for pointing out the following two:
+ - Remove now unused function fs/ntfs/malloc.h::vmalloc_nofs().
+ - Fix ntfs_free() for ia64 and parisc by checking for VMALLOC_END, too.
+
2.0.22 - Cleanups, mainly to ntfs_readdir(), and use C99 initializers.

- Change fs/ntfs/dir.c::ntfs_reddir() to only read/write ->f_pos once
diff -Nru a/fs/ntfs/Makefile b/fs/ntfs/Makefile
--- a/fs/ntfs/Makefile Mon Aug 5 00:08:29 2002
+++ b/fs/ntfs/Makefile Mon Aug 5 00:08:29 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.22\"
+EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.23\"

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 Aug 5 00:08:29 2002
+++ b/fs/ntfs/aops.c Mon Aug 5 00:08:29 2002
@@ -106,8 +106,6 @@
if (!NInoMstProtected(ni)) {
if (likely(page_uptodate && !PageError(page)))
SetPageUptodate(page);
- unlock_page(page);
- return;
} else {
char *addr;
unsigned int i, recs, nr_err;
@@ -332,6 +330,8 @@
* for it to be read in before we can do the copy.
*
* Return 0 on success and -errno on error.
+ *
+ * WARNING: Do not make this function static! It is used by mft.c!
*/
int ntfs_readpage(struct file *file, struct page *page)
{
@@ -372,8 +372,8 @@
else
base_ni = ni->_INE(base_ntfs_ino);

- /* Map, pin and lock the mft record for reading. */
- mrec = map_mft_record(READ, base_ni);
+ /* Map, pin and lock the mft record. */
+ mrec = map_mft_record(base_ni);
if (unlikely(IS_ERR(mrec))) {
err = PTR_ERR(mrec);
goto err_out;
@@ -416,7 +416,7 @@
put_unm_err_out:
put_attr_search_ctx(ctx);
unm_err_out:
- unmap_mft_record(READ, base_ni);
+ unmap_mft_record(base_ni);
err_out:
unlock_page(page);
return err;
diff -Nru a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c
--- a/fs/ntfs/attrib.c Mon Aug 5 00:08:29 2002
+++ b/fs/ntfs/attrib.c Mon Aug 5 00:08:29 2002
@@ -948,7 +948,7 @@
else
base_ni = ni->_INE(base_ntfs_ino);

- mrec = map_mft_record(READ, base_ni);
+ mrec = map_mft_record(base_ni);
if (IS_ERR(mrec))
return PTR_ERR(mrec);
ctx = get_attr_search_ctx(base_ni, mrec);
@@ -979,7 +979,7 @@

put_attr_search_ctx(ctx);
err_out:
- unmap_mft_record(READ, base_ni);
+ unmap_mft_record(base_ni);
return err;
}

@@ -1671,7 +1671,7 @@
return;
} /* Attribute list. */
if (ctx->ntfs_ino != ctx->base_ntfs_ino)
- unmap_mft_record(READ, ctx->ntfs_ino);
+ unmap_mft_record(ctx->ntfs_ino);
init_attr_search_ctx(ctx, ctx->base_ntfs_ino, ctx->base_mrec);
return;
}
@@ -1704,7 +1704,7 @@
void put_attr_search_ctx(attr_search_context *ctx)
{
if (ctx->base_ntfs_ino && ctx->ntfs_ino != ctx->base_ntfs_ino)
- unmap_mft_record(READ, ctx->ntfs_ino);
+ unmap_mft_record(ctx->ntfs_ino);
kmem_cache_free(ntfs_attr_ctx_cache, ctx);
return;
}
diff -Nru a/fs/ntfs/compress.c b/fs/ntfs/compress.c
--- a/fs/ntfs/compress.c Mon Aug 5 00:08:29 2002
+++ b/fs/ntfs/compress.c Mon Aug 5 00:08:29 2002
@@ -608,8 +608,27 @@
if (buffer_uptodate(tbh))
continue;
wait_on_buffer(tbh);
- if (unlikely(!buffer_uptodate(tbh)))
- goto read_err;
+ /*
+ * We need an optimization barrier here, otherwise we start
+ * hitting the below fixup code when accessing a loopback
+ * mounted ntfs partition. This indicates either there is a
+ * race condition in the loop driver or, more likely, gcc
+ * overoptimises the code without the barrier and it doesn't
+ * do the Right Thing(TM).
+ */
+ barrier();
+ if (unlikely(!buffer_uptodate(tbh))) {
+ ntfs_warning(vol->sb, "Buffer is unlocked but not "
+ "uptodate! Unplugging the disk queue "
+ "and rescheduling.");
+ get_bh(tbh);
+ blk_run_queues();
+ schedule();
+ put_bh(tbh);
+ if (unlikely(!buffer_uptodate(tbh)))
+ goto read_err;
+ ntfs_warning(vol->sb, "Buffer is now uptodate. Good.");
+ }
}

/*
diff -Nru a/fs/ntfs/dir.c b/fs/ntfs/dir.c
--- a/fs/ntfs/dir.c Mon Aug 5 00:08:29 2002
+++ b/fs/ntfs/dir.c Mon Aug 5 00:08:29 2002
@@ -76,7 +76,7 @@
u8 *index_end;
u64 mref;
attr_search_context *ctx;
- int err = 0, rc;
+ int err, rc;
VCN vcn, old_vcn;
struct address_space *ia_mapping;
struct page *page;
@@ -84,23 +84,24 @@
ntfs_name *name = NULL;

/* Get hold of the mft record for the directory. */
- m = map_mft_record(READ, dir_ni);
- if (IS_ERR(m))
- goto map_err_out;
-
+ m = map_mft_record(dir_ni);
+ if (unlikely(IS_ERR(m))) {
+ ntfs_error(sb, "map_mft_record() failed with error code %ld.",
+ -PTR_ERR(m));
+ return ERR_MREF(PTR_ERR(m));
+ }
ctx = get_attr_search_ctx(dir_ni, m);
- if (!ctx) {
+ if (unlikely(!ctx)) {
err = -ENOMEM;
- goto unm_err_out;
+ goto err_out;
}
-
/* Find the index root attribute in the mft record. */
if (!lookup_attr(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL, 0,
ctx)) {
ntfs_error(sb, "Index root attribute missing in directory "
"inode 0x%lx.", dir_ni->mft_no);
err = -EIO;
- goto put_unm_err_out;
+ goto err_out;
}
/* Get to the index root value (it's been verified in read_inode). */
ir = (INDEX_ROOT*)((u8*)ctx->attr +
@@ -154,7 +155,7 @@
GFP_NOFS);
if (!name) {
err = -ENOMEM;
- goto put_unm_err_out;
+ goto err_out;
}
}
name->mref = le64_to_cpu(
@@ -169,7 +170,7 @@
}
mref = le64_to_cpu(ie->_IIF(indexed_file));
put_attr_search_ctx(ctx);
- unmap_mft_record(READ, dir_ni);
+ unmap_mft_record(dir_ni);
return mref;
}
/*
@@ -208,7 +209,7 @@
name = kmalloc(name_size, GFP_NOFS);
if (!name) {
err = -ENOMEM;
- goto put_unm_err_out;
+ goto err_out;
}
name->mref = le64_to_cpu(ie->_IIF(indexed_file));
name->type = type;
@@ -267,12 +268,12 @@
if (!(ie->_IEH(flags) & INDEX_ENTRY_NODE)) {
if (name) {
put_attr_search_ctx(ctx);
- unmap_mft_record(READ, dir_ni);
+ unmap_mft_record(dir_ni);
return name->mref;
}
ntfs_debug("Entry not found.");
err = -ENOENT;
- goto put_unm_err_out;
+ goto err_out;
} /* Child node present, descend into it. */
/* Consistency check: Verify that an index allocation exists. */
if (!NInoIndexAllocPresent(dir_ni)) {
@@ -280,11 +281,19 @@
"requires one. Directory inode 0x%lx is "
"corrupt or driver bug.", dir_ni->mft_no);
err = -EIO;
- goto put_unm_err_out;
+ goto err_out;
}
/* Get the starting vcn of the index_block holding the child node. */
vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->_IEH(length)) - 8);
ia_mapping = VFS_I(dir_ni)->i_mapping;
+ /*
+ * We are done with the index root and the mft record. Release them,
+ * otherwise we deadlock with ntfs_map_page().
+ */
+ put_attr_search_ctx(ctx);
+ unmap_mft_record(dir_ni);
+ m = NULL;
+ ctx = NULL;
descend_into_child_node:
/*
* Convert vcn to index into the index allocation attribute in units
@@ -296,7 +305,8 @@
if (IS_ERR(page)) {
ntfs_error(sb, "Failed to map directory index page, error %ld.",
-PTR_ERR(page));
- goto put_unm_err_out;
+ err = PTR_ERR(page);
+ goto err_out;
}
kaddr = (u8*)page_address(page);
fast_descend_into_child_node:
@@ -308,7 +318,7 @@
ntfs_error(sb, "Out of bounds check failed. Corrupt directory "
"inode 0x%lx or driver bug.", dir_ni->mft_no);
err = -EIO;
- goto unm_unm_err_out;
+ goto unm_err_out;
}
if (sle64_to_cpu(ia->index_block_vcn) != vcn) {
ntfs_error(sb, "Actual VCN (0x%Lx) of index buffer is "
@@ -318,7 +328,7 @@
(long long)sle64_to_cpu(ia->index_block_vcn),
(long long)vcn, dir_ni->mft_no);
err = -EIO;
- goto unm_unm_err_out;
+ goto unm_err_out;
}
if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=
dir_ni->_IDM(index_block_size)) {
@@ -330,7 +340,7 @@
le32_to_cpu(ia->index.allocated_size) + 0x18,
dir_ni->_IDM(index_block_size));
err = -EIO;
- goto unm_unm_err_out;
+ goto unm_err_out;
}
index_end = (u8*)ia + dir_ni->_IDM(index_block_size);
if (index_end > kaddr + PAGE_CACHE_SIZE) {
@@ -339,7 +349,7 @@
"Cannot access! This is probably a bug in the "
"driver.", (long long)vcn, dir_ni->mft_no);
err = -EIO;
- goto unm_unm_err_out;
+ goto unm_err_out;
}
index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
if (index_end > (u8*)ia + dir_ni->_IDM(index_block_size)) {
@@ -347,7 +357,7 @@
"inode 0x%lx exceeds maximum size.",
(long long)vcn, dir_ni->mft_no);
err = -EIO;
- goto unm_unm_err_out;
+ goto unm_err_out;
}
/* The first index entry. */
ie = (INDEX_ENTRY*)((u8*)&ia->index +
@@ -367,7 +377,7 @@
"directory inode 0x%lx.",
dir_ni->mft_no);
err = -EIO;
- goto unm_unm_err_out;
+ goto unm_err_out;
}
/*
* The last entry cannot contain a name. It can however contain
@@ -403,7 +413,7 @@
GFP_NOFS);
if (!name) {
err = -ENOMEM;
- goto unm_unm_err_out;
+ goto unm_err_out;
}
}
name->mref = le64_to_cpu(
@@ -418,8 +428,6 @@
}
mref = le64_to_cpu(ie->_IIF(indexed_file));
ntfs_unmap_page(page);
- put_attr_search_ctx(ctx);
- unmap_mft_record(READ, dir_ni);
return mref;
}
/*
@@ -459,7 +467,7 @@
name = kmalloc(name_size, GFP_NOFS);
if (!name) {
err = -ENOMEM;
- goto put_unm_err_out;
+ goto unm_err_out;
}
name->mref = le64_to_cpu(ie->_IIF(indexed_file));
name->type = type;
@@ -519,7 +527,7 @@
"a leaf node in directory inode 0x%lx.",
dir_ni->mft_no);
err = -EIO;
- goto unm_unm_err_out;
+ goto unm_err_out;
}
/* Child node present, descend into it. */
old_vcn = vcn;
@@ -539,7 +547,7 @@
ntfs_error(sb, "Negative child node vcn in directory inode "
"0x%lx.", dir_ni->mft_no);
err = -EIO;
- goto unm_unm_err_out;
+ goto unm_err_out;
}
/*
* No child node present, return -ENOENT, unless we have got a matching
@@ -548,31 +556,26 @@
*/
if (name) {
ntfs_unmap_page(page);
- put_attr_search_ctx(ctx);
- unmap_mft_record(READ, dir_ni);
return name->mref;
}
ntfs_debug("Entry not found.");
err = -ENOENT;
-unm_unm_err_out:
- ntfs_unmap_page(page);
-put_unm_err_out:
- put_attr_search_ctx(ctx);
unm_err_out:
- unmap_mft_record(READ, dir_ni);
+ ntfs_unmap_page(page);
+err_out:
+ if (ctx)
+ put_attr_search_ctx(ctx);
+ if (m)
+ unmap_mft_record(dir_ni);
if (name) {
kfree(name);
*res = NULL;
}
return ERR_MREF(err);
-map_err_out:
- ntfs_error(sb, "map_mft_record(READ) failed with error code %ld.",
- -PTR_ERR(m));
- return ERR_MREF(PTR_ERR(m));
dir_err_out:
ntfs_error(sb, "Corrupt directory. Aborting lookup.");
err = -EIO;
- goto put_unm_err_out;
+ goto err_out;
}

#if 0
@@ -614,7 +617,7 @@
u8 *index_end;
u64 mref;
attr_search_context *ctx;
- int err = 0, rc;
+ int err, rc;
IGNORE_CASE_BOOL ic;
VCN vcn, old_vcn;
struct address_space *ia_mapping;
@@ -622,23 +625,24 @@
u8 *kaddr;

/* Get hold of the mft record for the directory. */
- m = map_mft_record(READ, dir_ni);
- if (IS_ERR(m))
- goto map_err_out;
-
+ m = map_mft_record(dir_ni);
+ if (IS_ERR(m)) {
+ ntfs_error(sb, "map_mft_record() failed with error code %ld.",
+ -PTR_ERR(m));
+ return ERR_MREF(PTR_ERR(m));
+ }
ctx = get_attr_search_ctx(dir_ni, m);
if (!ctx) {
err = -ENOMEM;
- goto unm_err_out;
+ goto err_out;
}
-
/* Find the index root attribute in the mft record. */
if (!lookup_attr(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL, 0,
ctx)) {
ntfs_error(sb, "Index root attribute missing in directory "
"inode 0x%lx.", dir_ni->mft_no);
err = -EIO;
- goto put_unm_err_out;
+ goto err_out;
}
/* Get to the index root value (it's been verified in read_inode). */
ir = (INDEX_ROOT*)((u8*)ctx->attr +
@@ -689,7 +693,7 @@
found_it:
mref = le64_to_cpu(ie->_IIF(indexed_file));
put_attr_search_ctx(ctx);
- unmap_mft_record(READ, dir_ni);
+ unmap_mft_record(dir_ni);
return mref;
}
/*
@@ -737,7 +741,7 @@
if (!(ie->_IEH(flags) & INDEX_ENTRY_NODE)) {
/* No child node, return -ENOENT. */
err = -ENOENT;
- goto put_unm_err_out;
+ goto err_out;
} /* Child node present, descend into it. */
/* Consistency check: Verify that an index allocation exists. */
if (!NInoIndexAllocPresent(dir_ni)) {
@@ -745,11 +749,19 @@
"requires one. Directory inode 0x%lx is "
"corrupt or driver bug.", dir_ni->mft_no);
err = -EIO;
- goto put_unm_err_out;
+ goto err_out;
}
/* Get the starting vcn of the index_block holding the child node. */
vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->_IEH(length)) - 8);
ia_mapping = VFS_I(dir_ni)->i_mapping;
+ /*
+ * We are done with the index root and the mft record. Release them,
+ * otherwise we deadlock with ntfs_map_page().
+ */
+ put_attr_search_ctx(ctx);
+ unmap_mft_record(dir_ni);
+ m = NULL;
+ ctx = NULL;
descend_into_child_node:
/*
* Convert vcn to index into the index allocation attribute in units
@@ -761,7 +773,8 @@
if (IS_ERR(page)) {
ntfs_error(sb, "Failed to map directory index page, error %ld.",
-PTR_ERR(page));
- goto put_unm_err_out;
+ err = PTR_ERR(page);
+ goto err_out;
}
kaddr = (u8*)page_address(page);
fast_descend_into_child_node:
@@ -773,7 +786,7 @@
ntfs_error(sb, "Out of bounds check failed. Corrupt directory "
"inode 0x%lx or driver bug.", dir_ni->mft_no);
err = -EIO;
- goto unm_unm_err_out;
+ goto unm_err_out;
}
if (sle64_to_cpu(ia->index_block_vcn) != vcn) {
ntfs_error(sb, "Actual VCN (0x%Lx) of index buffer is "
@@ -783,7 +796,7 @@
(long long)sle64_to_cpu(ia->index_block_vcn),
(long long)vcn, dir_ni->mft_no);
err = -EIO;
- goto unm_unm_err_out;
+ goto unm_err_out;
}
if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=
dir_ni->_IDM(index_block_size)) {
@@ -795,7 +808,7 @@
le32_to_cpu(ia->index.allocated_size) + 0x18,
dir_ni->_IDM(index_block_size));
err = -EIO;
- goto unm_unm_err_out;
+ goto unm_err_out;
}
index_end = (u8*)ia + dir_ni->_IDM(index_block_size);
if (index_end > kaddr + PAGE_CACHE_SIZE) {
@@ -804,7 +817,7 @@
"Cannot access! This is probably a bug in the "
"driver.", (long long)vcn, dir_ni->mft_no);
err = -EIO;
- goto unm_unm_err_out;
+ goto unm_err_out;
}
index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
if (index_end > (u8*)ia + dir_ni->_IDM(index_block_size)) {
@@ -812,7 +825,7 @@
"inode 0x%lx exceeds maximum size.",
(long long)vcn, dir_ni->mft_no);
err = -EIO;
- goto unm_unm_err_out;
+ goto unm_err_out;
}
/* The first index entry. */
ie = (INDEX_ENTRY*)((u8*)&ia->index +
@@ -832,7 +845,7 @@
"directory inode 0x%lx.",
dir_ni->mft_no);
err = -EIO;
- goto unm_unm_err_out;
+ goto unm_err_out;
}
/*
* The last entry cannot contain a name. It can however contain
@@ -865,8 +878,6 @@
found_it2:
mref = le64_to_cpu(ie->_IIF(indexed_file));
ntfs_unmap_page(page);
- put_attr_search_ctx(ctx);
- unmap_mft_record(READ, dir_ni);
return mref;
}
/*
@@ -917,7 +928,7 @@
"a leaf node in directory inode 0x%lx.",
dir_ni->mft_no);
err = -EIO;
- goto unm_unm_err_out;
+ goto unm_err_out;
}
/* Child node present, descend into it. */
old_vcn = vcn;
@@ -937,26 +948,23 @@
ntfs_error(sb, "Negative child node vcn in directory inode "
"0x%lx.", dir_ni->mft_no);
err = -EIO;
- goto unm_unm_err_out;
+ goto unm_err_out;
}
/* No child node, return -ENOENT. */
ntfs_debug("Entry not found.");
err = -ENOENT;
-unm_unm_err_out:
- ntfs_unmap_page(page);
-put_unm_err_out:
- put_attr_search_ctx(ctx);
unm_err_out:
- unmap_mft_record(READ, dir_ni);
+ ntfs_unmap_page(page);
+err_out:
+ if (ctx)
+ put_attr_search_ctx(ctx);
+ if (m)
+ unmap_mft_record(dir_ni);
return ERR_MREF(err);
-map_err_out:
- ntfs_error(sb, "map_mft_record(READ) failed with error code %ld.",
- -PTR_ERR(m));
- return ERR_MREF(PTR_ERR(m));
dir_err_out:
ntfs_error(sb, "Corrupt directory. Aborting lookup.");
err = -EIO;
- goto put_unm_err_out;
+ goto err_out;
}

#endif
@@ -1095,22 +1103,8 @@
goto done;
fpos++;
}
-
- /* Get hold of the mft record for the directory. */
- m = map_mft_record(READ, ndir);
- if (unlikely(IS_ERR(m))) {
- err = PTR_ERR(m);
- m = NULL;
- ctx = NULL;
- goto err_out;
- }
-
- ctx = get_attr_search_ctx(ndir, m);
- if (unlikely(!ctx)) {
- err = -ENOMEM;
- goto err_out;
- }
-
+ m = NULL;
+ ctx = NULL;
/*
* Allocate a buffer to store the current name being processed
* converted to format determined by current NLS.
@@ -1124,6 +1118,18 @@
/* Are we jumping straight into the index allocation attribute? */
if (fpos >= vol->mft_record_size)
goto skip_index_root;
+ /* Get hold of the mft record for the directory. */
+ m = map_mft_record(ndir);
+ if (unlikely(IS_ERR(m))) {
+ err = PTR_ERR(m);
+ m = NULL;
+ goto err_out;
+ }
+ ctx = get_attr_search_ctx(ndir, m);
+ if (unlikely(!ctx)) {
+ err = -ENOMEM;
+ goto err_out;
+ }
/* Get the offset into the index root attribute. */
ir_pos = (s64)fpos;
/* Find the index root attribute in the mft record. */
@@ -1162,9 +1168,21 @@
/* Submit the name to the filldir callback. */
rc = ntfs_filldir(vol, &fpos, ndir, INDEX_TYPE_ROOT, ir, ie,
name, dirent, filldir);
- if (rc)
+ if (rc) {
+ put_attr_search_ctx(ctx);
+ unmap_mft_record(ndir);
goto abort;
+ }
}
+ /*
+ * We are done with the index root and the mft record for that matter.
+ * We need to release it, otherwise we deadlock on ntfs_attr_iget()
+ * and/or ntfs_read_page().
+ */
+ put_attr_search_ctx(ctx);
+ unmap_mft_record(ndir);
+ m = NULL;
+ ctx = NULL;
/* If there is no index allocation attribute we are finished. */
if (!NInoIndexAllocPresent(ndir))
goto EOD;
@@ -1197,7 +1215,7 @@
}
/* Get the starting bit position in the current bitmap page. */
cur_bmp_pos = bmp_pos & ((PAGE_CACHE_SIZE * 8) - 1);
- bmp_pos &= ~((PAGE_CACHE_SIZE * 8) - 1);
+ bmp_pos &= ~(u64)((PAGE_CACHE_SIZE * 8) - 1);
get_next_bmp_page:
ntfs_debug("Reading bitmap with page index 0x%Lx, bit ofs 0x%Lx",
(long long)bmp_pos >> (3 + PAGE_CACHE_SHIFT),
@@ -1343,8 +1361,6 @@
/* We are finished, set fpos to EOD. */
fpos = vdir->i_size + vol->mft_record_size;
abort:
- put_attr_search_ctx(ctx);
- unmap_mft_record(READ, ndir);
kfree(name);
done:
#ifdef DEBUG
@@ -1366,7 +1382,7 @@
if (ctx)
put_attr_search_ctx(ctx);
if (m)
- unmap_mft_record(READ, ndir);
+ unmap_mft_record(ndir);
if (!err)
err = -EIO;
ntfs_debug("Failed. Returning error code %i.", -err);
diff -Nru a/fs/ntfs/inode.c b/fs/ntfs/inode.c
--- a/fs/ntfs/inode.c Mon Aug 5 00:08:29 2002
+++ b/fs/ntfs/inode.c Mon Aug 5 00:08:29 2002
@@ -278,7 +278,7 @@
ntfs_inode *ni = NTFS_I(inode);

ntfs_debug("Entering.");
- BUG_ON(atomic_read(&ni->mft_count) || !atomic_dec_and_test(&ni->count));
+ BUG_ON(ni->page || !atomic_dec_and_test(&ni->count));
kmem_cache_free(ntfs_big_inode_cache, NTFS_I(inode));
}

@@ -299,7 +299,7 @@
void ntfs_destroy_extent_inode(ntfs_inode *ni)
{
ntfs_debug("Entering.");
- BUG_ON(atomic_read(&ni->mft_count) || !atomic_dec_and_test(&ni->count));
+ BUG_ON(ni->page || !atomic_dec_and_test(&ni->count));
kmem_cache_free(ntfs_inode_cache, ni);
}

@@ -323,8 +323,7 @@
atomic_set(&ni->count, 1);
ni->vol = NTFS_SB(sb);
init_run_list(&ni->run_list);
- init_rwsem(&ni->mrec_lock);
- atomic_set(&ni->mft_count, 0);
+ init_MUTEX(&ni->mrec_lock);
ni->page = NULL;
ni->page_ofs = 0;
ni->attr_list_size = 0;
@@ -504,7 +503,7 @@
ntfs_init_big_inode(vi);
ni = NTFS_I(vi);

- m = map_mft_record(READ, ni);
+ m = map_mft_record(ni);
if (IS_ERR(m)) {
err = PTR_ERR(m);
goto err_out;
@@ -790,6 +789,11 @@
/* No index allocation. */
vi->i_size = ni->initialized_size =
ni->allocated_size = 0;
+ /* We are done with the mft record, so we release it. */
+ put_attr_search_ctx(ctx);
+ unmap_mft_record(ni);
+ m = NULL;
+ ctx = NULL;
goto skip_large_dir_stuff;
} /* LARGE_INDEX: Index allocation present. Setup state. */
NInoSetIndexAllocPresent(ni);
@@ -834,7 +838,14 @@
ctx->attr->_ANR(initialized_size));
ni->allocated_size = sle64_to_cpu(
ctx->attr->_ANR(allocated_size));
-
+ /*
+ * We are done with the mft record, so we release it. Otherwise
+ *
+ */
+ put_attr_search_ctx(ctx);
+ unmap_mft_record(ni);
+ m = NULL;
+ ctx = NULL;
/* Get the index bitmap attribute inode. */
bvi = ntfs_attr_iget(vi, AT_BITMAP, I30, 4);
if (unlikely(IS_ERR(bvi))) {
@@ -858,7 +869,6 @@
bvi->i_size << 3, vi->i_size);
goto unm_err_out;
}
-
skip_large_dir_stuff:
/* Everyone gets read and scan permissions. */
vi->i_mode |= S_IRUGO | S_IXUGO;
@@ -998,6 +1008,11 @@
le32_to_cpu(ctx->attr->_ARA(value_length));
}
no_data_attr_special_case:
+ /* We are done with the mft record, so we release it. */
+ put_attr_search_ctx(ctx);
+ unmap_mft_record(ni);
+ m = NULL;
+ ctx = NULL;
/* Everyone gets all permissions. */
vi->i_mode |= S_IRWXUGO;
/* If read-only, noone gets write permissions. */
@@ -1026,9 +1041,6 @@
else
vi->i_blocks = ni->_ICF(compressed_size) >> 9;

- put_attr_search_ctx(ctx);
- unmap_mft_record(READ, ni);
-
ntfs_debug("Done.");
return 0;

@@ -1037,7 +1049,8 @@
err = -EIO;
if (ctx)
put_attr_search_ctx(ctx);
- unmap_mft_record(READ, ni);
+ if (m)
+ unmap_mft_record(ni);
err_out:
ntfs_error(vi->i_sb, "Failed with error code %i. Marking inode 0x%lx "
"as bad.", -err, vi->i_ino);
@@ -1091,7 +1104,7 @@
/* Set inode type to zero but preserve permissions. */
vi->i_mode = base_vi->i_mode & ~S_IFMT;

- m = map_mft_record(READ, base_ni);
+ m = map_mft_record(base_ni);
if (IS_ERR(m)) {
err = PTR_ERR(m);
goto err_out;
@@ -1265,7 +1278,7 @@
ni->nr_extents = -1;

put_attr_search_ctx(ctx);
- unmap_mft_record(READ, base_ni);
+ unmap_mft_record(base_ni);

ntfs_debug("Done.");
return 0;
@@ -1275,7 +1288,7 @@
err = -EIO;
if (ctx)
put_attr_search_ctx(ctx);
- unmap_mft_record(READ, base_ni);
+ unmap_mft_record(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 "
@@ -1398,7 +1411,7 @@
/* Need this to sanity check attribute list references to $MFT. */
ni->seq_no = le16_to_cpu(m->sequence_number);

- /* Provides readpage() and sync_page() for map_mft_record(READ). */
+ /* Provides readpage() and sync_page() for map_mft_record(). */
vi->i_mapping->a_ops = &ntfs_mft_aops;

ctx = get_attr_search_ctx(ni, m);
@@ -1795,8 +1808,8 @@
}
}
/* Synchronize with ntfs_commit_inode(). */
- down_write(&ni->mrec_lock);
- up_write(&ni->mrec_lock);
+ down(&ni->mrec_lock);
+ up(&ni->mrec_lock);
if (NInoDirty(ni)) {
ntfs_error(ni->vol->sb, "Failed to commit dirty inode "
"asynchronously.");
diff -Nru a/fs/ntfs/inode.h b/fs/ntfs/inode.h
--- a/fs/ntfs/inode.h Mon Aug 5 00:08:29 2002
+++ b/fs/ntfs/inode.h Mon Aug 5 00:08:29 2002
@@ -72,9 +72,8 @@
* The following fields are only valid for real inodes and extent
* inodes.
*/
- struct rw_semaphore mrec_lock; /* Lock for serializing access to the
+ struct semaphore mrec_lock; /* Lock for serializing access to the
mft record belonging to this inode. */
- atomic_t mft_count; /* Mapping reference count for book keeping. */
struct page *page; /* The page containing the mft record of the
inode. This should only be touched by the
(un)map_mft_record*() functions. */
diff -Nru a/fs/ntfs/malloc.h b/fs/ntfs/malloc.h
--- a/fs/ntfs/malloc.h Mon Aug 5 00:08:29 2002
+++ b/fs/ntfs/malloc.h Mon Aug 5 00:08:29 2002
@@ -26,20 +26,6 @@
#include <linux/slab.h>

/**
- * vmalloc_nofs - allocate any pages but don't allow calls into fs layer
- * @size: number of bytes to allocate
- *
- * Allocate any pages but don't allow calls into fs layer. Return allocated
- * memory or NULL if insufficient memory.
- */
-static inline void *vmalloc_nofs(unsigned long size)
-{
- if (likely(size >> PAGE_SHIFT < num_physpages))
- return __vmalloc(size, GFP_NOFS | __GFP_HIGHMEM, PAGE_KERNEL);
- return NULL;
-}
-
-/**
* ntfs_malloc_nofs - allocate memory in multiples of pages
* @size number of bytes to allocate
*
@@ -66,7 +52,8 @@

static inline void ntfs_free(void *addr)
{
- if (likely((unsigned long)addr < VMALLOC_START)) {
+ if (likely(((unsigned long)addr < VMALLOC_START) ||
+ ((unsigned long)addr >= VMALLOC_END ))) {
return kfree(addr);
/* return free_page((unsigned long)addr); */
}
diff -Nru a/fs/ntfs/mft.c b/fs/ntfs/mft.c
--- a/fs/ntfs/mft.c Mon Aug 5 00:08:29 2002
+++ b/fs/ntfs/mft.c Mon Aug 5 00:08:29 2002
@@ -2,7 +2,7 @@
* mft.c - NTFS kernel mft record operations. Part of the Linux-NTFS project.
*
* 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
* modify it under the terms of the GNU General Public License as published
@@ -85,13 +85,15 @@
if (mft_rec)
m = mft_rec;
else {
- m = map_mft_record(WRITE, ni);
+ m = map_mft_record(ni);
if (IS_ERR(m))
return PTR_ERR(m);
}
__format_mft_record(m, ni->vol->mft_record_size, ni->mft_no);
- if (!mft_rec)
- unmap_mft_record(WRITE, ni);
+ if (!mft_rec) {
+ // FIXME: Need to set the mft record dirty!
+ unmap_mft_record(ni);
+ }
return 0;
}

@@ -132,7 +134,7 @@
struct page *page;
unsigned long index, ofs, end_index;

- BUG_ON(atomic_read(&ni->mft_count) || ni->page);
+ BUG_ON(ni->page);
/*
* The index into the page cache and the offset within the page cache
* page of the wanted mft record. FIXME: We need to check for
@@ -146,70 +148,36 @@
end_index = mft_vi->i_size >> PAGE_CACHE_SHIFT;

/* If the wanted index is out of bounds the mft record doesn't exist. */
- if (index >= end_index) {
+ if (unlikely(index >= end_index)) {
if (index > end_index || (mft_vi->i_size & ~PAGE_CACHE_MASK) <
ofs + vol->mft_record_size) {
page = ERR_PTR(-ENOENT);
- goto up_err_out;
+ goto err_out;
}
}
/* Read, map, and pin the page. */
page = ntfs_map_page(mft_vi->i_mapping, index);
- if (!IS_ERR(page)) {
- /* Pin the mft record mapping in the ntfs_inode. */
- atomic_inc(&ni->mft_count);
-
- /* Setup the references in the ntfs_inode. */
+ if (likely(!IS_ERR(page))) {
ni->page = page;
ni->page_ofs = ofs;
-
return page_address(page) + ofs;
}
-up_err_out:
- /* Just in case... */
+err_out:
ni->page = NULL;
ni->page_ofs = 0;
-
ntfs_error(vol->sb, "Failed with error code %lu.", -PTR_ERR(page));
return (void*)page;
}

/**
- * unmap_mft_record_page - unmap the page in which a specific mft record resides
- * @ni: ntfs inode whose mft record page to unmap
- *
- * This unmaps the page in which the mft record of the ntfs inode @ni is
- * situated and returns. This is a NOOP if highmem is not configured.
- *
- * The unmap happens via ntfs_unmap_page() which in turn decrements the use
- * count on the page thus releasing it from the pinned state.
- *
- * We do not actually unmap the page from memory of course, as that will be
- * done by the page cache code itself when memory pressure increases or
- * whatever.
- */
-static inline void unmap_mft_record_page(ntfs_inode *ni)
-{
- BUG_ON(atomic_read(&ni->mft_count) || !ni->page);
- // TODO: If dirty, blah...
- ntfs_unmap_page(ni->page);
- ni->page = NULL;
- ni->page_ofs = 0;
- return;
-}
-
-/**
* map_mft_record - map, pin and lock an mft record
- * @rw: map for read (rw = READ) or write (rw = WRITE)
* @ni: ntfs inode whose MFT record to map
*
- * First, take the mrec_lock semaphore for reading or writing, depending on
- * the value or @rw. We might now be sleeping, while waiting for the semaphore
- * if it was already locked by someone else.
- *
- * Then increment the map reference count and return the mft. If this is the
- * first invocation, the page of the record is first mapped using
- * map_mft_record_page().
+ * First, take the mrec_lock semaphore. We might now be sleeping, while waiting
+ * for the semaphore if it was already locked by someone else.
+ *
+ * The page of the record is first mapped using map_mft_record_page() before
+ * being returned to the caller.
*
* This in turn uses ntfs_map_page() to get the page containing the wanted mft
* record (it in turn calls read_cache_page() which reads it in from disk if
@@ -234,11 +202,11 @@
* locking problem then is them locking the page while we are accessing it.
*
* So that code will end up having to own the mrec_lock of all mft
- * records/inodes present in the page before I/O can proceed. Grr. In that
- * case we wouldn't need need to bother with PG_locked and PG_uptodate as
- * nobody will be accessing anything without owning the mrec_lock semaphore.
- * But we do need to use them because of the read_cache_page() invokation and
- * the code becomes so much simpler this way that it is well worth it.
+ * records/inodes present in the page before I/O can proceed. In that case we
+ * wouldn't need to bother with PG_locked and PG_uptodate as nobody will be
+ * accessing anything without owning the mrec_lock semaphore. But we do need
+ * to use them because of the read_cache_page() invokation and the code becomes
+ * so much simpler this way that it is well worth it.
*
* The mft record is now ours and we return a pointer to it. You need to check
* the returned pointer with IS_ERR() and if that is true, PTR_ERR() will return
@@ -251,89 +219,75 @@
* A: No, the inode ones mean we want to change the mft record, not we want to
* write it out.
*/
-MFT_RECORD *map_mft_record(const int rw, ntfs_inode *ni)
+MFT_RECORD *map_mft_record(ntfs_inode *ni)
{
MFT_RECORD *m;

- ntfs_debug("Entering for mft_no 0x%lx, mapping for %s.", ni->mft_no,
- rw == READ ? "READ" : "WRITE");
+ ntfs_debug("Entering for mft_no 0x%lx.", ni->mft_no);

/* Make sure the ntfs inode doesn't go away. */
atomic_inc(&ni->count);

/* Serialize access to this mft record. */
- if (rw == READ)
- down_read(&ni->mrec_lock);
- else
- down_write(&ni->mrec_lock);
-
- /* If already mapped, bump reference count and return the mft record. */
- if (atomic_read(&ni->mft_count)) {
- BUG_ON(!ni->page);
- atomic_inc(&ni->mft_count);
- return page_address(ni->page) + ni->page_ofs;
- }
+ down(&ni->mrec_lock);

- /* Wasn't mapped. Map it now and return it if all was ok. */
m = map_mft_record_page(ni);
- if (!IS_ERR(m))
+ if (likely(!IS_ERR(m)))
return m;

- /* Mapping failed. Release the mft record lock. */
- if (rw == READ)
- up_read(&ni->mrec_lock);
- else
- up_write(&ni->mrec_lock);
-
- ntfs_error(ni->vol->sb, "Failed with error code %lu.", -PTR_ERR(m));
-
- /* Release the ntfs inode and return the error code. */
+ up(&ni->mrec_lock);
atomic_dec(&ni->count);
+ ntfs_error(ni->vol->sb, "Failed with error code %lu.", -PTR_ERR(m));
return m;
}

/**
- * unmap_mft_record - release a mapped mft record
- * @rw: unmap from read (@rw = READ) or write (@rw = WRITE)
- * @ni: ntfs inode whose MFT record to unmap
- *
- * First, decrement the mapping count and when it reaches zero unmap the mft
- * record.
+ * unmap_mft_record_page - unmap the page in which a specific mft record resides
+ * @ni: ntfs inode whose mft record page to unmap
*
- * Second, release the mrec_lock semaphore.
+ * This unmaps the page in which the mft record of the ntfs inode @ni is
+ * situated and returns. This is a NOOP if highmem is not configured.
*
- * The mft record is now released for others to get hold of.
+ * The unmap happens via ntfs_unmap_page() which in turn decrements the use
+ * count on the page thus releasing it from the pinned state.
*
- * Finally, release the ntfs inode by decreasing the ntfs inode reference count.
+ * We do not actually unmap the page from memory of course, as that will be
+ * done by the page cache code itself when memory pressure increases or
+ * whatever.
+ */
+static inline void unmap_mft_record_page(ntfs_inode *ni)
+{
+ BUG_ON(!ni->page);
+
+ // TODO: If dirty, blah...
+ ntfs_unmap_page(ni->page);
+ ni->page = NULL;
+ ni->page_ofs = 0;
+ return;
+}
+
+/**
+ * unmap_mft_record - release a mapped mft record
+ * @ni: ntfs inode whose MFT record to unmap
*
- * NOTE: If caller had the mft record mapped for write and has modified it, it
- * is imperative to set the mft record dirty BEFORE calling unmap_mft_record().
+ * We release the page mapping and the mrec_lock mutex which unmaps the mft
+ * record and releases it for others to get hold of. We also release the ntfs
+ * inode by decrementing the ntfs inode reference count.
*
- * NOTE: This has to be done both for 'normal' mft records, and for extent mft
- * records.
+ * NOTE: If caller has modified the mft record, it is imperative to set the mft
+ * record dirty BEFORE calling unmap_mft_record().
*/
-void unmap_mft_record(const int rw, ntfs_inode *ni)
+void unmap_mft_record(ntfs_inode *ni)
{
struct page *page = ni->page;

- BUG_ON(!atomic_read(&ni->mft_count) || !page);
+ BUG_ON(!page);

- ntfs_debug("Entering for mft_no 0x%lx, unmapping from %s.", ni->mft_no,
- rw == READ ? "READ" : "WRITE");
+ ntfs_debug("Entering for mft_no 0x%lx.", ni->mft_no);

- /* Only release the actual page mapping if this is the last one. */
- if (atomic_dec_and_test(&ni->mft_count))
- unmap_mft_record_page(ni);
-
- /* Release the semaphore. */
- if (rw == READ)
- up_read(&ni->mrec_lock);
- else
- up_write(&ni->mrec_lock);
-
- /* Release the ntfs inode. */
+ unmap_mft_record_page(ni);
+ up(&ni->mrec_lock);
atomic_dec(&ni->count);
-
/*
* If pure ntfs_inode, i.e. no vfs inode attached, we leave it to
* ntfs_clear_extent_inode() in the extent inode case, and to the
@@ -355,11 +309,6 @@
*
* On successful return, @ntfs_ino contains a pointer to the ntfs_inode
* structure of the mapped extent inode.
- *
- * Note, we always map for READ. We consider this lock as irrelevant because
- * the base inode will be write locked in all cases when we want to write to
- * an extent inode which already gurantees that there is no-one else accessing
- * the extent inode.
*/
MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
ntfs_inode **ntfs_ino)
@@ -393,21 +342,21 @@
break;
}
}
- if (ni) {
+ if (likely(ni != NULL)) {
up(&base_ni->extent_lock);
atomic_dec(&base_ni->count);
/* We found the record; just have to map and return it. */
- m = map_mft_record(READ, ni);
- /* Map mft record increments this on success. */
+ m = map_mft_record(ni);
+ /* map_mft_record() has incremented this on success. */
atomic_dec(&ni->count);
- if (!IS_ERR(m)) {
+ if (likely(!IS_ERR(m))) {
/* Verify the sequence number. */
- if (le16_to_cpu(m->sequence_number) == seq_no) {
+ if (likely(le16_to_cpu(m->sequence_number) == seq_no)) {
ntfs_debug("Done 1.");
*ntfs_ino = ni;
return m;
}
- unmap_mft_record(READ, ni);
+ unmap_mft_record(ni);
ntfs_error(base_ni->vol->sb, "Found stale extent mft "
"reference! Corrupt file system. "
"Run chkdsk.");
@@ -420,7 +369,7 @@
}
/* Record wasn't there. Get a new ntfs inode and initialize it. */
ni = ntfs_new_extent_inode(base_ni->vol->sb, mft_no);
- if (!ni) {
+ if (unlikely(!ni)) {
up(&base_ni->extent_lock);
atomic_dec(&base_ni->count);
return ERR_PTR(-ENOMEM);
@@ -430,15 +379,15 @@
ni->nr_extents = -1;
ni->_INE(base_ntfs_ino) = base_ni;
/* Now map the record. */
- m = map_mft_record(READ, ni);
- if (IS_ERR(m)) {
+ m = map_mft_record(ni);
+ if (unlikely(IS_ERR(m))) {
up(&base_ni->extent_lock);
atomic_dec(&base_ni->count);
ntfs_clear_extent_inode(ni);
goto map_err_out;
}
/* Verify the sequence number. */
- if (le16_to_cpu(m->sequence_number) != seq_no) {
+ if (unlikely(le16_to_cpu(m->sequence_number) != seq_no)) {
ntfs_error(base_ni->vol->sb, "Found stale extent mft "
"reference! Corrupt file system. Run chkdsk.");
destroy_ni = TRUE;
@@ -451,7 +400,7 @@
int new_size = (base_ni->nr_extents + 4) * sizeof(ntfs_inode *);

tmp = (ntfs_inode **)kmalloc(new_size, GFP_NOFS);
- if (!tmp) {
+ if (unlikely(!tmp)) {
ntfs_error(base_ni->vol->sb, "Failed to allocate "
"internal buffer.");
destroy_ni = TRUE;
@@ -472,7 +421,7 @@
*ntfs_ino = ni;
return m;
unm_err_out:
- unmap_mft_record(READ, ni);
+ unmap_mft_record(ni);
up(&base_ni->extent_lock);
atomic_dec(&base_ni->count);
/*
diff -Nru a/fs/ntfs/mft.h b/fs/ntfs/mft.h
--- a/fs/ntfs/mft.h Mon Aug 5 00:08:29 2002
+++ b/fs/ntfs/mft.h Mon Aug 5 00:08:29 2002
@@ -31,15 +31,15 @@
//extern int format_mft_record2(struct super_block *vfs_sb,
// const unsigned long inum, MFT_RECORD *m);

-extern MFT_RECORD *map_mft_record(const int rw, ntfs_inode *ni);
-extern void unmap_mft_record(const int rw, ntfs_inode *ni);
+extern MFT_RECORD *map_mft_record(ntfs_inode *ni);
+extern void unmap_mft_record(ntfs_inode *ni);

extern MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
ntfs_inode **ntfs_ino);

static inline void unmap_extent_mft_record(ntfs_inode *ni)
{
- unmap_mft_record(READ, ni);
+ unmap_mft_record(ni);
return;
}

diff -Nru a/fs/ntfs/namei.c b/fs/ntfs/namei.c
--- a/fs/ntfs/namei.c Mon Aug 5 00:08:29 2002
+++ b/fs/ntfs/namei.c Mon Aug 5 00:08:29 2002
@@ -162,6 +162,7 @@
handle_name:
{
struct dentry *real_dent;
+ MFT_RECORD *m;
attr_search_context *ctx;
ntfs_inode *ni = NTFS_I(dent_inode);
int err;
@@ -175,22 +176,23 @@
name->len * 3 + 1);
kfree(name);
} else /* if (name->type == FILE_NAME_DOS) */ { /* Case 3. */
- MFT_RECORD *m;
FILE_NAME_ATTR *fn;

kfree(name);

/* Find the WIN32 name corresponding to the matched DOS name. */
ni = NTFS_I(dent_inode);
- m = map_mft_record(READ, ni);
+ m = map_mft_record(ni);
if (IS_ERR(m)) {
err = PTR_ERR(m);
- goto name_err_out;
+ m = NULL;
+ ctx = NULL;
+ goto err_out;
}
ctx = get_attr_search_ctx(ni, m);
if (!ctx) {
err = -ENOMEM;
- goto unm_err_out;
+ goto err_out;
}
do {
ATTR_RECORD *a;
@@ -202,21 +204,21 @@
"namespace counterpart to DOS "
"file name. Run chkdsk.");
err = -EIO;
- goto put_unm_err_out;
+ goto err_out;
}
/* Consistency checks. */
a = ctx->attr;
if (a->non_resident || a->flags)
- goto eio_put_unm_err_out;
+ goto eio_err_out;
val_len = le32_to_cpu(a->_ARA(value_length));
if (le16_to_cpu(a->_ARA(value_offset)) + val_len >
le32_to_cpu(a->length))
- goto eio_put_unm_err_out;
+ goto eio_err_out;
fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + le16_to_cpu(
ctx->attr->_ARA(value_offset)));
if ((u32)(fn->file_name_length * sizeof(uchar_t) +
sizeof(FILE_NAME_ATTR)) > val_len)
- goto eio_put_unm_err_out;
+ goto eio_err_out;
} while (fn->file_name_type != FILE_NAME_WIN32);

/* Convert the found WIN32 name to current NLS code page. */
@@ -226,13 +228,15 @@
fn->file_name_length * 3 + 1);

put_attr_search_ctx(ctx);
- unmap_mft_record(READ, ni);
+ unmap_mft_record(ni);
}
+ m = NULL;
+ ctx = NULL;

/* Check if a conversion error occured. */
if ((signed)nls_name.len < 0) {
err = (signed)nls_name.len;
- goto name_err_out;
+ goto err_out;
}
nls_name.hash = full_name_hash(nls_name.name, nls_name.len);

@@ -248,7 +252,7 @@
kfree(nls_name.name);
if (!real_dent) {
err = -ENOMEM;
- goto name_err_out;
+ goto err_out;
}
d_add(real_dent, dent_inode);
return real_dent;
@@ -269,14 +273,14 @@
d_instantiate(real_dent, dent_inode);
return real_dent;

-eio_put_unm_err_out:
+eio_err_out:
ntfs_error(vol->sb, "Illegal file name attribute. Run chkdsk.");
err = -EIO;
-put_unm_err_out:
- put_attr_search_ctx(ctx);
-unm_err_out:
- unmap_mft_record(READ, ni);
-name_err_out:
+err_out:
+ if (ctx)
+ put_attr_search_ctx(ctx);
+ if (m)
+ unmap_mft_record(ni);
iput(dent_inode);
return ERR_PTR(err);
}
diff -Nru a/fs/ntfs/super.c b/fs/ntfs/super.c
--- a/fs/ntfs/super.c Mon Aug 5 00:08:29 2002
+++ b/fs/ntfs/super.c Mon Aug 5 00:08:29 2002
@@ -852,7 +852,7 @@
ntfs_error(sb, "Failed to load $Volume.");
goto iput_lcnbmp_err_out;
}
- m = map_mft_record(READ, NTFS_I(vol->vol_ino));
+ m = map_mft_record(NTFS_I(vol->vol_ino));
if (IS_ERR(m)) {
iput_volume_failed:
iput(vol->vol_ino);
@@ -867,7 +867,7 @@
err_put_vol:
put_attr_search_ctx(ctx);
get_ctx_vol_failed:
- unmap_mft_record(READ, NTFS_I(vol->vol_ino));
+ unmap_mft_record(NTFS_I(vol->vol_ino));
goto iput_volume_failed;
}
vi = (VOLUME_INFORMATION*)((char*)ctx->attr +
@@ -882,7 +882,7 @@
vol->major_ver = vi->major_ver;
vol->minor_ver = vi->minor_ver;
put_attr_search_ctx(ctx);
- unmap_mft_record(READ, NTFS_I(vol->vol_ino));
+ unmap_mft_record(NTFS_I(vol->vol_ino));
printk(KERN_INFO "NTFS volume version %i.%i.\n", vol->major_ver,
vol->minor_ver);
/*

===================================================================

This BitKeeper patch contains the following changesets:
[email protected]|ChangeSet|20020804230133|24300
## Wrapped with gzip_uu ##


begin 664 bkpatch12434
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
MA6F_S9+#W\$<]M&PL9D%I4A2,#DP%Z@VL`;PRPW8[RN"7,A,[email protected]][\-*
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
MJN-\55)F*>VPA[B@[email protected]*ZK;Y5M`OA.-L%B/L1:/"ZLN1WC3!XBBS/B4
M["*Q!UI1'J8P>D97_NN<JW#?0`,9&B<;:.S%J6"6!+J,!UW`;$5/05!A8WF]
MY-/@:4J$D0NLB8!0L](:HHKG%F?'YS!-`EW2$&2L*\X2SH2$`64X<+:;=#:.
M\%*_2H<,*`?"^O_A3;\\!]16^*NZ<Q8!WD$/4CBHFW@\A@5QKI4JA^2VP(J`
M134!0-?J'GXK]UY"'TRYI$0'3H;IPS(9#-.'`?ZQ..T@ZH<!.,?J,./D.OW,
M)1M5!HA2[S`0N)?C?&"^)K-P)/)X,AU3*05PZR:XY1.)J?SM!F``G$@&6X<(
M!X[>IKB"FW>O+_L7IZ_.+WKB25T9RXHB6/$)*"8.)'%7G&.DUY$>S*XZCT_1
MG%<>':=(4F%\^?/X2_?QH2`83\_H<A!59WD[N!W^]Q3A.VCXYLSU&W02<XB8
M&5#"QPLV2B)M"QW@G5P0S;<=V&59A?"ZZ99CAEM8O^$`&.$(!Y,(DHH21=V.
M$0,!#]'SI0"#,(/6`K<"07YA&(>K9A%$'L,JG/"')#[AJQG!#+@9I?F:#:4)
M.1D=3#&MP3=]ALD4D;.B=_F6]6OVN!3`E>5@?9`<$K"XF`5%J2NLS7E5QP-V
M1;P_/_^`AF8$5FH"0DUE'`6ZQ&%\!9XNZB)Q-A-G5\3I\FA&:%'`;5['@:CG
MS`]*8M$$X'52I$/PU&`4>$>@[email protected]?,92YV68SPPS44TJ-$@@X,LW3"[^,$
M;1%6AVJBRV6ZH/':G-F(.*T5A+!M=-LU%M)4L,\TN\5C@]6S7!^BX2"%6S$;
ME'08W"Z'DFJS5,5%KL=#+J(J)Z,B,$0&<0+;#+!X*<W(E,&\"#?02!^WN;`5
M.HUCF/XZC:/MPK>AO+\MO.BC%3?Z2QL]]N5Y[_Q$G`W9,1^*P3@8=;O=S6N,
ME9&M1<YLD?:HGO0A(H"G!CQB@7G:_AU6.G[R9)NN@)I4^9>@\C!+V=RA#&"Y
M*@%>U0,N%Y:&,$N.9LL+.&8$+L+F/*J9;HZ56>Q6E`?(6;JH4A'&S".4+K`5
MY%T(O%XM;TW(>P>,,)<DX#YP-MX*",A"KBM7LK+33`]UIA/"F!2?]TPL]<,-
MEHK^_OSRE'C'GA4T"D!K&H%MT?4[@\/2'X"K`/1:(`Q?QV<KFR1)$"]/7Y]?
MG-+45-I8AVL'1!`K-S5;!7+3D9A<*,W-0BXK:&=2&<"9R7?[>[H94UGD9KAP
M?`-I5O+<E&KJF285X)@$"GLFE>.<<;/JA\!./F(%8&!H&9C;.[/(,S2C:,I.
M;N3<D7>D_B@-Q#[@%E:SSPB"</[,8DMOE25!#3Z1:;&Y9WD1NM)UK*73+])^
M.)UU)N`!]:\SE+)^,IL,='8`$2K(Q:]XE#R3I,PE-XVYY)ZEF#1J:M=OT(.G
M,BE^L)@MC>>SX[ZP9W%A`#?K/;^VKT>U?3$2XJ9>VUA,IF4O3EUQT[#W>I"_
MD8:Z^W<];"2AEM_PL)*!LNWJFVKN<X\DCKY/1>)>U?OT)14[@MZ],CPD5V<F
M(@W]!7,,XNX(]VDUY$YFC`2>Y?UN<E%^E4)-,N[U/0W-":"U[VFH4D!J;OB6
MSQ>.ZKX5^-_IPG$_4<%OFV@0E7+G^WQR55(E3&M-0IYRX([QN\<Y",_>G1&1
MG#C!QMQYH;8EY^!S2L+?GI)0;,%59<$WWK-=5I5=+M_':7^U#T=[TMK5A\,L
M]L<-?13W44TW['2/J4QC1WT)1/V\(7-[92A_ZH:;;16HBH-!;%:(.^&*4YOC
M1/L!JVPV5+C\^I6:"M_KNUV:57CMNUV6*JR4,F3Y.?/[Z/"_F+&G;ZAI4.%R
MYWM]U-/F:B]JMNDH?>+SC#]O`#_H(U('5%E.NN.55:L;O&\<QU:!FSL/6WP)
8'MU]Y+/),]/W[,#45OO_`)54W^.\3P``
`
end