Merge branch 'reiserfs/kill-bkl' of git://git.kernel.org/pub/scm/linux/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
This commit is contained in:
Linus Torvalds 2010-01-02 11:17:05 -08:00
commit 45d28b0972
7 changed files with 79 additions and 15 deletions

View File

@ -1277,7 +1277,10 @@ int reiserfs_init_bitmap_cache(struct super_block *sb)
struct reiserfs_bitmap_info *bitmap; struct reiserfs_bitmap_info *bitmap;
unsigned int bmap_nr = reiserfs_bmap_count(sb); unsigned int bmap_nr = reiserfs_bmap_count(sb);
/* Avoid lock recursion in fault case */
reiserfs_write_unlock(sb);
bitmap = vmalloc(sizeof(*bitmap) * bmap_nr); bitmap = vmalloc(sizeof(*bitmap) * bmap_nr);
reiserfs_write_lock(sb);
if (bitmap == NULL) if (bitmap == NULL)
return -ENOMEM; return -ENOMEM;

View File

@ -31,11 +31,12 @@ void reiserfs_delete_inode(struct inode *inode)
JOURNAL_PER_BALANCE_CNT * 2 + JOURNAL_PER_BALANCE_CNT * 2 +
2 * REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb); 2 * REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb);
struct reiserfs_transaction_handle th; struct reiserfs_transaction_handle th;
int depth;
int err; int err;
truncate_inode_pages(&inode->i_data, 0); 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.. */ /* 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 */ 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: out:
clear_inode(inode); /* note this must go after the journal_end to prevent deadlock */ clear_inode(inode); /* note this must go after the journal_end to prevent deadlock */
inode->i_blocks = 0; 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, static void _make_cpu_key(struct cpu_key *key, int version, __u32 dirid,

View File

@ -2009,10 +2009,11 @@ static int do_journal_release(struct reiserfs_transaction_handle *th,
destroy_workqueue(commit_wq); destroy_workqueue(commit_wq);
commit_wq = NULL; commit_wq = NULL;
} }
reiserfs_write_lock(sb);
free_journal_ram(sb); free_journal_ram(sb);
reiserfs_write_lock(sb);
return 0; 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 *journal;
struct reiserfs_journal_list *jl; struct reiserfs_journal_list *jl;
char b[BDEVNAME_SIZE]; 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)); journal = SB_JOURNAL(sb) = vmalloc(sizeof(struct reiserfs_journal));
if (!journal) { if (!journal) {
reiserfs_warning(sb, "journal-1256", reiserfs_warning(sb, "journal-1256",
"unable to get memory for journal structure"); "unable to get memory for journal structure");
reiserfs_write_lock(sb);
return 1; return 1;
} }
memset(journal, 0, sizeof(struct reiserfs_journal)); 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_working_list);
INIT_LIST_HEAD(&journal->j_journal_list); INIT_LIST_HEAD(&journal->j_journal_list);
journal->j_persistent_trans = 0; journal->j_persistent_trans = 0;
if (reiserfs_allocate_list_bitmaps(sb, ret = reiserfs_allocate_list_bitmaps(sb, journal->j_list_bitmap,
journal->j_list_bitmap, reiserfs_bmap_count(sb));
reiserfs_bmap_count(sb))) reiserfs_write_lock(sb);
if (ret)
goto free_and_return; goto free_and_return;
allocate_bitmap_nodes(sb); allocate_bitmap_nodes(sb);
/* reserved for journal area support */ /* reserved for journal area support */

View File

@ -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", reiserfs_panic(sb, "%s called without kernel lock held %d",
caller); 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

View File

@ -921,6 +921,7 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry)
struct reiserfs_transaction_handle th; struct reiserfs_transaction_handle th;
int jbegin_count; int jbegin_count;
unsigned long savelink; unsigned long savelink;
int depth;
inode = dentry->d_inode; inode = dentry->d_inode;
@ -932,7 +933,7 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry)
JOURNAL_PER_BALANCE_CNT * 2 + 2 + JOURNAL_PER_BALANCE_CNT * 2 + 2 +
4 * REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb); 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); retval = journal_begin(&th, dir->i_sb, jbegin_count);
if (retval) if (retval)
goto out_unlink; 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); retval = journal_end(&th, dir->i_sb, jbegin_count);
reiserfs_check_path(&path); reiserfs_check_path(&path);
reiserfs_write_unlock(dir->i_sb); reiserfs_write_unlock_once(dir->i_sb, depth);
return retval; return retval;
end_unlink: end_unlink:
@ -1003,7 +1004,7 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry)
if (err) if (err)
retval = err; retval = err;
out_unlink: out_unlink:
reiserfs_write_unlock(dir->i_sb); reiserfs_write_unlock_once(dir->i_sb, depth);
return retval; return retval;
} }

View File

@ -83,7 +83,8 @@ static int xattr_unlink(struct inode *dir, struct dentry *dentry)
BUG_ON(!mutex_is_locked(&dir->i_mutex)); BUG_ON(!mutex_is_locked(&dir->i_mutex));
vfs_dq_init(dir); 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); error = dir->i_op->unlink(dir, dentry);
mutex_unlock(&dentry->d_inode->i_mutex); 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)); BUG_ON(!mutex_is_locked(&dir->i_mutex));
vfs_dq_init(dir); 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); dentry_unhash(dentry);
error = dir->i_op->rmdir(dir, dentry); error = dir->i_op->rmdir(dir, dentry);
if (!error) 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) if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1)
return 0; return 0;
reiserfs_write_unlock(inode->i_sb);
dir = open_xa_dir(inode, XATTR_REPLACE); dir = open_xa_dir(inode, XATTR_REPLACE);
if (IS_ERR(dir)) { if (IS_ERR(dir)) {
err = PTR_ERR(dir); err = PTR_ERR(dir);
reiserfs_write_lock(inode->i_sb);
goto out; goto out;
} else if (!dir->d_inode) { } else if (!dir->d_inode) {
err = 0; err = 0;
reiserfs_write_lock(inode->i_sb);
goto out_dir; goto out_dir;
} }
mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR); mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR);
reiserfs_write_lock(inode->i_sb);
buf.xadir = dir; buf.xadir = dir;
err = reiserfs_readdir_dentry(dir, &buf, fill_with_dentries, &pos); err = reiserfs_readdir_dentry(dir, &buf, fill_with_dentries, &pos);
while ((err == 0 || err == -ENOSPC) && buf.count) { 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); err = journal_begin(&th, inode->i_sb, blocks);
if (!err) { if (!err) {
int jerror; int jerror;
mutex_lock_nested(&dir->d_parent->d_inode->i_mutex, reiserfs_mutex_lock_nested_safe(
I_MUTEX_XATTR); &dir->d_parent->d_inode->i_mutex,
I_MUTEX_XATTR, inode->i_sb);
err = action(dir, data); err = action(dir, data);
jerror = journal_end(&th, inode->i_sb, blocks); jerror = journal_end(&th, inode->i_sb, blocks);
mutex_unlock(&dir->d_parent->d_inode->i_mutex); mutex_unlock(&dir->d_parent->d_inode->i_mutex);
@ -480,11 +489,16 @@ reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *th,
if (!buffer) if (!buffer)
return lookup_and_delete_xattr(inode, name); return lookup_and_delete_xattr(inode, name);
reiserfs_write_unlock(inode->i_sb);
dentry = xattr_lookup(inode, name, flags); dentry = xattr_lookup(inode, name, flags);
if (IS_ERR(dentry)) if (IS_ERR(dentry)) {
reiserfs_write_lock(inode->i_sb);
return PTR_ERR(dentry); 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); xahash = xattr_hash(buffer, buffer_size);
while (buffer_pos < buffer_size || buffer_pos == 0) { while (buffer_pos < buffer_size || buffer_pos == 0) {

View File

@ -62,6 +62,12 @@ void reiserfs_write_unlock(struct super_block *s);
int reiserfs_write_lock_once(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); 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. * Several mutexes depend on the write lock.
* However sometimes we want to relax the write lock while we hold * 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, static inline void reiserfs_mutex_lock_safe(struct mutex *m,
struct super_block *s) struct super_block *s)
{ {
reiserfs_lock_check_recursive(s);
reiserfs_write_unlock(s); reiserfs_write_unlock(s);
mutex_lock(m); mutex_lock(m);
reiserfs_write_lock(s); 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, * When we schedule, we usually want to also release the write lock,
* according to the previous bkl based locking scheme of reiserfs. * according to the previous bkl based locking scheme of reiserfs.