Skip to content
This repository has been archived by the owner on Feb 26, 2020. It is now read-only.

Commit

Permalink
mutex: force serialization on mutex_exit() to fix races
Browse files Browse the repository at this point in the history
It is known that mutex in Linux is not safe when using it to synchronize
the freeing of object in which the mutex is embedded:
http://lwn.net/Articles/575477/

The known places in ZFS which are suspected to suffer from the race condition
are zio->io_lock and dbuf->db_mtx:
  zio uses zio->io_lock and zio->io_cv to synchronize freeing between zio_wait()
  and zio_done().
  dbuf uses dbuf->db_mtx to protect reference counting.

Add it's been reported multiple time that zio->io_lock and dbuf->db_mtx suffer
from corruption, which is exactly the symptom of the race.
openzfs/zfs#2523
openzfs/zfs#2897

This patch fix this kind of race by forcing serializaion on mutex_exit() with
a spinlock, making the mutex safer by sacrificing a bit of performance and
memory overhead.

Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
  • Loading branch information
tuxoko committed Dec 18, 2014
1 parent 52479ec commit 122bf3d
Showing 1 changed file with 12 additions and 1 deletion.
13 changes: 12 additions & 1 deletion include/sys/mutex.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ typedef enum {
*/
typedef struct {
struct mutex m;
spinlock_t m_lock;
} kmutex_t;

static inline kthread_t *
Expand All @@ -70,6 +71,7 @@ mutex_owner(kmutex_t *mp)
ASSERT(type == MUTEX_DEFAULT); \
\
__mutex_init(&(mp)->m, #mp, &__key); \
spin_lock_init(&(mp)->m_lock); \
})

#undef mutex_destroy
Expand All @@ -84,12 +86,18 @@ mutex_owner(kmutex_t *mp)
ASSERT3P(mutex_owner(mp), !=, current); \
mutex_lock(&(mp)->m); \
})
#define mutex_exit(mp) mutex_unlock(&(mp)->m)
#define mutex_exit(mp) \
({ \
spin_lock(&(mp)->m_lock); \
mutex_unlock(&(mp)->m); \
spin_unlock(&(mp)->m_lock); \
})

#else /* HAVE_MUTEX_OWNER */

typedef struct {
struct mutex m_mutex;
spinlock_t m_lock;
kthread_t *m_owner;
} kmutex_t;

Expand Down Expand Up @@ -125,6 +133,7 @@ spl_mutex_clear_owner(kmutex_t *mp)
ASSERT(type == MUTEX_DEFAULT); \
\
__mutex_init(MUTEX(mp), #mp, &__key); \
spin_lock_init(&(mp)->m_lock); \
spl_mutex_clear_owner(mp); \
})

Expand Down Expand Up @@ -153,8 +162,10 @@ spl_mutex_clear_owner(kmutex_t *mp)

#define mutex_exit(mp) \
({ \
spin_lock(&(mp)->m_lock); \
spl_mutex_clear_owner(mp); \
mutex_unlock(MUTEX(mp)); \
spin_unlock(&(mp)->m_lock); \
})

#endif /* HAVE_MUTEX_OWNER */
Expand Down

0 comments on commit 122bf3d

Please sign in to comment.