Commit 42500f5b authored by Stephen Lord's avatar Stephen Lord Committed by Linus Torvalds

[XFS] Transaction A is in callback processing unpinning a buffer,

Transaction B is in the process of marking the buffer stale.
Between transaction A dropping its reference and checking
the stale state, transaction B gets a reference and stales
the buffer. A ends up freeing the log item and releasing
the buffer. End result is we have a reference to free memory
and an unlocked buffer.

SGI Modid: 2.5.x-xfs:slinx:137748a
parent 49a85c6a
...@@ -379,7 +379,8 @@ xfs_buf_item_pin( ...@@ -379,7 +379,8 @@ xfs_buf_item_pin(
*/ */
void void
xfs_buf_item_unpin( xfs_buf_item_unpin(
xfs_buf_log_item_t *bip) xfs_buf_log_item_t *bip,
int stale)
{ {
xfs_mount_t *mp; xfs_mount_t *mp;
xfs_buf_t *bp; xfs_buf_t *bp;
...@@ -396,7 +397,8 @@ xfs_buf_item_unpin( ...@@ -396,7 +397,8 @@ xfs_buf_item_unpin(
freed = atomic_dec_and_test(&bip->bli_refcount); freed = atomic_dec_and_test(&bip->bli_refcount);
mp = bip->bli_item.li_mountp; mp = bip->bli_item.li_mountp;
xfs_bunpin(bp); xfs_bunpin(bp);
if (freed && (bip->bli_flags & XFS_BLI_STALE)) { if (freed && stale) {
ASSERT(bip->bli_flags & XFS_BLI_STALE);
ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
ASSERT(!(XFS_BUF_ISDELAYWRITE(bp))); ASSERT(!(XFS_BUF_ISDELAYWRITE(bp)));
ASSERT(XFS_BUF_ISSTALE(bp)); ASSERT(XFS_BUF_ISSTALE(bp));
...@@ -418,7 +420,6 @@ xfs_buf_item_unpin( ...@@ -418,7 +420,6 @@ xfs_buf_item_unpin(
ASSERT(XFS_BUF_FSPRIVATE(bp, void *) == NULL); ASSERT(XFS_BUF_FSPRIVATE(bp, void *) == NULL);
xfs_buf_relse(bp); xfs_buf_relse(bp);
} }
} }
/* /*
...@@ -435,6 +436,7 @@ xfs_buf_item_unpin_remove( ...@@ -435,6 +436,7 @@ xfs_buf_item_unpin_remove(
{ {
xfs_buf_t *bp; xfs_buf_t *bp;
xfs_log_item_desc_t *lidp; xfs_log_item_desc_t *lidp;
int stale = 0;
bp = bip->bli_buf; bp = bip->bli_buf;
/* /*
...@@ -454,6 +456,7 @@ xfs_buf_item_unpin_remove( ...@@ -454,6 +456,7 @@ xfs_buf_item_unpin_remove(
* will be able to bump up the refcount. * will be able to bump up the refcount.
*/ */
lidp = xfs_trans_find_item(tp, (xfs_log_item_t *) bip); lidp = xfs_trans_find_item(tp, (xfs_log_item_t *) bip);
stale = lidp->lid_flags & XFS_LID_BUF_STALE;
xfs_trans_free_item(tp, lidp); xfs_trans_free_item(tp, lidp);
/* /*
* Since the transaction no longer refers to the buffer, * Since the transaction no longer refers to the buffer,
...@@ -462,7 +465,7 @@ xfs_buf_item_unpin_remove( ...@@ -462,7 +465,7 @@ xfs_buf_item_unpin_remove(
XFS_BUF_SET_FSPRIVATE2(bp, NULL); XFS_BUF_SET_FSPRIVATE2(bp, NULL);
} }
xfs_buf_item_unpin(bip); xfs_buf_item_unpin(bip, stale);
return; return;
} }
...@@ -686,7 +689,7 @@ struct xfs_item_ops xfs_buf_item_ops = { ...@@ -686,7 +689,7 @@ struct xfs_item_ops xfs_buf_item_ops = {
.iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
xfs_buf_item_format, xfs_buf_item_format,
.iop_pin = (void(*)(xfs_log_item_t*))xfs_buf_item_pin, .iop_pin = (void(*)(xfs_log_item_t*))xfs_buf_item_pin,
.iop_unpin = (void(*)(xfs_log_item_t*))xfs_buf_item_unpin, .iop_unpin = (void(*)(xfs_log_item_t*, int))xfs_buf_item_unpin,
.iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t *)) .iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t *))
xfs_buf_item_unpin_remove, xfs_buf_item_unpin_remove,
.iop_trylock = (uint(*)(xfs_log_item_t*))xfs_buf_item_trylock, .iop_trylock = (uint(*)(xfs_log_item_t*))xfs_buf_item_trylock,
......
...@@ -93,9 +93,11 @@ xfs_qm_dquot_logitem_pin( ...@@ -93,9 +93,11 @@ xfs_qm_dquot_logitem_pin(
* anyone in xfs_dqwait_unpin() if the count goes to 0. The * anyone in xfs_dqwait_unpin() if the count goes to 0. The
* dquot must have been previously pinned with a call to xfs_dqpin(). * dquot must have been previously pinned with a call to xfs_dqpin().
*/ */
/* ARGSUSED */
STATIC void STATIC void
xfs_qm_dquot_logitem_unpin( xfs_qm_dquot_logitem_unpin(
xfs_dq_logitem_t *logitem) xfs_dq_logitem_t *logitem,
int stale)
{ {
unsigned long s; unsigned long s;
xfs_dquot_t *dqp; xfs_dquot_t *dqp;
...@@ -116,7 +118,7 @@ xfs_qm_dquot_logitem_unpin_remove( ...@@ -116,7 +118,7 @@ xfs_qm_dquot_logitem_unpin_remove(
xfs_dq_logitem_t *logitem, xfs_dq_logitem_t *logitem,
xfs_trans_t *tp) xfs_trans_t *tp)
{ {
xfs_qm_dquot_logitem_unpin(logitem); xfs_qm_dquot_logitem_unpin(logitem, 0);
} }
/* /*
...@@ -396,7 +398,8 @@ struct xfs_item_ops xfs_dquot_item_ops = { ...@@ -396,7 +398,8 @@ struct xfs_item_ops xfs_dquot_item_ops = {
.iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
xfs_qm_dquot_logitem_format, xfs_qm_dquot_logitem_format,
.iop_pin = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_pin, .iop_pin = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_pin,
.iop_unpin = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_unpin, .iop_unpin = (void(*)(xfs_log_item_t*, int))
xfs_qm_dquot_logitem_unpin,
.iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t*)) .iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t*))
xfs_qm_dquot_logitem_unpin_remove, xfs_qm_dquot_logitem_unpin_remove,
.iop_trylock = (uint(*)(xfs_log_item_t*)) .iop_trylock = (uint(*)(xfs_log_item_t*))
...@@ -492,7 +495,7 @@ xfs_qm_qoff_logitem_pin(xfs_qoff_logitem_t *qf) ...@@ -492,7 +495,7 @@ xfs_qm_qoff_logitem_pin(xfs_qoff_logitem_t *qf)
*/ */
/*ARGSUSED*/ /*ARGSUSED*/
STATIC void STATIC void
xfs_qm_qoff_logitem_unpin(xfs_qoff_logitem_t *qf) xfs_qm_qoff_logitem_unpin(xfs_qoff_logitem_t *qf, int stale)
{ {
return; return;
} }
...@@ -613,7 +616,8 @@ struct xfs_item_ops xfs_qm_qoffend_logitem_ops = { ...@@ -613,7 +616,8 @@ struct xfs_item_ops xfs_qm_qoffend_logitem_ops = {
.iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
xfs_qm_qoff_logitem_format, xfs_qm_qoff_logitem_format,
.iop_pin = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_pin, .iop_pin = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_pin,
.iop_unpin = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unpin, .iop_unpin = (void(*)(xfs_log_item_t* ,int))
xfs_qm_qoff_logitem_unpin,
.iop_unpin_remove = (void(*)(xfs_log_item_t*,xfs_trans_t*)) .iop_unpin_remove = (void(*)(xfs_log_item_t*,xfs_trans_t*))
xfs_qm_qoff_logitem_unpin_remove, xfs_qm_qoff_logitem_unpin_remove,
.iop_trylock = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_trylock, .iop_trylock = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_trylock,
...@@ -635,7 +639,8 @@ struct xfs_item_ops xfs_qm_qoff_logitem_ops = { ...@@ -635,7 +639,8 @@ struct xfs_item_ops xfs_qm_qoff_logitem_ops = {
.iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
xfs_qm_qoff_logitem_format, xfs_qm_qoff_logitem_format,
.iop_pin = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_pin, .iop_pin = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_pin,
.iop_unpin = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unpin, .iop_unpin = (void(*)(xfs_log_item_t*, int))
xfs_qm_qoff_logitem_unpin,
.iop_unpin_remove = (void(*)(xfs_log_item_t*,xfs_trans_t*)) .iop_unpin_remove = (void(*)(xfs_log_item_t*,xfs_trans_t*))
xfs_qm_qoff_logitem_unpin_remove, xfs_qm_qoff_logitem_unpin_remove,
.iop_trylock = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_trylock, .iop_trylock = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_trylock,
......
...@@ -105,7 +105,7 @@ xfs_efi_item_pin(xfs_efi_log_item_t *efip) ...@@ -105,7 +105,7 @@ xfs_efi_item_pin(xfs_efi_log_item_t *efip)
*/ */
/*ARGSUSED*/ /*ARGSUSED*/
STATIC void STATIC void
xfs_efi_item_unpin(xfs_efi_log_item_t *efip) xfs_efi_item_unpin(xfs_efi_log_item_t *efip, int stale)
{ {
int nexts; int nexts;
int size; int size;
...@@ -280,7 +280,7 @@ struct xfs_item_ops xfs_efi_item_ops = { ...@@ -280,7 +280,7 @@ struct xfs_item_ops xfs_efi_item_ops = {
.iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
xfs_efi_item_format, xfs_efi_item_format,
.iop_pin = (void(*)(xfs_log_item_t*))xfs_efi_item_pin, .iop_pin = (void(*)(xfs_log_item_t*))xfs_efi_item_pin,
.iop_unpin = (void(*)(xfs_log_item_t*))xfs_efi_item_unpin, .iop_unpin = (void(*)(xfs_log_item_t*, int))xfs_efi_item_unpin,
.iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t *)) .iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t *))
xfs_efi_item_unpin_remove, xfs_efi_item_unpin_remove,
.iop_trylock = (uint(*)(xfs_log_item_t*))xfs_efi_item_trylock, .iop_trylock = (uint(*)(xfs_log_item_t*))xfs_efi_item_trylock,
...@@ -474,7 +474,7 @@ xfs_efd_item_pin(xfs_efd_log_item_t *efdp) ...@@ -474,7 +474,7 @@ xfs_efd_item_pin(xfs_efd_log_item_t *efdp)
*/ */
/*ARGSUSED*/ /*ARGSUSED*/
STATIC void STATIC void
xfs_efd_item_unpin(xfs_efd_log_item_t *efdp) xfs_efd_item_unpin(xfs_efd_log_item_t *efdp, int stale)
{ {
return; return;
} }
...@@ -607,7 +607,7 @@ struct xfs_item_ops xfs_efd_item_ops = { ...@@ -607,7 +607,7 @@ struct xfs_item_ops xfs_efd_item_ops = {
.iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
xfs_efd_item_format, xfs_efd_item_format,
.iop_pin = (void(*)(xfs_log_item_t*))xfs_efd_item_pin, .iop_pin = (void(*)(xfs_log_item_t*))xfs_efd_item_pin,
.iop_unpin = (void(*)(xfs_log_item_t*))xfs_efd_item_unpin, .iop_unpin = (void(*)(xfs_log_item_t*, int))xfs_efd_item_unpin,
.iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t*)) .iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t*))
xfs_efd_item_unpin_remove, xfs_efd_item_unpin_remove,
.iop_trylock = (uint(*)(xfs_log_item_t*))xfs_efd_item_trylock, .iop_trylock = (uint(*)(xfs_log_item_t*))xfs_efd_item_trylock,
......
...@@ -534,9 +534,11 @@ xfs_inode_item_pin( ...@@ -534,9 +534,11 @@ xfs_inode_item_pin(
* item which was previously pinned with a call to xfs_inode_item_pin(). * item which was previously pinned with a call to xfs_inode_item_pin().
* Just call xfs_iunpin() on the inode to do this. * Just call xfs_iunpin() on the inode to do this.
*/ */
/* ARGSUSED */
STATIC void STATIC void
xfs_inode_item_unpin( xfs_inode_item_unpin(
xfs_inode_log_item_t *iip) xfs_inode_log_item_t *iip,
int stale)
{ {
xfs_iunpin(iip->ili_inode); xfs_iunpin(iip->ili_inode);
} }
...@@ -880,7 +882,7 @@ struct xfs_item_ops xfs_inode_item_ops = { ...@@ -880,7 +882,7 @@ struct xfs_item_ops xfs_inode_item_ops = {
.iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
xfs_inode_item_format, xfs_inode_item_format,
.iop_pin = (void(*)(xfs_log_item_t*))xfs_inode_item_pin, .iop_pin = (void(*)(xfs_log_item_t*))xfs_inode_item_pin,
.iop_unpin = (void(*)(xfs_log_item_t*))xfs_inode_item_unpin, .iop_unpin = (void(*)(xfs_log_item_t*, int))xfs_inode_item_unpin,
.iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t*)) .iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t*))
xfs_inode_item_unpin_remove, xfs_inode_item_unpin_remove,
.iop_trylock = (uint(*)(xfs_log_item_t*))xfs_inode_item_trylock, .iop_trylock = (uint(*)(xfs_log_item_t*))xfs_inode_item_trylock,
......
...@@ -1262,8 +1262,11 @@ xfs_trans_chunk_committed( ...@@ -1262,8 +1262,11 @@ xfs_trans_chunk_committed(
/* /*
* Now that we've repositioned the item in the AIL, * Now that we've repositioned the item in the AIL,
* unpin it so it can be flushed. * unpin it so it can be flushed. Pass information
* about buffer stale state down from the log item
* flags, if anyone else stales the buffer we do not
* want to pay any attention to it.
*/ */
IOP_UNPIN(lip); IOP_UNPIN(lip, lidp->lid_flags & XFS_LID_BUF_STALE);
} }
} }
...@@ -170,7 +170,7 @@ typedef struct xfs_item_ops { ...@@ -170,7 +170,7 @@ typedef struct xfs_item_ops {
uint (*iop_size)(xfs_log_item_t *); uint (*iop_size)(xfs_log_item_t *);
void (*iop_format)(xfs_log_item_t *, struct xfs_log_iovec *); void (*iop_format)(xfs_log_item_t *, struct xfs_log_iovec *);
void (*iop_pin)(xfs_log_item_t *); void (*iop_pin)(xfs_log_item_t *);
void (*iop_unpin)(xfs_log_item_t *); void (*iop_unpin)(xfs_log_item_t *, int);
void (*iop_unpin_remove)(xfs_log_item_t *, struct xfs_trans *); void (*iop_unpin_remove)(xfs_log_item_t *, struct xfs_trans *);
uint (*iop_trylock)(xfs_log_item_t *); uint (*iop_trylock)(xfs_log_item_t *);
void (*iop_unlock)(xfs_log_item_t *); void (*iop_unlock)(xfs_log_item_t *);
...@@ -184,7 +184,7 @@ typedef struct xfs_item_ops { ...@@ -184,7 +184,7 @@ typedef struct xfs_item_ops {
#define IOP_SIZE(ip) (*(ip)->li_ops->iop_size)(ip) #define IOP_SIZE(ip) (*(ip)->li_ops->iop_size)(ip)
#define IOP_FORMAT(ip,vp) (*(ip)->li_ops->iop_format)(ip, vp) #define IOP_FORMAT(ip,vp) (*(ip)->li_ops->iop_format)(ip, vp)
#define IOP_PIN(ip) (*(ip)->li_ops->iop_pin)(ip) #define IOP_PIN(ip) (*(ip)->li_ops->iop_pin)(ip)
#define IOP_UNPIN(ip) (*(ip)->li_ops->iop_unpin)(ip) #define IOP_UNPIN(ip, flags) (*(ip)->li_ops->iop_unpin)(ip, flags)
#define IOP_UNPIN_REMOVE(ip,tp) (*(ip)->li_ops->iop_unpin_remove)(ip, tp) #define IOP_UNPIN_REMOVE(ip,tp) (*(ip)->li_ops->iop_unpin_remove)(ip, tp)
#define IOP_TRYLOCK(ip) (*(ip)->li_ops->iop_trylock)(ip) #define IOP_TRYLOCK(ip) (*(ip)->li_ops->iop_trylock)(ip)
#define IOP_UNLOCK(ip) (*(ip)->li_ops->iop_unlock)(ip) #define IOP_UNLOCK(ip) (*(ip)->li_ops->iop_unlock)(ip)
...@@ -222,6 +222,7 @@ typedef struct xfs_log_item_desc { ...@@ -222,6 +222,7 @@ typedef struct xfs_log_item_desc {
#define XFS_LID_DIRTY 0x1 #define XFS_LID_DIRTY 0x1
#define XFS_LID_PINNED 0x2 #define XFS_LID_PINNED 0x2
#define XFS_LID_SYNC_UNLOCK 0x4 #define XFS_LID_SYNC_UNLOCK 0x4
#define XFS_LID_BUF_STALE 0x8
/* /*
* This structure is used to maintain a chunk list of log_item_desc * This structure is used to maintain a chunk list of log_item_desc
......
...@@ -796,6 +796,7 @@ xfs_trans_log_buf(xfs_trans_t *tp, ...@@ -796,6 +796,7 @@ xfs_trans_log_buf(xfs_trans_t *tp,
tp->t_flags |= XFS_TRANS_DIRTY; tp->t_flags |= XFS_TRANS_DIRTY;
lidp->lid_flags |= XFS_LID_DIRTY; lidp->lid_flags |= XFS_LID_DIRTY;
lidp->lid_flags &= ~XFS_LID_BUF_STALE;
bip->bli_flags |= XFS_BLI_LOGGED; bip->bli_flags |= XFS_BLI_LOGGED;
xfs_buf_item_log(bip, first, last); xfs_buf_item_log(bip, first, last);
xfs_buf_item_trace("BLOG", bip); xfs_buf_item_trace("BLOG", bip);
...@@ -882,7 +883,7 @@ xfs_trans_binval( ...@@ -882,7 +883,7 @@ xfs_trans_binval(
bip->bli_format.blf_flags |= XFS_BLI_CANCEL; bip->bli_format.blf_flags |= XFS_BLI_CANCEL;
memset((char *)(bip->bli_format.blf_data_map), 0, memset((char *)(bip->bli_format.blf_data_map), 0,
(bip->bli_format.blf_map_size * sizeof(uint))); (bip->bli_format.blf_map_size * sizeof(uint)));
lidp->lid_flags |= XFS_LID_DIRTY; lidp->lid_flags |= XFS_LID_DIRTY|XFS_LID_BUF_STALE;
tp->t_flags |= XFS_TRANS_DIRTY; tp->t_flags |= XFS_TRANS_DIRTY;
xfs_buftrace("XFS_BINVAL", bp); xfs_buftrace("XFS_BINVAL", bp);
xfs_buf_item_trace("BINVAL", bip); xfs_buf_item_trace("BINVAL", bip);
......
...@@ -5248,6 +5248,7 @@ xfsidbg_xtp(xfs_trans_t *tp) ...@@ -5248,6 +5248,7 @@ xfsidbg_xtp(xfs_trans_t *tp)
"dirty", /* 0x1 */ "dirty", /* 0x1 */
"pinned", /* 0x2 */ "pinned", /* 0x2 */
"sync unlock", /* 0x4 */ "sync unlock", /* 0x4 */
"buf stale", /* 0x8 */
0 0
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment