Commit 17b38471c3c07a49f0bbc2ecc2e92050c164e226
Committed by
Alex Elder
1 parent
bc6e588a89
Exists in
master
and in
6 other branches
xfs: force the log if we encounter pinned buffers in .iop_pushbuf
We need to check for pinned buffers even in .iop_pushbuf given that inode items flush into the same buffers that may be pinned directly due operations on the unlinked inode list operating directly on buffers. To do this add a return value to .iop_pushbuf that tells the AIL push about this and use the existing log force mechanisms to unpin it. Signed-off-by: Christoph Hellwig <hch@lst.de> Reported-by: Stefan Priebe <s.priebe@profihost.ag> Tested-by: Stefan Priebe <s.priebe@profihost.ag> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Alex Elder <aelder@sgi.com>
Showing 5 changed files with 24 additions and 10 deletions Side-by-side Diff
fs/xfs/xfs_buf_item.c
... | ... | @@ -629,7 +629,7 @@ |
629 | 629 | * the xfsbufd to get this buffer written. We have to unlock the buffer |
630 | 630 | * to allow the xfsbufd to write it, too. |
631 | 631 | */ |
632 | -STATIC void | |
632 | +STATIC bool | |
633 | 633 | xfs_buf_item_pushbuf( |
634 | 634 | struct xfs_log_item *lip) |
635 | 635 | { |
... | ... | @@ -643,6 +643,7 @@ |
643 | 643 | |
644 | 644 | xfs_buf_delwri_promote(bp); |
645 | 645 | xfs_buf_relse(bp); |
646 | + return true; | |
646 | 647 | } |
647 | 648 | |
648 | 649 | STATIC void |
fs/xfs/xfs_dquot_item.c
... | ... | @@ -183,13 +183,14 @@ |
183 | 183 | * search the buffer cache can be a time consuming thing, and AIL lock is a |
184 | 184 | * spinlock. |
185 | 185 | */ |
186 | -STATIC void | |
186 | +STATIC bool | |
187 | 187 | xfs_qm_dquot_logitem_pushbuf( |
188 | 188 | struct xfs_log_item *lip) |
189 | 189 | { |
190 | 190 | struct xfs_dq_logitem *qlip = DQUOT_ITEM(lip); |
191 | 191 | struct xfs_dquot *dqp = qlip->qli_dquot; |
192 | 192 | struct xfs_buf *bp; |
193 | + bool ret = true; | |
193 | 194 | |
194 | 195 | ASSERT(XFS_DQ_IS_LOCKED(dqp)); |
195 | 196 | |
196 | 197 | |
197 | 198 | |
198 | 199 | |
... | ... | @@ -201,17 +202,20 @@ |
201 | 202 | if (completion_done(&dqp->q_flush) || |
202 | 203 | !(lip->li_flags & XFS_LI_IN_AIL)) { |
203 | 204 | xfs_dqunlock(dqp); |
204 | - return; | |
205 | + return true; | |
205 | 206 | } |
206 | 207 | |
207 | 208 | bp = xfs_incore(dqp->q_mount->m_ddev_targp, qlip->qli_format.qlf_blkno, |
208 | 209 | dqp->q_mount->m_quotainfo->qi_dqchunklen, XBF_TRYLOCK); |
209 | 210 | xfs_dqunlock(dqp); |
210 | 211 | if (!bp) |
211 | - return; | |
212 | + return true; | |
212 | 213 | if (XFS_BUF_ISDELAYWRITE(bp)) |
213 | 214 | xfs_buf_delwri_promote(bp); |
215 | + if (xfs_buf_ispinned(bp)) | |
216 | + ret = false; | |
214 | 217 | xfs_buf_relse(bp); |
218 | + return ret; | |
215 | 219 | } |
216 | 220 | |
217 | 221 | /* |
fs/xfs/xfs_inode_item.c
... | ... | @@ -708,13 +708,14 @@ |
708 | 708 | * marked delayed write. If that's the case, we'll promote it and that will |
709 | 709 | * allow the caller to write the buffer by triggering the xfsbufd to run. |
710 | 710 | */ |
711 | -STATIC void | |
711 | +STATIC bool | |
712 | 712 | xfs_inode_item_pushbuf( |
713 | 713 | struct xfs_log_item *lip) |
714 | 714 | { |
715 | 715 | struct xfs_inode_log_item *iip = INODE_ITEM(lip); |
716 | 716 | struct xfs_inode *ip = iip->ili_inode; |
717 | 717 | struct xfs_buf *bp; |
718 | + bool ret = true; | |
718 | 719 | |
719 | 720 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED)); |
720 | 721 | |
... | ... | @@ -725,7 +726,7 @@ |
725 | 726 | if (completion_done(&ip->i_flush) || |
726 | 727 | !(lip->li_flags & XFS_LI_IN_AIL)) { |
727 | 728 | xfs_iunlock(ip, XFS_ILOCK_SHARED); |
728 | - return; | |
729 | + return true; | |
729 | 730 | } |
730 | 731 | |
731 | 732 | bp = xfs_incore(ip->i_mount->m_ddev_targp, iip->ili_format.ilf_blkno, |
732 | 733 | |
733 | 734 | |
... | ... | @@ -733,10 +734,13 @@ |
733 | 734 | |
734 | 735 | xfs_iunlock(ip, XFS_ILOCK_SHARED); |
735 | 736 | if (!bp) |
736 | - return; | |
737 | + return true; | |
737 | 738 | if (XFS_BUF_ISDELAYWRITE(bp)) |
738 | 739 | xfs_buf_delwri_promote(bp); |
740 | + if (xfs_buf_ispinned(bp)) | |
741 | + ret = false; | |
739 | 742 | xfs_buf_relse(bp); |
743 | + return ret; | |
740 | 744 | } |
741 | 745 | |
742 | 746 | /* |
fs/xfs/xfs_trans.h
... | ... | @@ -350,7 +350,7 @@ |
350 | 350 | void (*iop_unlock)(xfs_log_item_t *); |
351 | 351 | xfs_lsn_t (*iop_committed)(xfs_log_item_t *, xfs_lsn_t); |
352 | 352 | void (*iop_push)(xfs_log_item_t *); |
353 | - void (*iop_pushbuf)(xfs_log_item_t *); | |
353 | + bool (*iop_pushbuf)(xfs_log_item_t *); | |
354 | 354 | void (*iop_committing)(xfs_log_item_t *, xfs_lsn_t); |
355 | 355 | } xfs_item_ops_t; |
356 | 356 |
fs/xfs/xfs_trans_ail.c
... | ... | @@ -427,8 +427,13 @@ |
427 | 427 | |
428 | 428 | case XFS_ITEM_PUSHBUF: |
429 | 429 | XFS_STATS_INC(xs_push_ail_pushbuf); |
430 | - IOP_PUSHBUF(lip); | |
431 | - ailp->xa_last_pushed_lsn = lsn; | |
430 | + | |
431 | + if (!IOP_PUSHBUF(lip)) { | |
432 | + stuck++; | |
433 | + flush_log = 1; | |
434 | + } else { | |
435 | + ailp->xa_last_pushed_lsn = lsn; | |
436 | + } | |
432 | 437 | push_xfsbufd = 1; |
433 | 438 | break; |
434 | 439 |