Commit a97689d2 authored by Anton Altaparmakov's avatar Anton Altaparmakov

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: default avatarAnton Altaparmakov <aia21@cantab.net>
parent c4b0642b
......@@ -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.
......
......@@ -457,3 +457,63 @@ int ntfs_index_lookup(const void *key, const int key_len,
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 */
......@@ -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 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment