/* * This is called when IOP_TRYLOCK returns XFS_ITEM_PUSHBUF to indicate that * the dquot is locked by us, but the flush lock isn't. So, here we are * going to see if the relevant dquot buffer is incore, waiting on DELWRI. * If so, we want to push it out to help us take this item off the AIL as soon * as possible. * * We must not be holding the AIL lock at this point. Calling incore() to * search the buffer cache can be a time consuming thing, and AIL lock is a * spinlock. */ STATIC void xfs_qm_dquot_logitem_pushbuf( struct xfs_log_item *lip) { struct xfs_dq_logitem *qlip = DQUOT_ITEM(lip); struct xfs_dquot *dqp = qlip->qli_dquot; struct xfs_buf *bp; ASSERT(XFS_DQ_IS_LOCKED(dqp)); /* * If flushlock isn't locked anymore, chances are that the * inode flush completed and the inode was taken off the AIL. * So, just get out. */ if (completion_done(&dqp->q_flush) || !(lip->li_flags & XFS_LI_IN_AIL)) { xfs_dqunlock(dqp); return; } bp = xfs_incore(dqp->q_mount->m_ddev_targp, qlip->qli_format.qlf_blkno, dqp->q_mount->m_quotainfo->qi_dqchunklen, XBF_TRYLOCK); xfs_dqunlock(dqp); if (!bp) return; if (XFS_BUF_ISDELAYWRITE(bp)) xfs_buf_delwri_promote(bp); xfs_buf_relse(bp); }
/* * Given the logitem, this writes the corresponding dquot entry to disk * asynchronously. This is called with the dquot entry securely locked; * we simply get xfs_qm_dqflush() to do the work, and unlock the dquot * at the end. */ STATIC void xfs_qm_dquot_logitem_push( struct xfs_log_item *lip) { struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot; int error; ASSERT(XFS_DQ_IS_LOCKED(dqp)); ASSERT(!completion_done(&dqp->q_flush)); /* * Since we were able to lock the dquot's flush lock and * we found it on the AIL, the dquot must be dirty. This * is because the dquot is removed from the AIL while still * holding the flush lock in xfs_dqflush_done(). Thus, if * we found it in the AIL and were able to obtain the flush * lock without sleeping, then there must not have been * anyone in the process of flushing the dquot. */ error = xfs_qm_dqflush(dqp, 0); if (error) xfs_fs_cmn_err(CE_WARN, dqp->q_mount, "xfs_qm_dquot_logitem_push: push error %d on dqp %p", error, dqp); xfs_dqunlock(dqp); }
/* * Increment the pin count of the given dquot. */ STATIC void xfs_qm_dquot_logitem_pin( struct xfs_log_item *lip) { struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot; ASSERT(XFS_DQ_IS_LOCKED(dqp)); atomic_inc(&dqp->q_pincount); }
/* * Decrement the pin count of the given dquot, and wake up * anyone in xfs_dqwait_unpin() if the count goes to 0. The * dquot must have been previously pinned with a call to * xfs_qm_dquot_logitem_pin(). */ STATIC void xfs_qm_dquot_logitem_unpin( struct xfs_log_item *lip, int remove) { struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot; ASSERT(atomic_read(&dqp->q_pincount) > 0); if (atomic_dec_and_test(&dqp->q_pincount)) wake_up(&dqp->q_pinwait); }
/* * fills in the vector of log iovecs for the given dquot log item. */ STATIC void xfs_qm_dquot_logitem_format( struct xfs_log_item *lip, struct xfs_log_iovec *logvec) { struct xfs_dq_logitem *qlip = DQUOT_ITEM(lip); logvec->i_addr = &qlip->qli_format; logvec->i_len = sizeof(xfs_dq_logformat_t); logvec->i_type = XLOG_REG_TYPE_QFORMAT; logvec++; logvec->i_addr = &qlip->qli_dquot->q_core; logvec->i_len = sizeof(xfs_disk_dquot_t); logvec->i_type = XLOG_REG_TYPE_DQUOT; qlip->qli_format.qlf_size = 2; }
/* * Unlock the dquot associated with the log item. * Clear the fields of the dquot and dquot log item that * are specific to the current transaction. If the * hold flags is set, do not unlock the dquot. */ STATIC void xfs_qm_dquot_logitem_unlock( struct xfs_log_item *lip) { struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot; ASSERT(XFS_DQ_IS_LOCKED(dqp)); /* * Clear the transaction pointer in the dquot */ dqp->q_transp = NULL; /* * dquots are never 'held' from getting unlocked at the end of * a transaction. Their locking and unlocking is hidden inside the * transaction layer, within trans_commit. Hence, no LI_HOLD flag * for the logitem. */ xfs_dqunlock(dqp); }
/* * fills in the vector of log iovecs for the given dquot log item. */ STATIC void xfs_qm_dquot_logitem_format( struct xfs_log_item *lip, struct xfs_log_vec *lv) { struct xfs_dq_logitem *qlip = DQUOT_ITEM(lip); struct xfs_log_iovec *vecp = NULL; struct xfs_dq_logformat *qlf; qlf = xlog_prepare_iovec(lv, &vecp, XLOG_REG_TYPE_QFORMAT); qlf->qlf_type = XFS_LI_DQUOT; qlf->qlf_size = 2; qlf->qlf_id = be32_to_cpu(qlip->qli_dquot->q_core.d_id); qlf->qlf_blkno = qlip->qli_dquot->q_blkno; qlf->qlf_len = 1; qlf->qlf_boffset = qlip->qli_dquot->q_bufoffset; xlog_finish_iovec(lv, vecp, sizeof(struct xfs_dq_logformat)); xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_DQUOT, &qlip->qli_dquot->q_core, sizeof(struct xfs_disk_dquot)); }
/* * This is called to attempt to lock the dquot associated with this * dquot log item. Don't sleep on the dquot lock or the flush lock. * If the flush lock is already held, indicating that the dquot has * been or is in the process of being flushed, then see if we can * find the dquot's buffer in the buffer cache without sleeping. If * we can and it is marked delayed write, then we want to send it out. * We delay doing so until the push routine, though, to avoid sleeping * in any device strategy routines. */ STATIC uint xfs_qm_dquot_logitem_trylock( struct xfs_log_item *lip) { struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot; if (atomic_read(&dqp->q_pincount) > 0) return XFS_ITEM_PINNED; if (!xfs_qm_dqlock_nowait(dqp)) return XFS_ITEM_LOCKED; if (!xfs_dqflock_nowait(dqp)) { /* * dquot has already been flushed to the backing buffer, * leave it locked, pushbuf routine will unlock it. */ return XFS_ITEM_PUSHBUF; } ASSERT(lip->li_flags & XFS_LI_IN_AIL); return XFS_ITEM_SUCCESS; }
return; /* * Give the log a push so we don't wait here too long. */ xfs_log_force(dqp->q_mount, 0); wait_event(dqp->q_pinwait, (atomic_read(&dqp->q_pincount) == 0)); } STATIC uint xfs_qm_dquot_logitem_push( struct xfs_log_item *lip, struct list_head *buffer_list) __releases(&lip->li_ailp->xa_lock) __acquires(&lip->li_ailp->xa_lock) { struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot; struct xfs_buf *bp = NULL; uint rval = XFS_ITEM_SUCCESS; int error; if (atomic_read(&dqp->q_pincount) > 0) return XFS_ITEM_PINNED; if (!xfs_dqlock_nowait(dqp)) return XFS_ITEM_LOCKED; /* * Re-check the pincount now that we stabilized the value by * taking the quota lock. */ if (atomic_read(&dqp->q_pincount) > 0) {