]> git.neil.brown.name Git - history.git/commitdiff
NTFS: 2.0.23 - Major bug fixes (races, deadlocks, non-i386 architectures).
authorAnton Altaparmakov <aia21@cantab.net>
Mon, 5 Aug 2002 01:01:33 +0000 (02:01 +0100)
committerAnton Altaparmakov <aia21@cantab.net>
Mon, 5 Aug 2002 01:01:33 +0000 (02:01 +0100)
- 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.

14 files changed:
Documentation/filesystems/ntfs.txt
fs/ntfs/ChangeLog
fs/ntfs/Makefile
fs/ntfs/aops.c
fs/ntfs/attrib.c
fs/ntfs/compress.c
fs/ntfs/dir.c
fs/ntfs/inode.c
fs/ntfs/inode.h
fs/ntfs/malloc.h
fs/ntfs/mft.c
fs/ntfs/mft.h
fs/ntfs/namei.c
fs/ntfs/super.c

index ee1dd43d5da062f164defc3c32523a75fbc23b05..0abee2c6f899e7527355fa93bd0ac6a32a4cb867 100644 (file)
@@ -247,6 +247,14 @@ ChangeLog
 
 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:
index eaf9673a83a2cfb9fbf8d17690e31a7feecbb675..ab57d6ab0593b7397a7acbeae4110780a3271a4b 100644 (file)
@@ -2,6 +2,20 @@ ToDo:
        - 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
index 2854d48c606a107c3533f0d0aa2e8656aaf38871..30b50a7fe515b86e39b1e0175ebbd882e7e9011e 100644 (file)
@@ -5,7 +5,7 @@ obj-$(CONFIG_NTFS_FS) += ntfs.o
 ntfs-objs := aops.o attrib.o compress.o debug.o dir.o file.o inode.o mft.o \
             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
index eabcf4e3127afa42deb0f18f2a7d60c7408f7554..fa36979b4e7eb4d1072f1edc340d918f7bd79886 100644 (file)
@@ -106,8 +106,6 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate)
        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 @@ 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)
 {
@@ -372,8 +372,8 @@ int ntfs_readpage(struct file *file, struct page *page)
        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 @@ int ntfs_readpage(struct file *file, struct page *page)
 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;
index e1780078cb69f58d7de3541946652abadbee7f74..e995eadfdaef73462346920fc9b991fb2835e546 100644 (file)
@@ -948,7 +948,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);
@@ -979,7 +979,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;
 }
 
@@ -1671,7 +1671,7 @@ void reinit_attr_search_ctx(attr_search_context *ctx)
                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 @@ attr_search_context *get_attr_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec)
 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;
 }
index b0a3b4da132c4b384feec143f0f2d21796dafddd..fbfe8e8bc941e7ac75c2382614c5c531a275b25c 100644 (file)
@@ -608,8 +608,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);
+                       blk_run_queues();
+                       schedule();
+                       put_bh(tbh);
+                       if (unlikely(!buffer_uptodate(tbh)))
+                               goto read_err;
+                       ntfs_warning(vol->sb, "Buffer is now uptodate. Good.");
+               }
        }
 
        /*
index e7b2dd0195164dd73cb54720d2a7b3cc72dfbdda..f92d2bc0ecdb594da30d998500013e86855fd53b 100644 (file)
@@ -76,7 +76,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
        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 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
        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 @@ found_it:
                                                        GFP_NOFS);
                                        if (!name) {
                                                err = -ENOMEM;
-                                               goto put_unm_err_out;
+                                               goto err_out;
                                        }
                                }
                                name->mref = le64_to_cpu(
@@ -169,7 +170,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;
                }
                /*
@@ -208,7 +209,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;
@@ -267,12 +268,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)) {
@@ -280,11 +281,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
@@ -296,7 +305,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:
@@ -308,7 +318,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 "
@@ -318,7 +328,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)) {
@@ -330,7 +340,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) {
@@ -339,7 +349,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)) {
@@ -347,7 +357,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 +
@@ -367,7 +377,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
@@ -403,7 +413,7 @@ found_it2:
                                                        GFP_NOFS);
                                        if (!name) {
                                                err = -ENOMEM;
-                                               goto unm_unm_err_out;
+                                               goto unm_err_out;
                                        }
                                }
                                name->mref = le64_to_cpu(
@@ -418,8 +428,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;
                }
                /*
@@ -459,7 +467,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;
@@ -519,7 +527,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;
@@ -539,7 +547,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
@@ -548,31 +556,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
@@ -614,7 +617,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
        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 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
        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 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
 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 @@ 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)) {
@@ -745,11 +749,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
@@ -761,7 +773,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:
@@ -773,7 +786,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 "
@@ -783,7 +796,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)) {
@@ -795,7 +808,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) {
@@ -804,7 +817,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)) {
@@ -812,7 +825,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 +
@@ -832,7 +845,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
@@ -865,8 +878,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;
                }
                /*
@@ -917,7 +928,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;
@@ -937,26 +948,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
@@ -1095,22 +1103,8 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
                        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 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
        /* 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 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
                /* 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 @@ skip_index_root:
        }
        /* 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 @@ 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
@@ -1366,7 +1382,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);
index ac0b770f335095b74e897279812741e6dcc5f4c2..936e0299e5b821e60aa6c9d5d8ec4e6d8ee3c3d0 100644 (file)
@@ -278,7 +278,7 @@ void ntfs_destroy_big_inode(struct inode *inode)
        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 @@ static inline ntfs_inode *ntfs_alloc_extent_inode(void)
 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 @@ static void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni)
        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 @@ static int ntfs_read_locked_inode(struct inode *vi)
                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 @@ 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);
@@ -834,7 +838,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
+                *
+                */
+               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 @@ 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;
@@ -998,6 +1008,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. */
@@ -1026,9 +1041,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 0;
 
@@ -1037,7 +1049,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);
@@ -1091,7 +1104,7 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
        /* 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 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
        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 @@ 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 "
@@ -1398,7 +1411,7 @@ void ntfs_read_inode_mount(struct inode *vi)
        /* 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 @@ 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.");
index 0b9b051a9a075caca78e5c093872880895f488d0..6ffed2bbf51b6ea1efb7f15841562c90110c8bf3 100644 (file)
@@ -72,9 +72,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. */
index 91a685753a4bc631c49d4952d5a811b4e1ca6869..98170fb3773fc9f8fc6d541f6468d75a059bf681 100644 (file)
 #include <linux/vmalloc.h>
 #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(unsigned long size)
 
 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); */
        }
index f5fc70b7d8d6babbe30a2b224bbf81f38d12659b..5291e7299f8a535952e97031698cf812b4327ae2 100644 (file)
@@ -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 @@ int format_mft_record(ntfs_inode *ni, MFT_RECORD *mft_rec)
        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 @@ static inline MFT_RECORD *map_mft_record_page(ntfs_inode *ni)
        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 @@ static inline MFT_RECORD *map_mft_record_page(ntfs_inode *ni)
        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.
+ * First, take the mrec_lock semaphore. 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().
+ * 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 @@ static inline void unmap_mft_record_page(ntfs_inode *ni)
  * 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 @@ static inline void unmap_mft_record_page(ntfs_inode *ni)
  * 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);
-
-       ntfs_debug("Entering for mft_no 0x%lx, unmapping from %s.", ni->mft_no,
-                       rw == READ ? "READ" : "WRITE");
+       BUG_ON(!page);
 
-       /* 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);
+       ntfs_debug("Entering for mft_no 0x%lx.", ni->mft_no);
 
-       /* 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 @@ void unmap_mft_record(const int rw, ntfs_inode *ni)
  *
  * 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 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
                        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 @@ 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);
@@ -430,15 +379,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;
@@ -451,7 +400,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;
@@ -472,7 +421,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);
        /*
index 72d421834a0dc010adb8c5878cea8000a27a769a..61b17ffbed06ca56160df3dc28a5bae43b396618 100644 (file)
@@ -31,15 +31,15 @@ extern int format_mft_record(ntfs_inode *ni, MFT_RECORD *m);
 //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;
 }
 
index 772248de883944bac755b5b4cd502a8659f677d6..e29b8e8b9df81ba855028dbc242e3a96cc504dc0 100644 (file)
@@ -162,6 +162,7 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent)
 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 @@ 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;
@@ -202,21 +204,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. */
@@ -226,13 +228,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);
 
@@ -248,7 +252,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;
@@ -269,14 +273,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);
    }
index 108b4a160d5c990935b34230ee4e71803d26d19b..367615e6798aed44b9f0fb4109577ed3e758b0e5 100644 (file)
@@ -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);
        /*