mirror of
https://github.com/torvalds/linux.git
synced 2024-09-26 18:03:17 +00:00
kill-the-bkl/reiserfs: acquire the inode mutex safely
While searching a pathname, an inode mutex can be acquired in do_lookup() which calls reiserfs_lookup() which in turn acquires the write lock. On the other side reiserfs_fill_super() can acquire the write_lock and then call reiserfs_lookup_privroot() which can acquire an inode mutex (the root of the mount point). So we theoretically risk an AB - BA lock inversion that could lead to a deadlock. As for other lock dependencies found since the bkl to mutex conversion, the fix is to use reiserfs_mutex_lock_safe() which drops the lock dependency to the write lock. [ Impact: fix a possible deadlock with reiserfs ] Cc: Jeff Mahoney <jeffm@suse.com> Cc: Chris Mason <chris.mason@oracle.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Alexander Beregalov <a.beregalov@gmail.com> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
This commit is contained in:
parent
2ac626955e
commit
c72e05756b
|
@ -537,40 +537,6 @@ static inline void insert_journal_hash(struct reiserfs_journal_cnode **table,
|
||||||
journal_hash(table, cn->sb, cn->blocknr) = cn;
|
journal_hash(table, cn->sb, cn->blocknr) = cn;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Several mutexes depend on the write lock.
|
|
||||||
* However sometimes we want to relax the write lock while we hold
|
|
||||||
* these mutexes, according to the release/reacquire on schedule()
|
|
||||||
* properties of the Bkl that were used.
|
|
||||||
* Reiserfs performances and locking were based on this scheme.
|
|
||||||
* Now that the write lock is a mutex and not the bkl anymore, doing so
|
|
||||||
* may result in a deadlock:
|
|
||||||
*
|
|
||||||
* A acquire write_lock
|
|
||||||
* A acquire j_commit_mutex
|
|
||||||
* A release write_lock and wait for something
|
|
||||||
* B acquire write_lock
|
|
||||||
* B can't acquire j_commit_mutex and sleep
|
|
||||||
* A can't acquire write lock anymore
|
|
||||||
* deadlock
|
|
||||||
*
|
|
||||||
* What we do here is avoiding such deadlock by playing the same game
|
|
||||||
* than the Bkl: if we can't acquire a mutex that depends on the write lock,
|
|
||||||
* we release the write lock, wait a bit and then retry.
|
|
||||||
*
|
|
||||||
* The mutexes concerned by this hack are:
|
|
||||||
* - The commit mutex of a journal list
|
|
||||||
* - The flush mutex
|
|
||||||
* - The journal lock
|
|
||||||
*/
|
|
||||||
static inline void reiserfs_mutex_lock_safe(struct mutex *m,
|
|
||||||
struct super_block *s)
|
|
||||||
{
|
|
||||||
reiserfs_write_unlock(s);
|
|
||||||
mutex_lock(m);
|
|
||||||
reiserfs_write_lock(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* lock the current transaction */
|
/* lock the current transaction */
|
||||||
static inline void lock_journal(struct super_block *sb)
|
static inline void lock_journal(struct super_block *sb)
|
||||||
{
|
{
|
||||||
|
|
|
@ -975,7 +975,7 @@ int reiserfs_lookup_privroot(struct super_block *s)
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
/* If we don't have the privroot located yet - go find it */
|
/* If we don't have the privroot located yet - go find it */
|
||||||
mutex_lock(&s->s_root->d_inode->i_mutex);
|
reiserfs_mutex_lock_safe(&s->s_root->d_inode->i_mutex, s);
|
||||||
dentry = lookup_one_len(PRIVROOT_NAME, s->s_root,
|
dentry = lookup_one_len(PRIVROOT_NAME, s->s_root,
|
||||||
strlen(PRIVROOT_NAME));
|
strlen(PRIVROOT_NAME));
|
||||||
if (!IS_ERR(dentry)) {
|
if (!IS_ERR(dentry)) {
|
||||||
|
@ -1011,7 +1011,7 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags)
|
||||||
|
|
||||||
if (privroot->d_inode) {
|
if (privroot->d_inode) {
|
||||||
s->s_xattr = reiserfs_xattr_handlers;
|
s->s_xattr = reiserfs_xattr_handlers;
|
||||||
mutex_lock(&privroot->d_inode->i_mutex);
|
reiserfs_mutex_lock_safe(&privroot->d_inode->i_mutex, s);
|
||||||
if (!REISERFS_SB(s)->xattr_root) {
|
if (!REISERFS_SB(s)->xattr_root) {
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
dentry = lookup_one_len(XAROOT_NAME, privroot,
|
dentry = lookup_one_len(XAROOT_NAME, privroot,
|
||||||
|
|
|
@ -62,6 +62,41 @@ 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);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Several mutexes depend on the write lock.
|
||||||
|
* However sometimes we want to relax the write lock while we hold
|
||||||
|
* these mutexes, according to the release/reacquire on schedule()
|
||||||
|
* properties of the Bkl that were used.
|
||||||
|
* Reiserfs performances and locking were based on this scheme.
|
||||||
|
* Now that the write lock is a mutex and not the bkl anymore, doing so
|
||||||
|
* may result in a deadlock:
|
||||||
|
*
|
||||||
|
* A acquire write_lock
|
||||||
|
* A acquire j_commit_mutex
|
||||||
|
* A release write_lock and wait for something
|
||||||
|
* B acquire write_lock
|
||||||
|
* B can't acquire j_commit_mutex and sleep
|
||||||
|
* A can't acquire write lock anymore
|
||||||
|
* deadlock
|
||||||
|
*
|
||||||
|
* What we do here is avoiding such deadlock by playing the same game
|
||||||
|
* than the Bkl: if we can't acquire a mutex that depends on the write lock,
|
||||||
|
* we release the write lock, wait a bit and then retry.
|
||||||
|
*
|
||||||
|
* The mutexes concerned by this hack are:
|
||||||
|
* - The commit mutex of a journal list
|
||||||
|
* - The flush mutex
|
||||||
|
* - The journal lock
|
||||||
|
* - The inode mutex
|
||||||
|
*/
|
||||||
|
static inline void reiserfs_mutex_lock_safe(struct mutex *m,
|
||||||
|
struct super_block *s)
|
||||||
|
{
|
||||||
|
reiserfs_write_unlock(s);
|
||||||
|
mutex_lock(m);
|
||||||
|
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
Block a user