From d62b1b87a7d1c3a21dddabed4251763090be3182 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Wed, 1 Feb 2006 03:06:47 -0800 Subject: [PATCH] resierfs: fix reiserfs_invalidatepage race against data=ordered After a transaction has closed but before it has finished commit, there is a window where data=ordered mode requires invalidatepage to pin pages instead of freeing them. This patch fixes a race between the invalidatepage checks and data=ordered writeback, and it also adds a check to the reiserfs write_ordered_buffers routines to write any anonymous buffers that were dirtied after its first writeback loop. That bug works like this: proc1: transaction closes and a new one starts proc1: write_ordered_buffers starts processing data=ordered list proc1: buffer A is cleaned and written proc2: buffer A is dirtied by another process proc2: File is truncated to zero, page A goes through invalidatepage proc2: reiserfs_invalidatepage sees dirty buffer A with reiserfs journal head, pins it proc1: write_ordered_buffers frees the journal head on buffer A At this point, buffer A stays dirty forever Signed-off-by: Chris Mason Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/reiserfs/inode.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'fs/reiserfs/inode.c') diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index ffa34b861bdb..60e2f2344703 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -2743,6 +2743,7 @@ static int invalidatepage_can_drop(struct inode *inode, struct buffer_head *bh) int ret = 1; struct reiserfs_journal *j = SB_JOURNAL(inode->i_sb); + lock_buffer(bh); spin_lock(&j->j_dirty_buffers_lock); if (!buffer_mapped(bh)) { goto free_jh; @@ -2758,7 +2759,7 @@ static int invalidatepage_can_drop(struct inode *inode, struct buffer_head *bh) if (buffer_journaled(bh) || buffer_journal_dirty(bh)) { ret = 0; } - } else if (buffer_dirty(bh) || buffer_locked(bh)) { + } else if (buffer_dirty(bh)) { struct reiserfs_journal_list *jl; struct reiserfs_jh *jh = bh->b_private; @@ -2784,6 +2785,7 @@ static int invalidatepage_can_drop(struct inode *inode, struct buffer_head *bh) reiserfs_free_jh(bh); } spin_unlock(&j->j_dirty_buffers_lock); + unlock_buffer(bh); return ret; } -- cgit v1.2.2 From e0e851cf30f1a9bd2e2a7624e9810378d6a2b072 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Wed, 1 Feb 2006 03:06:49 -0800 Subject: [PATCH] reiserfs: reiserfs hang and performance fix for data=journal mode In data=journal mode, reiserfs writepage needs to make sure not to trigger transactions while being run under PF_MEMALLOC. This patch makes sure to redirty the page instead of forcing a transaction start in this case. Also, calling filemap_fdata* in order to trigger io on the block device can cause lock inversions on the page lock. Instead, do simple batching from flush_commit_list. Signed-off-by: Chris Mason Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/reiserfs/inode.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'fs/reiserfs/inode.c') diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 60e2f2344703..b33d67bba2fd 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -2363,6 +2363,13 @@ static int reiserfs_write_full_page(struct page *page, int bh_per_page = PAGE_CACHE_SIZE / s->s_blocksize; th.t_trans_id = 0; + /* no logging allowed when nonblocking or from PF_MEMALLOC */ + if (checked && (current->flags & PF_MEMALLOC)) { + redirty_page_for_writepage(wbc, page); + unlock_page(page); + return 0; + } + /* The page dirty bit is cleared before writepage is called, which * means we have to tell create_empty_buffers to make dirty buffers * The page really should be up to date at this point, so tossing -- cgit v1.2.2