summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Altaparmakov <aia21@cantab.net>2004-07-02 12:18:27 +0100
committerAnton Altaparmakov <aia21@cantab.net>2004-07-02 12:18:27 +0100
commita97689d27e01ad9fa189fbf90fd1762baaf535a7 (patch)
tree3a44e8039c1216c24febf74b397d850fe908124f
parentc4b0642b6f9b55957f9e5f8a8c494dcfd6293826 (diff)
NTFS: Add fs/ntfs/index.c::__ntfs_index_entry_mark_dirty() which sets all
buffers that are inside the ntfs record in the page dirty after which it sets the page dirty. This allows ->writepage to only write the dirty index records rather than having to write all the records in the page. Modify fs/ntfs/index.h::ntfs_index_entry_mark_dirty() to use this rather than __set_page_dirty_nobuffers(). Signed-off-by: Anton Altaparmakov <aia21@cantab.net>
-rw-r--r--fs/ntfs/ChangeLog6
-rw-r--r--fs/ntfs/index.c60
-rw-r--r--fs/ntfs/index.h27
3 files changed, 76 insertions, 17 deletions
diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog
index 30aa30ac9bc6..863b078a4e4a 100644
--- a/fs/ntfs/ChangeLog
+++ b/fs/ntfs/ChangeLog
@@ -83,6 +83,12 @@ ToDo/Notes:
It is simply set to __set_page_dirty_nobuffers() to make sure that
running set_page_dirty() on a page containing mft/ntfs records will
not affect the dirty state of the page buffers.
+ - Add fs/ntfs/index.c::__ntfs_index_entry_mark_dirty() which sets all
+ buffers that are inside the ntfs record in the page dirty after which
+ it sets the page dirty. This allows ->writepage to only write the
+ dirty index records rather than having to write all the records in
+ the page. Modify fs/ntfs/index.h::ntfs_index_entry_mark_dirty() to
+ use this rather than __set_page_dirty_nobuffers().
2.1.14 - Fix an NFSd caused deadlock reported by several users.
diff --git a/fs/ntfs/index.c b/fs/ntfs/index.c
index 06e81aff1a3d..41bfe847ac44 100644
--- a/fs/ntfs/index.c
+++ b/fs/ntfs/index.c
@@ -457,3 +457,63 @@ idx_err_out:
err = -EIO;
goto err_out;
}
+
+#ifdef NTFS_RW
+
+/**
+ * __ntfs_index_entry_mark_dirty - mark an index allocation entry dirty
+ * @ictx: ntfs index context describing the index entry
+ *
+ * NOTE: You want to use fs/ntfs/index.h::ntfs_index_entry_mark_dirty() instead!
+ *
+ * Mark the index allocation entry described by the index entry context @ictx
+ * dirty.
+ *
+ * The index entry must be in an index block belonging to the index allocation
+ * attribute. Mark the buffers belonging to the index record as well as the
+ * page cache page the index block is in dirty. This automatically marks the
+ * VFS inode of the ntfs index inode to which the index entry belongs dirty,
+ * too (I_DIRTY_PAGES) and this in turn ensures the page buffers, and hence the
+ * dirty index block, will be written out to disk later.
+ */
+void __ntfs_index_entry_mark_dirty(ntfs_index_context *ictx)
+{
+ struct address_space *mapping;
+ struct page *page;
+ ntfs_inode *ni;
+
+ BUG_ON(ictx->is_in_root);
+ ni = ictx->idx_ni;
+ page = ictx->page;
+ /*
+ * If the index block is the same size as the page cache page, set all
+ * the buffers in the page, as well as the page itself, dirty.
+ */
+ if (ni->itype.index.block_size == PAGE_CACHE_SIZE) {
+ __set_page_dirty_buffers(page);
+ return;
+ }
+ /* Set only the buffers in which the index block is located dirty. */
+ mapping = page->mapping;
+ if (page_has_buffers(page)) {
+ struct buffer_head *bh, *head;
+ unsigned int bh_start, bh_end, rec_start, rec_end;
+ unsigned int bh_size = ni->vol->sb->s_blocksize;
+
+ bh = head = page_buffers(page);
+ bh_start = 0;
+ rec_start = (unsigned int)((u8*)ictx->ia -
+ (u8*)page_address(page));
+ rec_end = rec_start + ni->itype.index.block_size;
+ do {
+ bh_end = bh_start + bh_size;
+ if ((bh_start >= rec_start) && (bh_end <= rec_end))
+ set_buffer_dirty(bh);
+ bh_start = bh_end;
+ } while ((bh = bh->b_this_page) != head);
+ }
+ /* Finally, set the page itself dirty, too. */
+ __set_page_dirty_nobuffers(page);
+}
+
+#endif /* NTFS_RW */
diff --git a/fs/ntfs/index.h b/fs/ntfs/index.h
index e43bedc4519f..8ed943655a1d 100644
--- a/fs/ntfs/index.h
+++ b/fs/ntfs/index.h
@@ -54,8 +54,8 @@
* @page are NULL in this case.
*
* If @is_in_root is FALSE, @entry is in the index allocation attribute and @ia
- * and @page point to the index allocation block and the locked page it is in,
- * respectively. @ir, @actx and @base_ni are NULL in this case.
+ * and @page point to the index allocation block and the mapped, locked page it
+ * is in, respectively. @ir, @actx and @base_ni are NULL in this case.
*
* To obtain a context call ntfs_index_ctx_get().
*
@@ -115,6 +115,8 @@ static inline void ntfs_index_entry_flush_dcache_page(ntfs_index_context *ictx)
flush_dcache_page(ictx->page);
}
+extern void __ntfs_index_entry_mark_dirty(ntfs_index_context *ictx);
+
/**
* ntfs_index_entry_mark_dirty - mark an index entry dirty
* @ictx: ntfs index context describing the index entry
@@ -127,27 +129,18 @@ static inline void ntfs_index_entry_flush_dcache_page(ntfs_index_context *ictx)
* later.
*
* If the index entry is in an index block belonging to the index allocation
- * attribute, simply mark the page cache page the index block is in dirty.
- * This automatically marks the VFS inode of the ntfs index inode to which the
- * index entry belongs dirty, too (I_DIRTY_PAGES) and this in turn ensures the
- * page, and hence the dirty index block, will be written out to disk later.
- *
- * Note, that if an index block is smaller than PAGE_CACHE_SIZE, i.e. if there
- * are multiple index blocks in each page cache page, dirtying an index entry
- * in one index block will cause all index blocks located in the same page
- * cache page to be written out, too but this is a small price to pay
- * considering how much more complicated the code would have to be to keep
- * track of which index block inside a page is dirty and which is not. And
- * anyway, on ia32 architectures index blocks are usually 4kiB in size which is
- * the PAGE_CACHE_SIZE and hence this problem does not exist in the majority of
- * cases.
+ * attribute, mark the buffers belonging to the index record as well as the
+ * page cache page the index block is in dirty. This automatically marks the
+ * VFS inode of the ntfs index inode to which the index entry belongs dirty,
+ * too (I_DIRTY_PAGES) and this in turn ensures the page buffers, and hence the
+ * dirty index block, will be written out to disk later.
*/
static inline void ntfs_index_entry_mark_dirty(ntfs_index_context *ictx)
{
if (ictx->is_in_root)
mark_mft_record_dirty(ictx->actx->ntfs_ino);
else
- __set_page_dirty_nobuffers(ictx->page);
+ __ntfs_index_entry_mark_dirty(ictx);
}
#endif /* NTFS_RW */