Skip to content

Commit e6e6d07

Browse files
committed
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
2 parents b939c51 + 63db7c8 commit e6e6d07

File tree

2 files changed

+28
-15
lines changed

2 files changed

+28
-15
lines changed

fs/xfs/xfs_buf.c

+26-12
Original file line numberDiff line numberDiff line change
@@ -97,27 +97,41 @@ static inline void
9797
xfs_buf_ioacct_inc(
9898
struct xfs_buf *bp)
9999
{
100-
if (bp->b_flags & (XBF_NO_IOACCT|_XBF_IN_FLIGHT))
100+
if (bp->b_flags & XBF_NO_IOACCT)
101101
return;
102102

103103
ASSERT(bp->b_flags & XBF_ASYNC);
104-
bp->b_flags |= _XBF_IN_FLIGHT;
105-
percpu_counter_inc(&bp->b_target->bt_io_count);
104+
spin_lock(&bp->b_lock);
105+
if (!(bp->b_state & XFS_BSTATE_IN_FLIGHT)) {
106+
bp->b_state |= XFS_BSTATE_IN_FLIGHT;
107+
percpu_counter_inc(&bp->b_target->bt_io_count);
108+
}
109+
spin_unlock(&bp->b_lock);
106110
}
107111

108112
/*
109113
* Clear the in-flight state on a buffer about to be released to the LRU or
110114
* freed and unaccount from the buftarg.
111115
*/
112116
static inline void
113-
xfs_buf_ioacct_dec(
117+
__xfs_buf_ioacct_dec(
114118
struct xfs_buf *bp)
115119
{
116-
if (!(bp->b_flags & _XBF_IN_FLIGHT))
117-
return;
120+
ASSERT(spin_is_locked(&bp->b_lock));
118121

119-
bp->b_flags &= ~_XBF_IN_FLIGHT;
120-
percpu_counter_dec(&bp->b_target->bt_io_count);
122+
if (bp->b_state & XFS_BSTATE_IN_FLIGHT) {
123+
bp->b_state &= ~XFS_BSTATE_IN_FLIGHT;
124+
percpu_counter_dec(&bp->b_target->bt_io_count);
125+
}
126+
}
127+
128+
static inline void
129+
xfs_buf_ioacct_dec(
130+
struct xfs_buf *bp)
131+
{
132+
spin_lock(&bp->b_lock);
133+
__xfs_buf_ioacct_dec(bp);
134+
spin_unlock(&bp->b_lock);
121135
}
122136

123137
/*
@@ -149,9 +163,9 @@ xfs_buf_stale(
149163
* unaccounted (released to LRU) before that occurs. Drop in-flight
150164
* status now to preserve accounting consistency.
151165
*/
152-
xfs_buf_ioacct_dec(bp);
153-
154166
spin_lock(&bp->b_lock);
167+
__xfs_buf_ioacct_dec(bp);
168+
155169
atomic_set(&bp->b_lru_ref, 0);
156170
if (!(bp->b_state & XFS_BSTATE_DISPOSE) &&
157171
(list_lru_del(&bp->b_target->bt_lru, &bp->b_lru)))
@@ -979,12 +993,12 @@ xfs_buf_rele(
979993
* ensures the decrement occurs only once per-buf.
980994
*/
981995
if ((atomic_read(&bp->b_hold) == 1) && !list_empty(&bp->b_lru))
982-
xfs_buf_ioacct_dec(bp);
996+
__xfs_buf_ioacct_dec(bp);
983997
goto out_unlock;
984998
}
985999

9861000
/* the last reference has been dropped ... */
987-
xfs_buf_ioacct_dec(bp);
1001+
__xfs_buf_ioacct_dec(bp);
9881002
if (!(bp->b_flags & XBF_STALE) && atomic_read(&bp->b_lru_ref)) {
9891003
/*
9901004
* If the buffer is added to the LRU take a new reference to the

fs/xfs/xfs_buf.h

+2-3
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ typedef enum {
6363
#define _XBF_KMEM (1 << 21)/* backed by heap memory */
6464
#define _XBF_DELWRI_Q (1 << 22)/* buffer on a delwri queue */
6565
#define _XBF_COMPOUND (1 << 23)/* compound buffer */
66-
#define _XBF_IN_FLIGHT (1 << 25) /* I/O in flight, for accounting purposes */
6766

6867
typedef unsigned int xfs_buf_flags_t;
6968

@@ -84,14 +83,14 @@ typedef unsigned int xfs_buf_flags_t;
8483
{ _XBF_PAGES, "PAGES" }, \
8584
{ _XBF_KMEM, "KMEM" }, \
8685
{ _XBF_DELWRI_Q, "DELWRI_Q" }, \
87-
{ _XBF_COMPOUND, "COMPOUND" }, \
88-
{ _XBF_IN_FLIGHT, "IN_FLIGHT" }
86+
{ _XBF_COMPOUND, "COMPOUND" }
8987

9088

9189
/*
9290
* Internal state flags.
9391
*/
9492
#define XFS_BSTATE_DISPOSE (1 << 0) /* buffer being discarded */
93+
#define XFS_BSTATE_IN_FLIGHT (1 << 1) /* I/O in flight */
9594

9695
/*
9796
* The xfs_buftarg contains 2 notions of "sector size" -

0 commit comments

Comments
 (0)