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: ...@@ -83,6 +83,12 @@ ToDo/Notes:
It is simply set to __set_page_dirty_nobuffers() to make sure that 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 running set_page_dirty() on a page containing mft/ntfs records will
not affect the dirty state of the page buffers. 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. 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, ...@@ -457,3 +457,63 @@ int ntfs_index_lookup(const void *key, const int key_len,
err = -EIO; err = -EIO;
goto err_out; 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 @@ ...@@ -54,8 +54,8 @@
* @page are NULL in this case. * @page are NULL in this case.
* *
* If @is_in_root is FALSE, @entry is in the index allocation attribute and @ia * 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, * and @page point to the index allocation block and the mapped, locked page it
* respectively. @ir, @actx and @base_ni are NULL in this case. * is in, respectively. @ir, @actx and @base_ni are NULL in this case.
* *
* To obtain a context call ntfs_index_ctx_get(). * 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) ...@@ -115,6 +115,8 @@ static inline void ntfs_index_entry_flush_dcache_page(ntfs_index_context *ictx)
flush_dcache_page(ictx->page); 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 * ntfs_index_entry_mark_dirty - mark an index entry dirty
* @ictx: ntfs index context describing the index entry * @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) ...@@ -127,27 +129,18 @@ static inline void ntfs_index_entry_flush_dcache_page(ntfs_index_context *ictx)
* later. * later.
* *
* If the index entry is in an index block belonging to the index allocation * 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. * attribute, mark the buffers belonging to the index record as well as the
* This automatically marks the VFS inode of the ntfs index inode to which the * page cache page the index block is in dirty. This automatically marks the
* index entry belongs dirty, too (I_DIRTY_PAGES) and this in turn ensures the * VFS inode of the ntfs index inode to which the index entry belongs dirty,
* page, and hence the dirty index block, will be written out to disk later. * 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.
* 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.
*/ */
static inline void ntfs_index_entry_mark_dirty(ntfs_index_context *ictx) static inline void ntfs_index_entry_mark_dirty(ntfs_index_context *ictx)
{ {
if (ictx->is_in_root) if (ictx->is_in_root)
mark_mft_record_dirty(ictx->actx->ntfs_ino); mark_mft_record_dirty(ictx->actx->ntfs_ino);
else else
__set_page_dirty_nobuffers(ictx->page); __ntfs_index_entry_mark_dirty(ictx);
} }
#endif /* NTFS_RW */ #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