Skip to content

Commit

Permalink
Merge branch 'reiserfs/kill-bkl' of git://git.kernel.org/pub/scm/linu…
Browse files Browse the repository at this point in the history
…x/kernel/git/frederic/random-tracing

* 'reiserfs/kill-bkl' of git://git.kernel.org/pub/scm/linux/kernel/git/frederic/random-tracing:
  reiserfs: Safely acquire i_mutex from xattr_rmdir
  reiserfs: Safely acquire i_mutex from reiserfs_for_each_xattr
  reiserfs: Fix journal mutex <-> inode mutex lock inversion
  reiserfs: Fix unwanted recursive reiserfs lock in reiserfs_unlink()
  reiserfs: Relax lock before open xattr dir in reiserfs_xattr_set_handle()
  reiserfs: Relax reiserfs lock while freeing the journal
  reiserfs: Fix reiserfs lock <-> i_mutex dependency inversion on xattr
  reiserfs: Warn on lock relax if taken recursively
  reiserfs: Fix reiserfs lock <-> i_xattr_sem dependency inversion
  reiserfs: Fix remaining in-reclaim-fs <-> reclaim-fs-on locking inversion
  reiserfs: Fix reiserfs lock <-> inode mutex dependency inversion
  reiserfs: Fix reiserfs lock and journal lock inversion dependency
  reiserfs: Fix possible recursive lock
  • Loading branch information
Linus Torvalds committed Jan 2, 2010
2 parents 4207a15 + 835d524 commit 45d28b0
Showing 7 changed files with 79 additions and 15 deletions.
3 changes: 3 additions & 0 deletions fs/reiserfs/bitmap.c
Original file line number Diff line number Diff line change
@@ -1277,7 +1277,10 @@ int reiserfs_init_bitmap_cache(struct super_block *sb)
struct reiserfs_bitmap_info *bitmap;
unsigned int bmap_nr = reiserfs_bmap_count(sb);

/* Avoid lock recursion in fault case */
reiserfs_write_unlock(sb);
bitmap = vmalloc(sizeof(*bitmap) * bmap_nr);
reiserfs_write_lock(sb);
if (bitmap == NULL)
return -ENOMEM;

5 changes: 3 additions & 2 deletions fs/reiserfs/inode.c
Original file line number Diff line number Diff line change
@@ -31,11 +31,12 @@ void reiserfs_delete_inode(struct inode *inode)
JOURNAL_PER_BALANCE_CNT * 2 +
2 * REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb);
struct reiserfs_transaction_handle th;
int depth;
int err;

truncate_inode_pages(&inode->i_data, 0);

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

/* The = 0 happens when we abort creating a new inode for some reason like lack of space.. */
if (!(inode->i_state & I_NEW) && INODE_PKEY(inode)->k_objectid != 0) { /* also handles bad_inode case */
@@ -74,7 +75,7 @@ void reiserfs_delete_inode(struct inode *inode)
out:
clear_inode(inode); /* note this must go after the journal_end to prevent deadlock */
inode->i_blocks = 0;
reiserfs_write_unlock(inode->i_sb);
reiserfs_write_unlock_once(inode->i_sb, depth);
}

static void _make_cpu_key(struct cpu_key *key, int version, __u32 dirid,
18 changes: 14 additions & 4 deletions fs/reiserfs/journal.c
Original file line number Diff line number Diff line change
@@ -2009,10 +2009,11 @@ static int do_journal_release(struct reiserfs_transaction_handle *th,
destroy_workqueue(commit_wq);
commit_wq = NULL;
}
reiserfs_write_lock(sb);

free_journal_ram(sb);

reiserfs_write_lock(sb);

return 0;
}

@@ -2758,11 +2759,18 @@ int journal_init(struct super_block *sb, const char *j_dev_name,
struct reiserfs_journal *journal;
struct reiserfs_journal_list *jl;
char b[BDEVNAME_SIZE];
int ret;

/*
* Unlock here to avoid various RECLAIM-FS-ON <-> IN-RECLAIM-FS
* dependency inversion warnings.
*/
reiserfs_write_unlock(sb);
journal = SB_JOURNAL(sb) = vmalloc(sizeof(struct reiserfs_journal));
if (!journal) {
reiserfs_warning(sb, "journal-1256",
"unable to get memory for journal structure");
reiserfs_write_lock(sb);
return 1;
}
memset(journal, 0, sizeof(struct reiserfs_journal));
@@ -2771,10 +2779,12 @@ int journal_init(struct super_block *sb, const char *j_dev_name,
INIT_LIST_HEAD(&journal->j_working_list);
INIT_LIST_HEAD(&journal->j_journal_list);
journal->j_persistent_trans = 0;
if (reiserfs_allocate_list_bitmaps(sb,
journal->j_list_bitmap,
reiserfs_bmap_count(sb)))
ret = reiserfs_allocate_list_bitmaps(sb, journal->j_list_bitmap,
reiserfs_bmap_count(sb));
reiserfs_write_lock(sb);
if (ret)
goto free_and_return;

allocate_bitmap_nodes(sb);

/* reserved for journal area support */
9 changes: 9 additions & 0 deletions fs/reiserfs/lock.c
Original file line number Diff line number Diff line change
@@ -86,3 +86,12 @@ void reiserfs_check_lock_depth(struct super_block *sb, char *caller)
reiserfs_panic(sb, "%s called without kernel lock held %d",
caller);
}

#ifdef CONFIG_REISERFS_CHECK
void reiserfs_lock_check_recursive(struct super_block *sb)
{
struct reiserfs_sb_info *sb_i = REISERFS_SB(sb);

WARN_ONCE((sb_i->lock_depth > 0), "Unwanted recursive reiserfs lock!\n");
}
#endif
7 changes: 4 additions & 3 deletions fs/reiserfs/namei.c
Original file line number Diff line number Diff line change
@@ -921,6 +921,7 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry)
struct reiserfs_transaction_handle th;
int jbegin_count;
unsigned long savelink;
int depth;

inode = dentry->d_inode;

@@ -932,7 +933,7 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry)
JOURNAL_PER_BALANCE_CNT * 2 + 2 +
4 * REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb);

reiserfs_write_lock(dir->i_sb);
depth = reiserfs_write_lock_once(dir->i_sb);
retval = journal_begin(&th, dir->i_sb, jbegin_count);
if (retval)
goto out_unlink;
@@ -993,7 +994,7 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry)

retval = journal_end(&th, dir->i_sb, jbegin_count);
reiserfs_check_path(&path);
reiserfs_write_unlock(dir->i_sb);
reiserfs_write_unlock_once(dir->i_sb, depth);
return retval;

end_unlink:
@@ -1003,7 +1004,7 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry)
if (err)
retval = err;
out_unlink:
reiserfs_write_unlock(dir->i_sb);
reiserfs_write_unlock_once(dir->i_sb, depth);
return retval;
}

26 changes: 20 additions & 6 deletions fs/reiserfs/xattr.c
Original file line number Diff line number Diff line change
@@ -83,7 +83,8 @@ static int xattr_unlink(struct inode *dir, struct dentry *dentry)
BUG_ON(!mutex_is_locked(&dir->i_mutex));
vfs_dq_init(dir);

mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD);
reiserfs_mutex_lock_nested_safe(&dentry->d_inode->i_mutex,
I_MUTEX_CHILD, dir->i_sb);
error = dir->i_op->unlink(dir, dentry);
mutex_unlock(&dentry->d_inode->i_mutex);

@@ -98,7 +99,8 @@ static int xattr_rmdir(struct inode *dir, struct dentry *dentry)
BUG_ON(!mutex_is_locked(&dir->i_mutex));
vfs_dq_init(dir);

mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD);
reiserfs_mutex_lock_nested_safe(&dentry->d_inode->i_mutex,
I_MUTEX_CHILD, dir->i_sb);
dentry_unhash(dentry);
error = dir->i_op->rmdir(dir, dentry);
if (!error)
@@ -235,16 +237,22 @@ static int reiserfs_for_each_xattr(struct inode *inode,
if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1)
return 0;

reiserfs_write_unlock(inode->i_sb);
dir = open_xa_dir(inode, XATTR_REPLACE);
if (IS_ERR(dir)) {
err = PTR_ERR(dir);
reiserfs_write_lock(inode->i_sb);
goto out;
} else if (!dir->d_inode) {
err = 0;
reiserfs_write_lock(inode->i_sb);
goto out_dir;
}

mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR);

reiserfs_write_lock(inode->i_sb);

buf.xadir = dir;
err = reiserfs_readdir_dentry(dir, &buf, fill_with_dentries, &pos);
while ((err == 0 || err == -ENOSPC) && buf.count) {
@@ -283,8 +291,9 @@ static int reiserfs_for_each_xattr(struct inode *inode,
err = journal_begin(&th, inode->i_sb, blocks);
if (!err) {
int jerror;
mutex_lock_nested(&dir->d_parent->d_inode->i_mutex,
I_MUTEX_XATTR);
reiserfs_mutex_lock_nested_safe(
&dir->d_parent->d_inode->i_mutex,
I_MUTEX_XATTR, inode->i_sb);
err = action(dir, data);
jerror = journal_end(&th, inode->i_sb, blocks);
mutex_unlock(&dir->d_parent->d_inode->i_mutex);
@@ -480,11 +489,16 @@ reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *th,
if (!buffer)
return lookup_and_delete_xattr(inode, name);

reiserfs_write_unlock(inode->i_sb);
dentry = xattr_lookup(inode, name, flags);
if (IS_ERR(dentry))
if (IS_ERR(dentry)) {
reiserfs_write_lock(inode->i_sb);
return PTR_ERR(dentry);
}

down_write(&REISERFS_I(inode)->i_xattr_sem);
down_read(&REISERFS_I(inode)->i_xattr_sem);

reiserfs_write_lock(inode->i_sb);

xahash = xattr_hash(buffer, buffer_size);
while (buffer_pos < buffer_size || buffer_pos == 0) {
26 changes: 26 additions & 0 deletions include/linux/reiserfs_fs.h
Original file line number Diff line number Diff line change
@@ -62,6 +62,12 @@ void reiserfs_write_unlock(struct super_block *s);
int reiserfs_write_lock_once(struct super_block *s);
void reiserfs_write_unlock_once(struct super_block *s, int lock_depth);

#ifdef CONFIG_REISERFS_CHECK
void reiserfs_lock_check_recursive(struct super_block *s);
#else
static inline void reiserfs_lock_check_recursive(struct super_block *s) { }
#endif

/*
* Several mutexes depend on the write lock.
* However sometimes we want to relax the write lock while we hold
@@ -92,11 +98,31 @@ void reiserfs_write_unlock_once(struct super_block *s, int lock_depth);
static inline void reiserfs_mutex_lock_safe(struct mutex *m,
struct super_block *s)
{
reiserfs_lock_check_recursive(s);
reiserfs_write_unlock(s);
mutex_lock(m);
reiserfs_write_lock(s);
}

static inline void
reiserfs_mutex_lock_nested_safe(struct mutex *m, unsigned int subclass,
struct super_block *s)
{
reiserfs_lock_check_recursive(s);
reiserfs_write_unlock(s);
mutex_lock_nested(m, subclass);
reiserfs_write_lock(s);
}

static inline void
reiserfs_down_read_safe(struct rw_semaphore *sem, struct super_block *s)
{
reiserfs_lock_check_recursive(s);
reiserfs_write_unlock(s);
down_read(sem);
reiserfs_write_lock(s);
}

/*
* When we schedule, we usually want to also release the write lock,
* according to the previous bkl based locking scheme of reiserfs.

0 comments on commit 45d28b0

Please sign in to comment.