aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2009-04-13 23:34:25 -0400
committerFrederic Weisbecker <fweisbec@gmail.com>2009-09-14 01:18:04 -0400
commitdc8f6d8936eb244eea452af689df5ee19e635206 (patch)
treec93624678a2d2821c78048f6f7db19889eac5b3a /fs
parent22c963addcf426bef97a43f6e601f985f8082ed5 (diff)
kill-the-BKL/reiserfs: only acquire the write lock once in reiserfs_dirty_inode
Impact: fix a deadlock reiserfs_dirty_inode() is the super_operations::dirty_inode() callback of reiserfs. It can be called from different contexts where the write lock can be already held. But this function also grab the write lock (possibly recursively). Subsequent release of the lock before sleep will actually not release the lock if the caller of mark_inode_dirty() (which in turn calls reiserfs_dirty_inode()) already owns the lock. A typical case: reiserfs_write_end() { acquire_write_lock() mark_inode_dirty() { reiserfs_dirty_inode() { reacquire_write_lock() { journal_begin() { do_journal_begin_r() { /* * fail to release, still * one depth of lock */ release_write_lock() reiserfs_wait_on_write_block() { wait_event() The event is usually provided by something which needs the write lock but it hasn't been released. We use reiserfs_write_lock_once() here to ensure we only grab the write lock in one level. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Alessio Igor Bogani <abogani@texware.it> Cc: Jeff Mahoney <jeffm@suse.com> Cc: Chris Mason <chris.mason@oracle.com> LKML-Reference: <1239680065-25013-4-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'fs')
-rw-r--r--fs/reiserfs/super.c15
1 files changed, 9 insertions, 6 deletions
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index e1cfb80d0bf3..58727b5b4351 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -554,25 +554,28 @@ static void reiserfs_dirty_inode(struct inode *inode)
554 struct reiserfs_transaction_handle th; 554 struct reiserfs_transaction_handle th;
555 555
556 int err = 0; 556 int err = 0;
557 int lock_depth;
558
557 if (inode->i_sb->s_flags & MS_RDONLY) { 559 if (inode->i_sb->s_flags & MS_RDONLY) {
558 reiserfs_warning(inode->i_sb, "clm-6006", 560 reiserfs_warning(inode->i_sb, "clm-6006",
559 "writing inode %lu on readonly FS", 561 "writing inode %lu on readonly FS",
560 inode->i_ino); 562 inode->i_ino);
561 return; 563 return;
562 } 564 }
563 reiserfs_write_lock(inode->i_sb); 565 lock_depth = reiserfs_write_lock_once(inode->i_sb);
564 566
565 /* this is really only used for atime updates, so they don't have 567 /* this is really only used for atime updates, so they don't have
566 ** to be included in O_SYNC or fsync 568 ** to be included in O_SYNC or fsync
567 */ 569 */
568 err = journal_begin(&th, inode->i_sb, 1); 570 err = journal_begin(&th, inode->i_sb, 1);
569 if (err) { 571 if (err)
570 reiserfs_write_unlock(inode->i_sb); 572 goto out;
571 return; 573
572 }
573 reiserfs_update_sd(&th, inode); 574 reiserfs_update_sd(&th, inode);
574 journal_end(&th, inode->i_sb, 1); 575 journal_end(&th, inode->i_sb, 1);
575 reiserfs_write_unlock(inode->i_sb); 576
577out:
578 reiserfs_write_unlock_once(inode->i_sb, lock_depth);
576} 579}
577 580
578#ifdef CONFIG_QUOTA 581#ifdef CONFIG_QUOTA