NTFS: Change ntfs_cluster_free() to require a write locked runlist on entry
[platform/adaptation/renesas_rcar/renesas_kernel.git] / fs / ntfs / mft.c
index 3d0ba8e..247586d 100644 (file)
@@ -511,7 +511,6 @@ int ntfs_sync_mft_mirror(ntfs_volume *vol, const unsigned long mft_no,
                } while (bh);
                tail->b_this_page = head;
                attach_page_buffers(page, head);
-               BUG_ON(!page_has_buffers(page));
        }
        bh = head = page_buffers(page);
        BUG_ON(!bh);
@@ -533,6 +532,7 @@ int ntfs_sync_mft_mirror(ntfs_volume *vol, const unsigned long mft_no,
                        LCN lcn;
                        unsigned int vcn_ofs;
 
+                       bh->b_bdev = vol->sb->s_bdev;
                        /* Obtain the vcn and offset of the current block. */
                        vcn = ((VCN)mft_no << vol->mft_record_size_bits) +
                                        (block_start - m_start);
@@ -691,7 +691,6 @@ int write_mft_record_nolock(ntfs_inode *ni, MFT_RECORD *m, int sync)
         */
        if (!NInoTestClearDirty(ni))
                goto done;
-       BUG_ON(!page_has_buffers(page));
        bh = head = page_buffers(page);
        BUG_ON(!bh);
        rl = NULL;
@@ -725,6 +724,7 @@ int write_mft_record_nolock(ntfs_inode *ni, MFT_RECORD *m, int sync)
                        LCN lcn;
                        unsigned int vcn_ofs;
 
+                       bh->b_bdev = vol->sb->s_bdev;
                        /* Obtain the vcn and offset of the current block. */
                        vcn = ((VCN)ni->mft_no << vol->mft_record_size_bits) +
                                        (block_start - m_start);
@@ -948,20 +948,23 @@ BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no,
        na.name_len = 0;
        na.type = AT_UNUSED;
        /*
-        * For inode 0, i.e. $MFT itself, we cannot use ilookup5() from here or
-        * we deadlock because the inode is already locked by the kernel
-        * (fs/fs-writeback.c::__sync_single_inode()) and ilookup5() waits
-        * until the inode is unlocked before returning it and it never gets
-        * unlocked because ntfs_should_write_mft_record() never returns.  )-:
-        * Fortunately, we have inode 0 pinned in icache for the duration of
-        * the mount so we can access it directly.
+        * Optimize inode 0, i.e. $MFT itself, since we have it in memory and
+        * we get here for it rather often.
         */
        if (!mft_no) {
                /* Balance the below iput(). */
                vi = igrab(mft_vi);
                BUG_ON(vi != mft_vi);
-       } else
-               vi = ilookup5(sb, mft_no, (test_t)ntfs_test_inode, &na);
+       } else {
+               /*
+                * Have to use ilookup5_nowait() since ilookup5() waits for the
+                * inode lock which causes ntfs to deadlock when a concurrent
+                * inode write via the inode dirty code paths and the page
+                * dirty code path of the inode dirty code path when writing
+                * $MFT occurs.
+                */
+               vi = ilookup5_nowait(sb, mft_no, (test_t)ntfs_test_inode, &na);
+       }
        if (vi) {
                ntfs_debug("Base inode 0x%lx is in icache.", mft_no);
                /* The inode is in icache. */
@@ -1016,7 +1019,13 @@ BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no,
        na.mft_no = MREF_LE(m->base_mft_record);
        ntfs_debug("Mft record 0x%lx is an extent record.  Looking for base "
                        "inode 0x%lx in icache.", mft_no, na.mft_no);
-       vi = ilookup5(sb, na.mft_no, (test_t)ntfs_test_inode, &na);
+       if (!na.mft_no) {
+               /* Balance the below iput(). */
+               vi = igrab(mft_vi);
+               BUG_ON(vi != mft_vi);
+       } else
+               vi = ilookup5_nowait(sb, na.mft_no, (test_t)ntfs_test_inode,
+                               &na);
        if (!vi) {
                /*
                 * The base inode is not in icache, write this extent mft
@@ -1944,7 +1953,7 @@ restore_undo_alloc:
        a = ctx->attr;
        a->data.non_resident.highest_vcn = cpu_to_sle64(old_last_vcn - 1);
 undo_alloc:
-       if (ntfs_cluster_free(vol->mft_ino, old_last_vcn, -1) < 0) {
+       if (ntfs_cluster_free(mft_ni, old_last_vcn, -1) < 0) {
                ntfs_error(vol->sb, "Failed to free clusters from mft data "
                                "attribute.%s", es);
                NVolSetErrors(vol);