Changes since last update:

- Fix an unmount hang due to a race in io buffer accounting.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABCgAGBQJZMKVEAAoJEPh/dxk0SrTrBYcQAKSpzE8C9wDBw6cyxP3kwrTr
 FSQiSr7flnGBHwy2U0UC/SIFIwYxvW4BTnXJWADyqtnvLWP1+TC7UY1oNpkTsbkK
 KLsWgz3aOcT/8sb346PzFDAuxof2lkv3xFPRBFaoeSkybxWqLz6BWsbmaJNH/wqy
 W3k3H241mAftEiv1i9IUlAZMXE31qywIKzzUJvkOglXS8OdVFfMPQvUz6epU2LWA
 I2tBip936Sl45vLu6ubqoRpk8dWNuPPX+f4YXl8dVeqRKTYhviMwgYD4rlljb6Ti
 kIRG9HYg1GVZo5z/5unAjyEaKzYoRrXnO5Lg+i09NIhezlDhB2HJ+k71NljoeHoe
 YCwqumQIGgnxdFu+FP10tKh2EWvDp80SQxgzIvr+FCCKJdsdNYyftRh4CtsCPJSG
 xWHT1jgovygHsBEEmG2LS9mCXKkyWgMkHNMBu3Yy/F/4HGzrPjcU3F+x90OmOo7J
 S26kEwsAoo+Q5Is8QkmqrnD+CQ7jwXEv9Mw3UqRwQ7UagRdR2nI8CIGEC7W+42Mm
 Gd3TtAyJCbhZWXNq7pLeTnGu7JY3/dhR/8VSW+mIKtvFg7v9O1wZBYId8vTwZN1+
 8jgnW0h6myE10YKU5bc1TZeYYAkWA+JLRKxoexL3QD8jWeffyZgMNWPM2rb+4Jjp
 2wwCHMPvHE8X7a2urTW3
 =wRbJ
 -----END PGP SIGNATURE-----

Merge tag 'xfs-4.12-fixes-3' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux

Pull XFS fix from Darrick Wong:
 "I've one more bugfix for you for 4.12-rc4: Fix an unmount hang due to
  a race in io buffer accounting"

* tag 'xfs-4.12-fixes-3' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux:
  xfs: use ->b_state to fix buffer I/O accounting release race
This commit is contained in:
Linus Torvalds 2017-06-02 12:29:03 -07:00
commit e6e6d07436
2 changed files with 28 additions and 15 deletions

View File

@ -97,27 +97,41 @@ static inline void
xfs_buf_ioacct_inc( xfs_buf_ioacct_inc(
struct xfs_buf *bp) struct xfs_buf *bp)
{ {
if (bp->b_flags & (XBF_NO_IOACCT|_XBF_IN_FLIGHT)) if (bp->b_flags & XBF_NO_IOACCT)
return; return;
ASSERT(bp->b_flags & XBF_ASYNC); ASSERT(bp->b_flags & XBF_ASYNC);
bp->b_flags |= _XBF_IN_FLIGHT; spin_lock(&bp->b_lock);
if (!(bp->b_state & XFS_BSTATE_IN_FLIGHT)) {
bp->b_state |= XFS_BSTATE_IN_FLIGHT;
percpu_counter_inc(&bp->b_target->bt_io_count); percpu_counter_inc(&bp->b_target->bt_io_count);
}
spin_unlock(&bp->b_lock);
} }
/* /*
* Clear the in-flight state on a buffer about to be released to the LRU or * Clear the in-flight state on a buffer about to be released to the LRU or
* freed and unaccount from the buftarg. * freed and unaccount from the buftarg.
*/ */
static inline void
__xfs_buf_ioacct_dec(
struct xfs_buf *bp)
{
ASSERT(spin_is_locked(&bp->b_lock));
if (bp->b_state & XFS_BSTATE_IN_FLIGHT) {
bp->b_state &= ~XFS_BSTATE_IN_FLIGHT;
percpu_counter_dec(&bp->b_target->bt_io_count);
}
}
static inline void static inline void
xfs_buf_ioacct_dec( xfs_buf_ioacct_dec(
struct xfs_buf *bp) struct xfs_buf *bp)
{ {
if (!(bp->b_flags & _XBF_IN_FLIGHT)) spin_lock(&bp->b_lock);
return; __xfs_buf_ioacct_dec(bp);
spin_unlock(&bp->b_lock);
bp->b_flags &= ~_XBF_IN_FLIGHT;
percpu_counter_dec(&bp->b_target->bt_io_count);
} }
/* /*
@ -149,9 +163,9 @@ xfs_buf_stale(
* unaccounted (released to LRU) before that occurs. Drop in-flight * unaccounted (released to LRU) before that occurs. Drop in-flight
* status now to preserve accounting consistency. * status now to preserve accounting consistency.
*/ */
xfs_buf_ioacct_dec(bp);
spin_lock(&bp->b_lock); spin_lock(&bp->b_lock);
__xfs_buf_ioacct_dec(bp);
atomic_set(&bp->b_lru_ref, 0); atomic_set(&bp->b_lru_ref, 0);
if (!(bp->b_state & XFS_BSTATE_DISPOSE) && if (!(bp->b_state & XFS_BSTATE_DISPOSE) &&
(list_lru_del(&bp->b_target->bt_lru, &bp->b_lru))) (list_lru_del(&bp->b_target->bt_lru, &bp->b_lru)))
@ -979,12 +993,12 @@ xfs_buf_rele(
* ensures the decrement occurs only once per-buf. * ensures the decrement occurs only once per-buf.
*/ */
if ((atomic_read(&bp->b_hold) == 1) && !list_empty(&bp->b_lru)) if ((atomic_read(&bp->b_hold) == 1) && !list_empty(&bp->b_lru))
xfs_buf_ioacct_dec(bp); __xfs_buf_ioacct_dec(bp);
goto out_unlock; goto out_unlock;
} }
/* the last reference has been dropped ... */ /* the last reference has been dropped ... */
xfs_buf_ioacct_dec(bp); __xfs_buf_ioacct_dec(bp);
if (!(bp->b_flags & XBF_STALE) && atomic_read(&bp->b_lru_ref)) { if (!(bp->b_flags & XBF_STALE) && atomic_read(&bp->b_lru_ref)) {
/* /*
* If the buffer is added to the LRU take a new reference to the * If the buffer is added to the LRU take a new reference to the

View File

@ -63,7 +63,6 @@ typedef enum {
#define _XBF_KMEM (1 << 21)/* backed by heap memory */ #define _XBF_KMEM (1 << 21)/* backed by heap memory */
#define _XBF_DELWRI_Q (1 << 22)/* buffer on a delwri queue */ #define _XBF_DELWRI_Q (1 << 22)/* buffer on a delwri queue */
#define _XBF_COMPOUND (1 << 23)/* compound buffer */ #define _XBF_COMPOUND (1 << 23)/* compound buffer */
#define _XBF_IN_FLIGHT (1 << 25) /* I/O in flight, for accounting purposes */
typedef unsigned int xfs_buf_flags_t; typedef unsigned int xfs_buf_flags_t;
@ -84,14 +83,14 @@ typedef unsigned int xfs_buf_flags_t;
{ _XBF_PAGES, "PAGES" }, \ { _XBF_PAGES, "PAGES" }, \
{ _XBF_KMEM, "KMEM" }, \ { _XBF_KMEM, "KMEM" }, \
{ _XBF_DELWRI_Q, "DELWRI_Q" }, \ { _XBF_DELWRI_Q, "DELWRI_Q" }, \
{ _XBF_COMPOUND, "COMPOUND" }, \ { _XBF_COMPOUND, "COMPOUND" }
{ _XBF_IN_FLIGHT, "IN_FLIGHT" }
/* /*
* Internal state flags. * Internal state flags.
*/ */
#define XFS_BSTATE_DISPOSE (1 << 0) /* buffer being discarded */ #define XFS_BSTATE_DISPOSE (1 << 0) /* buffer being discarded */
#define XFS_BSTATE_IN_FLIGHT (1 << 1) /* I/O in flight */
/* /*
* The xfs_buftarg contains 2 notions of "sector size" - * The xfs_buftarg contains 2 notions of "sector size" -