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:
commit
45d28b0972
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in New Issue