Skip to content

Commit

Permalink
kill-the-BKL/reiserfs: lock only once in reiserfs_truncate_file
Browse files Browse the repository at this point in the history
Impact: fix a deadlock

reiserfs_truncate_file() can be called from multiple context where
the write lock can be already hold or not.

This function also acquire (possibly recursively) the write
lock. Subsequent releases before sleeping will not actually release
the lock because we may be in more than one lock depth degree.

A typical case is:

reiserfs_file_release {
	acquire_the_lock()
	reiserfs_truncate_file()
		reacquire_the_lock()
		journal_begin() {
			do_journal_begin_r() {
				reiserfs_wait_on_write_block() {
					/*
					 * Not released because still one
					 * depth owned
					 */
					release_lock()
					wait_for_event()

At this stage the event never happen because the one which provides
it needs the write lock.

We use reiserfs_write_lock_once() here to ensure that we don't acquire the
write lock recursively.

Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Alessio Igor Bogani <abogani@texware.it>
Cc: Jeff Mahoney <jeffm@suse.com>
Cc: Alexander Beregalov <a.beregalov@gmail.com>
Cc: Chris Mason <chris.mason@oracle.com>
LKML-Reference: <1239680065-25013-3-git-send-email-fweisbec@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
  • Loading branch information
Frederic Weisbecker committed Sep 14, 2009
1 parent daf88c8 commit 22c963a
Showing 1 changed file with 7 additions and 3 deletions.
10 changes: 7 additions & 3 deletions fs/reiserfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -2079,8 +2079,9 @@ int reiserfs_truncate_file(struct inode *inode, int update_timestamps)
int error;
struct buffer_head *bh = NULL;
int err2;
int lock_depth;

reiserfs_write_lock(inode->i_sb);
lock_depth = reiserfs_write_lock_once(inode->i_sb);

if (inode->i_size > 0) {
error = grab_tail_page(inode, &page, &bh);
Expand Down Expand Up @@ -2149,14 +2150,17 @@ int reiserfs_truncate_file(struct inode *inode, int update_timestamps)
page_cache_release(page);
}

reiserfs_write_unlock(inode->i_sb);
reiserfs_write_unlock_once(inode->i_sb, lock_depth);

return 0;
out:
if (page) {
unlock_page(page);
page_cache_release(page);
}
reiserfs_write_unlock(inode->i_sb);

reiserfs_write_unlock_once(inode->i_sb, lock_depth);

return error;
}

Expand Down

0 comments on commit 22c963a

Please sign in to comment.