From 921372c289951a2235c95c51aba0642b80d5fa19 Mon Sep 17 00:00:00 2001 From: Anton Altaparmakov Date: Fri, 15 Oct 2004 12:51:22 +0100 Subject: [PATCH] NTFS: 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(). Signed-off-by: Anton Altaparmakov --- fs/ntfs/ChangeLog | 6 ++++++ fs/ntfs/aops.c | 27 +++++++++++++-------------- fs/ntfs/mft.c | 34 +++++++++++++++++++--------------- 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index 52670b89d938d..698b00b0d9d84 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog @@ -122,6 +122,12 @@ ToDo/Notes: 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. diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c index bc1d88dd6e510..751c6d81de7a4 100644 --- a/fs/ntfs/aops.c +++ b/fs/ntfs/aops.c @@ -868,23 +868,24 @@ static int ntfs_write_mst_block(struct writeback_control *wbc, clear_buffer_dirty(bh); 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. */ rec_block += bhs_per_rec; if (!buffer_dirty(bh)) { - /* Clean buffers are not written out. */ + /* Clean records are not written out. */ rec_is_dirty = FALSE; continue; } 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_uptodate(bh)); @@ -973,10 +974,8 @@ static int ntfs_write_mst_block(struct writeback_control *wbc, continue; if (unlikely(test_set_buffer_locked(tbh))) BUG(); - if (unlikely(!test_clear_buffer_dirty(tbh))) { - unlock_buffer(tbh); - continue; - } + /* The buffer dirty state is now irrelevant, just clean it. */ + clear_buffer_dirty(tbh); BUG_ON(!buffer_uptodate(tbh)); BUG_ON(!buffer_mapped(tbh)); get_bh(tbh); diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c index 68cb2678cd504..10c729286a821 100644 --- a/fs/ntfs/mft.c +++ b/fs/ntfs/mft.c @@ -572,8 +572,10 @@ err_out: * ntfs inode @ni to backing store. If the mft record @m has a counterpart in * the mft mirror, that is also updated. * - * We only write the mft record if the ntfs inode @ni is dirty and the buffers - * belonging to its mft record are dirty, too. + * We only write the mft record if the ntfs inode @ni is dirty and the first + * 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 * record dirty and return -errno. The caller should call make_bad_inode() on @@ -632,21 +634,23 @@ int write_mft_record_nolock(ntfs_inode *ni, MFT_RECORD *m, int sync) continue; if (unlikely(block_start >= m_end)) break; - /* - * If the buffer is clean and it is the first buffer of the mft - * record, it was written out by other means already so we are - * done. For safety we make sure all the other buffers are - * 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) + if (block_start == m_start) { + /* This block is the first one in the record. */ + if (!buffer_dirty(bh)) { + /* Clean records are not written out. */ rec_is_dirty = FALSE; - else - BUG_ON(rec_is_dirty); - continue; + 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_uptodate(bh)); BUG_ON(!nr_bhs && (m_start != block_start)); -- 2.53.0