This is an incremental patch from 2.0.22b to 2.0.23a for kernel 2.4.19-vanilla.
Have fun,
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/
--- ntfs-2.0.22b-to-2.0.23a.patch ---
diff -urNp linux-2.4.19-tg3-ntfs-2.0.22b/Documentation/filesystems/ntfs.txt linux-2.4.19-tg3-ntfs-2.0.23a/Documentation/filesystems/ntfs.txt
--- linux-2.4.19-tg3-ntfs-2.0.22b/Documentation/filesystems/ntfs.txt Sun Aug 4 21:13:10 2002
+++ linux-2.4.19-tg3-ntfs-2.0.23a/Documentation/filesystems/ntfs.txt Sun Aug 4 21:14:52 2002
@@ -247,6 +247,14 @@ ChangeLog
Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
+2.0.23a:
+ - 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.22a:
- Sync with NTFS 2.0.22 and kernel 2.4.19.
2.0.22:
diff -urNp linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/ChangeLog linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/ChangeLog
--- linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/ChangeLog Sun Aug 4 21:12:51 2002
+++ linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/ChangeLog Sun Aug 4 21:31:43 2002
@@ -1,6 +1,20 @@
ToDo:
- Find and fix bugs.
+2.0.23a - 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.22a - Updates of the backport.
- Sync with NTFS 2.0.22.
diff -urNp linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/Makefile linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/Makefile
--- linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/Makefile Sun Aug 4 21:12:52 2002
+++ linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/Makefile Sun Aug 4 21:14:51 2002
@@ -7,7 +7,7 @@ obj-y := aops.o attrib.o compress.o de
obj-m := $(O_TARGET)
-EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.22a\"
+EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.23a\"
ifeq ($(CONFIG_NTFS_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
diff -urNp linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/aops.c linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/aops.c
--- linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/aops.c Sun Aug 4 21:12:36 2002
+++ linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/aops.c Sun Aug 4 21:14:30 2002
@@ -335,6 +335,8 @@ handle_zblock:
* 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)
{
@@ -375,8 +377,8 @@ int ntfs_readpage(struct file *file, str
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;
@@ -419,7 +421,7 @@ int ntfs_readpage(struct file *file, str
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;
@@ -429,8 +431,8 @@ err_out:
* ntfs_aops - general address space operations for inodes and attributes
*/
struct address_space_operations ntfs_aops = {
- readpage: ntfs_readpage, /* Fill page with data. */
- sync_page: block_sync_page, /* Currently, just unplugs the
+ .readpage = ntfs_readpage, /* Fill page with data. */
+ .sync_page = block_sync_page, /* Currently, just unplugs the
disk request queue. */
};
diff -urNp linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/attrib.c linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/attrib.c
--- linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/attrib.c Sun Aug 4 21:12:47 2002
+++ linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/attrib.c Sun Aug 4 21:14:54 2002
@@ -947,7 +947,7 @@ int map_run_list(ntfs_inode *ni, VCN vcn
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);
@@ -978,7 +978,7 @@ int map_run_list(ntfs_inode *ni, VCN vcn
put_attr_search_ctx(ctx);
err_out:
- unmap_mft_record(READ, base_ni);
+ unmap_mft_record(base_ni);
return err;
}
@@ -1670,7 +1670,7 @@ void reinit_attr_search_ctx(attr_search_
return;
} /* Attribute list. */
if (ctx->ntfs_ino != ctx->base_ntfs_ino)
- unmap_mft_record(READ, ctx->ntfs_ino);
+ unmap_extent_mft_record(ctx->ntfs_ino);
init_attr_search_ctx(ctx, ctx->base_ntfs_ino, ctx->base_mrec);
return;
}
@@ -1703,7 +1703,7 @@ attr_search_context *get_attr_search_ctx
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_extent_mft_record(ctx->ntfs_ino);
kmem_cache_free(ntfs_attr_ctx_cache, ctx);
return;
}
diff -urNp linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/compress.c linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/compress.c
--- linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/compress.c Sun Aug 4 21:12:43 2002
+++ linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/compress.c Sun Aug 4 21:24:37 2002
@@ -609,8 +609,27 @@ lock_retry_remap:
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);
+ run_task_queue(&tq_disk);
+ schedule();
+ put_bh(tbh);
+ if (unlikely(!buffer_uptodate(tbh)))
+ goto read_err;
+ ntfs_warning(vol->sb, "Buffer is now uptodate. Good.");
+ }
}
/*
diff -urNp linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/dir.c linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/dir.c
--- linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/dir.c Sun Aug 4 21:13:12 2002
+++ linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/dir.c Sun Aug 4 21:14:53 2002
@@ -77,7 +77,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_i
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;
@@ -85,23 +85,24 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_i
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 +
@@ -155,7 +156,7 @@ found_it:
GFP_NOFS);
if (!name) {
err = -ENOMEM;
- goto put_unm_err_out;
+ goto err_out;
}
}
name->mref = le64_to_cpu(
@@ -170,7 +171,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;
}
/*
@@ -209,7 +210,7 @@ found_it:
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;
@@ -268,12 +269,12 @@ found_it:
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)) {
@@ -281,11 +282,19 @@ found_it:
"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
@@ -297,7 +306,8 @@ descend_into_child_node:
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:
@@ -309,7 +319,7 @@ fast_descend_into_child_node:
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 "
@@ -319,7 +329,7 @@ fast_descend_into_child_node:
(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)) {
@@ -331,7 +341,7 @@ fast_descend_into_child_node:
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) {
@@ -340,7 +350,7 @@ fast_descend_into_child_node:
"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)) {
@@ -348,7 +358,7 @@ fast_descend_into_child_node:
"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 +
@@ -368,7 +378,7 @@ fast_descend_into_child_node:
"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
@@ -404,7 +414,7 @@ found_it2:
GFP_NOFS);
if (!name) {
err = -ENOMEM;
- goto unm_unm_err_out;
+ goto unm_err_out;
}
}
name->mref = le64_to_cpu(
@@ -419,8 +429,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;
}
/*
@@ -460,7 +468,7 @@ found_it2:
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;
@@ -520,7 +528,7 @@ found_it2:
"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;
@@ -540,7 +548,7 @@ found_it2:
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
@@ -549,31 +557,26 @@ found_it2:
*/
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
@@ -623,23 +626,24 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode
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 +
@@ -690,7 +694,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode
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;
}
/*
@@ -738,7 +742,7 @@ found_it:
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)) {
@@ -746,11 +750,19 @@ found_it:
"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
@@ -762,7 +774,8 @@ descend_into_child_node:
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:
@@ -774,7 +787,7 @@ fast_descend_into_child_node:
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 "
@@ -784,7 +797,7 @@ fast_descend_into_child_node:
(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)) {
@@ -796,7 +809,7 @@ fast_descend_into_child_node:
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) {
@@ -805,7 +818,7 @@ fast_descend_into_child_node:
"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)) {
@@ -813,7 +826,7 @@ fast_descend_into_child_node:
"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 +
@@ -833,7 +846,7 @@ fast_descend_into_child_node:
"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
@@ -866,8 +879,6 @@ fast_descend_into_child_node:
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;
}
/*
@@ -918,7 +929,7 @@ found_it2:
"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;
@@ -938,26 +949,23 @@ found_it2:
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
@@ -1092,22 +1100,8 @@ static int ntfs_readdir(struct file *fil
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.
@@ -1121,6 +1115,18 @@ static int ntfs_readdir(struct file *fil
/* 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. */
@@ -1159,9 +1165,21 @@ static int ntfs_readdir(struct file *fil
/* 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;
@@ -1340,8 +1358,6 @@ EOD:
/* 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
@@ -1363,7 +1379,7 @@ err_out:
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);
@@ -1397,9 +1413,9 @@ static int ntfs_dir_open(struct inode *v
}
struct file_operations ntfs_dir_ops = {
- llseek: generic_file_llseek, /* Seek inside directory. */
- read: generic_read_dir, /* Return -EISDIR. */
- readdir: ntfs_readdir, /* Read directory contents. */
- open: ntfs_dir_open, /* Open directory. */
+ .llseek = generic_file_llseek, /* Seek inside directory. */
+ .read = generic_read_dir, /* Return -EISDIR. */
+ .readdir = ntfs_readdir, /* Read directory contents. */
+ .open = ntfs_dir_open, /* Open directory. */
};
diff -urNp linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/file.c linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/file.c
--- linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/file.c Sun Aug 4 21:12:28 2002
+++ linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/file.c Sun Aug 4 21:14:52 2002
@@ -49,10 +49,10 @@ static int ntfs_file_open(struct inode *
}
struct file_operations ntfs_file_ops = {
- llseek: generic_file_llseek, /* Seek inside file. */
- read: generic_file_read, /* Read from file. */
- mmap: generic_file_mmap, /* Mmap file. */
- open: ntfs_file_open, /* Open file. */
+ .llseek = generic_file_llseek, /* Seek inside file. */
+ .read = generic_file_read, /* Read from file. */
+ .mmap = generic_file_mmap, /* Mmap file. */
+ .open = ntfs_file_open, /* Open file. */
};
struct inode_operations ntfs_file_inode_ops = {};
diff -urNp linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/inode.c linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/inode.c
--- linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/inode.c Sun Aug 4 21:12:52 2002
+++ linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/inode.c Sun Aug 4 21:14:51 2002
@@ -252,7 +252,7 @@ static inline ntfs_inode *ntfs_alloc_ext
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);
}
@@ -276,8 +276,7 @@ static void __ntfs_init_inode(struct sup
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;
@@ -469,7 +468,7 @@ void ntfs_read_locked_inode(struct inode
vi->i_gid = vol->gid;
vi->i_mode = 0;
- m = map_mft_record(READ, ni);
+ m = map_mft_record(ni);
if (IS_ERR(m)) {
err = PTR_ERR(m);
goto err_out;
@@ -755,6 +754,11 @@ skip_attr_list_load:
/* 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);
@@ -799,7 +803,14 @@ skip_attr_list_load:
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
+ * we would deadlock in ntfs_attr_iget().
+ */
+ 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))) {
@@ -823,7 +834,6 @@ skip_attr_list_load:
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;
@@ -963,6 +973,11 @@ skip_large_dir_stuff:
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. */
@@ -991,9 +1006,6 @@ no_data_attr_special_case:
else
vi->i_blocks = ni->_ICF(compressed_size) >> 9;
- put_attr_search_ctx(ctx);
- unmap_mft_record(READ, ni);
-
ntfs_debug("Done.");
return;
unm_err_out:
@@ -1001,7 +1013,8 @@ unm_err_out:
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);
@@ -1055,7 +1068,7 @@ static int ntfs_read_locked_attr_inode(s
/* 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;
@@ -1229,7 +1242,7 @@ static int ntfs_read_locked_attr_inode(s
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;
@@ -1239,7 +1252,7 @@ unm_err_out:
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 "
@@ -1364,7 +1377,7 @@ void ntfs_read_inode_mount(struct inode
/* 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);
@@ -1761,8 +1774,8 @@ void __ntfs_clear_inode(ntfs_inode *ni)
}
}
/* 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.");
@@ -1836,7 +1849,7 @@ void ntfs_clear_big_inode(struct inode *
ni->_INE(base_ntfs_ino) = NULL;
}
}
- BUG_ON(atomic_read(&ni->mft_count) || !atomic_dec_and_test(&ni->count));
+ BUG_ON(ni->page || !atomic_dec_and_test(&ni->count));
return;
}
diff -urNp linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/inode.h linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/inode.h
--- linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/inode.h Sun Aug 4 21:12:32 2002
+++ linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/inode.h Sun Aug 4 21:14:21 2002
@@ -77,9 +77,8 @@ struct _ntfs_inode {
* 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 -urNp linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/kcompat.h linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/kcompat.h
--- linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/kcompat.h Sun Aug 4 21:12:32 2002
+++ linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/kcompat.h Sun Aug 4 21:14:25 2002
@@ -25,10 +25,6 @@
#define _LINUX_NTFS_KCOMPAT_H
#include <linux/version.h>
-
-/* Just in case someone would like to use it with 2.5.x ;-) */
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-
#include <linux/compiler.h>
#ifndef MAX_BUF_PER_PAGE
@@ -45,11 +41,6 @@
# define MAX_LFS_FILESIZE 0x7fffffffffffffff
#endif
-#ifndef CONFIG_PREEMPT
-# define preempt_disable() do {} while (0);
-# define preempt_enable() do {} while (0);
-#endif
-
#include <linux/fs.h>
/*
@@ -83,24 +74,4 @@ BUFFER_FNS(Uptodate, uptodate)
BUFFER_FNS(Async, async)
TAS_BUFFER_FNS(Lock, locked)
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19))
-/* Copied from 2.5.x: fs/block_dev.c. This function was introduced with
- 2.4.19-pre8 kernel version. If you use some post pre7 version but earlier
- then 2.4.19 release you will want to remove these -- pkot */
-static inline int sb_set_blocksize(struct super_block *sb, int size)
-{
- int bits;
- if (set_blocksize(sb->s_dev, size) < 0)
- return 0;
- sb->s_blocksize = size;
- for (bits = 9, size >>= 9; size >>= 1; bits++)
- ;
- sb->s_blocksize_bits = bits;
- return sb->s_blocksize;
-}
-
-#endif /* Linux 2.4.18 and older */
-
-#endif /* Linux 2.4.x */
-
#endif /* _LINUX_NTFS_KCOMPAT_H */
diff -urNp linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/malloc.h linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/malloc.h
--- linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/malloc.h Sun Aug 4 21:12:52 2002
+++ linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/malloc.h Sun Aug 4 21:14:54 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_malloc_nofs(uns
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 -urNp linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/mft.c linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/mft.c
--- linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/mft.c Sun Aug 4 21:12:42 2002
+++ linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/mft.c Sun Aug 4 21:14:21 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
@@ -86,13 +86,15 @@ int format_mft_record(ntfs_inode *ni, MF
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;
}
@@ -108,12 +110,12 @@ extern int ntfs_readpage(struct file *,
* ntfs_map_page() in map_mft_record_page().
*/
struct address_space_operations ntfs_mft_aops = {
- writepage: NULL, /* Write dirty page to disk. */
- readpage: ntfs_readpage, /* Fill page with data. */
- sync_page: block_sync_page, /* Currently, just unplugs the
+ .writepage = NULL, /* Write dirty page to disk. */
+ .readpage = ntfs_readpage, /* Fill page with data. */
+ .sync_page = block_sync_page, /* Currently, just unplugs the
disk request queue. */
- prepare_write: NULL, /* . */
- commit_write: NULL, /* . */
+ .prepare_write = NULL, /* . */
+ .commit_write = NULL, /* . */
};
/**
@@ -133,7 +135,7 @@ static inline MFT_RECORD *map_mft_record
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
@@ -147,70 +149,36 @@ static inline MFT_RECORD *map_mft_record
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 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
@@ -235,11 +203,11 @@ static inline void unmap_mft_record_page
* 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 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
@@ -252,89 +220,75 @@ static inline void unmap_mft_record_page
* 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
@@ -356,11 +310,6 @@ void unmap_mft_record(const int rw, ntfs
*
* 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)
@@ -394,21 +343,21 @@ MFT_RECORD *map_extent_mft_record(ntfs_i
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.");
@@ -421,7 +370,7 @@ map_err_out:
}
/* 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);
@@ -431,15 +380,15 @@ map_err_out:
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;
@@ -452,7 +401,7 @@ map_err_out:
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;
@@ -473,7 +422,7 @@ map_err_out:
*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 -urNp linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/mft.h linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/mft.h
--- linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/mft.h Sun Aug 4 21:13:13 2002
+++ linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/mft.h Sun Aug 4 21:14:53 2002
@@ -31,15 +31,15 @@ extern int format_mft_record(ntfs_inode
//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 -urNp linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/namei.c linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/namei.c
--- linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/namei.c Sun Aug 4 21:12:41 2002
+++ linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/namei.c Sun Aug 4 21:14:23 2002
@@ -164,6 +164,7 @@ static struct dentry *ntfs_lookup(struct
handle_name:
{
struct dentry *real_dent;
+ MFT_RECORD *m;
attr_search_context *ctx;
ntfs_inode *ni = NTFS_I(dent_inode);
int err;
@@ -177,22 +178,23 @@ handle_name:
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;
@@ -204,21 +206,21 @@ handle_name:
"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. */
@@ -228,13 +230,15 @@ handle_name:
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);
@@ -250,7 +254,7 @@ handle_name:
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;
@@ -271,14 +275,14 @@ handle_name:
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);
}
@@ -288,6 +292,6 @@ name_err_out:
* Inode operations for directories.
*/
struct inode_operations ntfs_dir_inode_ops = {
- lookup: ntfs_lookup, /* VFS: Lookup directory. */
+ .lookup = ntfs_lookup, /* VFS: Lookup directory. */
};
diff -urNp linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/super.c linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/super.c
--- linux-2.4.19-tg3-ntfs-2.0.22b/fs/ntfs/super.c Sun Aug 4 21:13:13 2002
+++ linux-2.4.19-tg3-ntfs-2.0.23a/fs/ntfs/super.c Sun Aug 4 21:14:54 2002
@@ -852,7 +852,7 @@ volume_failed:
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 @@ iput_volume_failed:
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 @@ get_ctx_vol_failed:
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);
/*
@@ -1260,9 +1260,9 @@ static int ntfs_statfs(struct super_bloc
* proper functions.
*/
struct super_operations ntfs_mount_sops = {
- read_inode: ntfs_read_inode_mount, /* VFS: Load inode from disk,
+ .read_inode = ntfs_read_inode_mount,/* VFS: Load inode from disk,
called from iget(). */
- clear_inode: ntfs_clear_big_inode, /* VFS: Called when an inode is
+ .clear_inode = ntfs_clear_big_inode, /* VFS: Called when an inode is
removed from memory. */
};
@@ -1272,19 +1272,21 @@ typedef void (*read_inode2_t)(struct ino
* The complete super operations.
*/
struct super_operations ntfs_sops = {
- read_inode2: (read_inode2_t)ntfs_read_locked_inode, /* VFS: Load
+ .read_inode2 = (read_inode2_t)ntfs_read_locked_inode, /* VFS: Load
inode from disk, called from
ntfs_iget(). */
- dirty_inode: ntfs_dirty_inode, /* VFS: Called from
+ .dirty_inode = ntfs_dirty_inode, /* VFS: Called from
__mark_inode_dirty(). */
- put_inode: ntfs_put_inode, /* VFS: Called just before the inode
- reference count is decreased. */
- put_super: ntfs_put_super, /* Syscall: umount. */
- statfs: ntfs_statfs, /* Syscall: statfs */
- remount_fs: ntfs_remount, /* Syscall: mount -o remount. */
- clear_inode: ntfs_clear_big_inode, /* VFS: Called when an inode is
+ .put_inode = ntfs_put_inode, /* VFS: Called just before the
+ inode reference count is
+ decreased. */
+ .put_super = ntfs_put_super, /* Syscall: umount. */
+ .statfs = ntfs_statfs, /* Syscall: statfs */
+ .remount_fs = ntfs_remount, /* Syscall: mount -o remount. */
+ .clear_inode = ntfs_clear_big_inode, /* VFS: Called when an inode is
removed from memory. */
- show_options: ntfs_show_options, /* Show mount options in proc. */
+ .show_options = ntfs_show_options, /* Show mount options in
+ proc. */
};
/**
diff -urNp linux-2.4.19-tg3-ntfs-2.0.22b/include/linux/dcache.h linux-2.4.19-tg3-ntfs-2.0.23a/include/linux/dcache.h
--- linux-2.4.19-tg3-ntfs-2.0.22b/include/linux/dcache.h Sun Aug 4 21:13:11 2002
+++ linux-2.4.19-tg3-ntfs-2.0.23a/include/linux/dcache.h Sun Aug 4 21:14:52 2002
@@ -5,6 +5,7 @@
#include <asm/atomic.h>
#include <linux/mount.h>
+#include <linux/kernel.h>
/*
* linux/include/linux/dcache.h
|