Commit 89fdbccc authored by Anton Altaparmakov's avatar Anton Altaparmakov

Merge ssh://linux-ntfs@bkbits.net/ntfs-2.6-devel

into cantab.net:/home/src/ntfs-2.6-devel
parents ada8d309 921372c2
...@@ -118,6 +118,16 @@ ToDo/Notes: ...@@ -118,6 +118,16 @@ ToDo/Notes:
inode semaphore around the code thst sets ni->itype.index.bmp_ino to inode semaphore around the code thst sets ni->itype.index.bmp_ino to
NULL and reorganize the code to optimize it a bit. (Thanks to NULL and reorganize the code to optimize it a bit. (Thanks to
Christoph Hellwig for spotting this.) Christoph Hellwig for spotting this.)
- Modify fs/ntfs/aops.c::mark_ntfs_record_dirty() to no longer take the
ntfs inode as a parameter as this is confusing and misleading and the
needed ntfs inode is available via NTFS_I(page->mapping->host).
Adapt all callers to this change.
- Modify fs/ntfs/mft.c::write_mft_record_nolock() and
fs/ntfs/aops.c::ntfs_write_mst_block() to only check the dirty state
of the first buffer in a record and to take this as the ntfs record
dirty state. We cannot look at the dirty state for subsequent
buffers because we might be racing with
fs/ntfs/aops.c::mark_ntfs_record_dirty().
2.1.20 - Fix two stupid bugs introduced in 2.1.18 release. 2.1.20 - Fix two stupid bugs introduced in 2.1.18 release.
......
...@@ -868,23 +868,24 @@ static int ntfs_write_mst_block(struct writeback_control *wbc, ...@@ -868,23 +868,24 @@ static int ntfs_write_mst_block(struct writeback_control *wbc,
clear_buffer_dirty(bh); clear_buffer_dirty(bh);
continue; continue;
} }
if (rec_block == block) { if (likely(block < rec_block)) {
/*
* This block is not the first one in the record. We
* ignore the buffer's dirty state because we could
* have raced with a parallel mark_ntfs_record_dirty().
*/
if (!rec_is_dirty)
continue;
} else /* if (block == rec_block) */ {
BUG_ON(block > rec_block);
/* This block is the first one in the record. */ /* This block is the first one in the record. */
rec_block += bhs_per_rec; rec_block += bhs_per_rec;
if (!buffer_dirty(bh)) { if (!buffer_dirty(bh)) {
/* Clean buffers are not written out. */ /* Clean records are not written out. */
rec_is_dirty = FALSE; rec_is_dirty = FALSE;
continue; continue;
} }
rec_is_dirty = TRUE; rec_is_dirty = TRUE;
} else {
/* This block is not the first one in the record. */
if (!buffer_dirty(bh)) {
/* Clean buffers are not written out. */
BUG_ON(rec_is_dirty);
continue;
}
BUG_ON(!rec_is_dirty);
} }
BUG_ON(!buffer_mapped(bh)); BUG_ON(!buffer_mapped(bh));
BUG_ON(!buffer_uptodate(bh)); BUG_ON(!buffer_uptodate(bh));
...@@ -973,10 +974,8 @@ static int ntfs_write_mst_block(struct writeback_control *wbc, ...@@ -973,10 +974,8 @@ static int ntfs_write_mst_block(struct writeback_control *wbc,
continue; continue;
if (unlikely(test_set_buffer_locked(tbh))) if (unlikely(test_set_buffer_locked(tbh)))
BUG(); BUG();
if (unlikely(!test_clear_buffer_dirty(tbh))) { /* The buffer dirty state is now irrelevant, just clean it. */
unlock_buffer(tbh); clear_buffer_dirty(tbh);
continue;
}
BUG_ON(!buffer_uptodate(tbh)); BUG_ON(!buffer_uptodate(tbh));
BUG_ON(!buffer_mapped(tbh)); BUG_ON(!buffer_mapped(tbh));
get_bh(tbh); get_bh(tbh);
...@@ -2132,9 +2131,8 @@ struct address_space_operations ntfs_mst_aops = { ...@@ -2132,9 +2131,8 @@ struct address_space_operations ntfs_mst_aops = {
/** /**
* mark_ntfs_record_dirty - mark an ntfs record dirty * mark_ntfs_record_dirty - mark an ntfs record dirty
* @ni: ntfs inode containing the ntfs record to be marked dirty
* @page: page containing the ntfs record to mark dirty * @page: page containing the ntfs record to mark dirty
* @rec_start: byte offset within @page at which the ntfs record begins * @ofs: byte offset within @page at which the ntfs record begins
* *
* If the ntfs record is the same size as the page cache page @page, set all * If the ntfs record is the same size as the page cache page @page, set all
* buffers in the page dirty. Otherwise, set only the buffers in which the * buffers in the page dirty. Otherwise, set only the buffers in which the
...@@ -2143,26 +2141,29 @@ struct address_space_operations ntfs_mst_aops = { ...@@ -2143,26 +2141,29 @@ struct address_space_operations ntfs_mst_aops = {
* Also, set the page containing the ntfs record dirty, which also marks the * Also, set the page containing the ntfs record dirty, which also marks the
* vfs inode the ntfs record belongs to dirty (I_DIRTY_PAGES). * vfs inode the ntfs record belongs to dirty (I_DIRTY_PAGES).
*/ */
void mark_ntfs_record_dirty(ntfs_inode *ni, struct page *page, void mark_ntfs_record_dirty(struct page *page, const unsigned int ofs) {
unsigned int rec_start) { ntfs_inode *ni;
struct buffer_head *bh, *head; struct buffer_head *bh, *head;
unsigned int rec_end, bh_size, bh_start, bh_end; unsigned int end, bh_size, bh_ofs;
BUG_ON(!page); BUG_ON(!page);
BUG_ON(!page_has_buffers(page)); BUG_ON(!page_has_buffers(page));
ni = NTFS_I(page->mapping->host);
BUG_ON(!ni);
if (ni->itype.index.block_size == PAGE_CACHE_SIZE) { if (ni->itype.index.block_size == PAGE_CACHE_SIZE) {
__set_page_dirty_buffers(page); __set_page_dirty_buffers(page);
return; return;
} }
rec_end = rec_start + ni->itype.index.block_size; end = ofs + ni->itype.index.block_size;
bh_size = ni->vol->sb->s_blocksize; bh_size = ni->vol->sb->s_blocksize;
bh_start = 0;
bh = head = page_buffers(page); bh = head = page_buffers(page);
do { do {
bh_end = bh_start + bh_size; bh_ofs = bh_offset(bh);
if ((bh_start >= rec_start) && (bh_end <= rec_end)) if (bh_ofs + bh_size <= ofs)
set_buffer_dirty(bh); continue;
bh_start = bh_end; if (unlikely(bh_ofs >= end))
break;
set_buffer_dirty(bh);
} while ((bh = bh->b_this_page) != head); } while ((bh = bh->b_this_page) != head);
__set_page_dirty_nobuffers(page); __set_page_dirty_nobuffers(page);
} }
......
...@@ -95,8 +95,7 @@ static inline struct page *ntfs_map_page(struct address_space *mapping, ...@@ -95,8 +95,7 @@ static inline struct page *ntfs_map_page(struct address_space *mapping,
#ifdef NTFS_RW #ifdef NTFS_RW
extern void mark_ntfs_record_dirty(ntfs_inode *ni, struct page *page, extern void mark_ntfs_record_dirty(struct page *page, const unsigned int ofs);
unsigned int rec_start);
#endif /* NTFS_RW */ #endif /* NTFS_RW */
......
...@@ -139,8 +139,8 @@ static inline void ntfs_index_entry_mark_dirty(ntfs_index_context *ictx) ...@@ -139,8 +139,8 @@ 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
mark_ntfs_record_dirty(ictx->idx_ni, ictx->page, mark_ntfs_record_dirty(ictx->page,
(u8*)ictx->ia - (u8*)page_address(ictx->page)); (u8*)ictx->ia - (u8*)page_address(ictx->page));
} }
#endif /* NTFS_RW */ #endif /* NTFS_RW */
......
...@@ -2513,8 +2513,8 @@ int ntfs_write_inode(struct inode *vi, int sync) ...@@ -2513,8 +2513,8 @@ int ntfs_write_inode(struct inode *vi, int sync)
* this function returns. * this function returns.
*/ */
if (modified && !NInoTestSetDirty(ctx->ntfs_ino)) if (modified && !NInoTestSetDirty(ctx->ntfs_ino))
mark_ntfs_record_dirty(NTFS_I(ni->vol->mft_ino), mark_ntfs_record_dirty(ctx->ntfs_ino->page,
ctx->ntfs_ino->page, ctx->ntfs_ino->page_ofs); ctx->ntfs_ino->page_ofs);
ntfs_attr_put_search_ctx(ctx); ntfs_attr_put_search_ctx(ctx);
/* Now the access times are updated, write the base mft record. */ /* Now the access times are updated, write the base mft record. */
if (NInoDirty(ni)) if (NInoDirty(ni))
......
...@@ -380,8 +380,7 @@ void __mark_mft_record_dirty(ntfs_inode *ni) ...@@ -380,8 +380,7 @@ void __mark_mft_record_dirty(ntfs_inode *ni)
ntfs_debug("Entering for inode 0x%lx.", ni->mft_no); ntfs_debug("Entering for inode 0x%lx.", ni->mft_no);
BUG_ON(NInoAttr(ni)); BUG_ON(NInoAttr(ni));
mark_ntfs_record_dirty(NTFS_I(ni->vol->mft_ino), ni->page, mark_ntfs_record_dirty(ni->page, ni->page_ofs);
ni->page_ofs);
/* Determine the base vfs inode and mark it dirty, too. */ /* Determine the base vfs inode and mark it dirty, too. */
down(&ni->extent_lock); down(&ni->extent_lock);
if (likely(ni->nr_extents >= 0)) if (likely(ni->nr_extents >= 0))
...@@ -573,8 +572,10 @@ int ntfs_sync_mft_mirror(ntfs_volume *vol, const unsigned long mft_no, ...@@ -573,8 +572,10 @@ int ntfs_sync_mft_mirror(ntfs_volume *vol, const unsigned long mft_no,
* ntfs inode @ni to backing store. If the mft record @m has a counterpart in * ntfs inode @ni to backing store. If the mft record @m has a counterpart in
* the mft mirror, that is also updated. * the mft mirror, that is also updated.
* *
* We only write the mft record if the ntfs inode @ni is dirty and the buffers * We only write the mft record if the ntfs inode @ni is dirty and the first
* belonging to its mft record are dirty, too. * buffer belonging to its mft record is dirty, too. We ignore the dirty state
* of subsequent buffers because we could have raced with
* fs/ntfs/aops.c::mark_ntfs_record_dirty().
* *
* On success, clean the mft record and return 0. On error, leave the mft * On success, clean the mft record and return 0. On error, leave the mft
* record dirty and return -errno. The caller should call make_bad_inode() on * record dirty and return -errno. The caller should call make_bad_inode() on
...@@ -633,21 +634,23 @@ int write_mft_record_nolock(ntfs_inode *ni, MFT_RECORD *m, int sync) ...@@ -633,21 +634,23 @@ int write_mft_record_nolock(ntfs_inode *ni, MFT_RECORD *m, int sync)
continue; continue;
if (unlikely(block_start >= m_end)) if (unlikely(block_start >= m_end))
break; break;
/* if (block_start == m_start) {
* If the buffer is clean and it is the first buffer of the mft /* This block is the first one in the record. */
* record, it was written out by other means already so we are if (!buffer_dirty(bh)) {
* done. For safety we make sure all the other buffers are /* Clean records are not written out. */
* clean also. If it is clean but not the first buffer and the
* first buffer was dirty it is a bug.
*/
if (!buffer_dirty(bh)) {
if (block_start == m_start)
rec_is_dirty = FALSE; rec_is_dirty = FALSE;
else continue;
BUG_ON(rec_is_dirty); }
continue; rec_is_dirty = TRUE;
} else {
/*
* This block is not the first one in the record. We
* ignore the buffer's dirty state because we could
* have raced with a parallel mark_ntfs_record_dirty().
*/
if (!rec_is_dirty)
continue;
} }
BUG_ON(!rec_is_dirty);
BUG_ON(!buffer_mapped(bh)); BUG_ON(!buffer_mapped(bh));
BUG_ON(!buffer_uptodate(bh)); BUG_ON(!buffer_uptodate(bh));
BUG_ON(!nr_bhs && (m_start != block_start)); BUG_ON(!nr_bhs && (m_start != block_start));
......
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