10b61f8a4SDave Chinner // SPDX-License-Identifier: GPL-2.0 2c59d87c4SChristoph Hellwig /* 3c59d87c4SChristoph Hellwig * Copyright (c) 2000-2003 Silicon Graphics, Inc. 4c59d87c4SChristoph Hellwig * All Rights Reserved. 5c59d87c4SChristoph Hellwig */ 6c59d87c4SChristoph Hellwig #include "xfs.h" 7c59d87c4SChristoph Hellwig #include "xfs_fs.h" 85467b34bSDarrick J. Wong #include "xfs_shared.h" 96ca1c906SDave Chinner #include "xfs_format.h" 10239880efSDave Chinner #include "xfs_log_format.h" 11239880efSDave Chinner #include "xfs_trans_resv.h" 12c59d87c4SChristoph Hellwig #include "xfs_mount.h" 13c59d87c4SChristoph Hellwig #include "xfs_inode.h" 14a4fbe6abSDave Chinner #include "xfs_quota.h" 15239880efSDave Chinner #include "xfs_trans.h" 16c59d87c4SChristoph Hellwig #include "xfs_buf_item.h" 17c59d87c4SChristoph Hellwig #include "xfs_trans_priv.h" 18c59d87c4SChristoph Hellwig #include "xfs_qm.h" 19239880efSDave Chinner #include "xfs_log.h" 20*c08d0399SDarrick J. Wong #include "xfs_error.h" 21c59d87c4SChristoph Hellwig 22c59d87c4SChristoph Hellwig static inline struct xfs_dq_logitem *DQUOT_ITEM(struct xfs_log_item *lip) 23c59d87c4SChristoph Hellwig { 24c59d87c4SChristoph Hellwig return container_of(lip, struct xfs_dq_logitem, qli_item); 25c59d87c4SChristoph Hellwig } 26c59d87c4SChristoph Hellwig 27c59d87c4SChristoph Hellwig /* 28c59d87c4SChristoph Hellwig * returns the number of iovecs needed to log the given dquot item. 29c59d87c4SChristoph Hellwig */ 30166d1368SDave Chinner STATIC void 31c59d87c4SChristoph Hellwig xfs_qm_dquot_logitem_size( 32166d1368SDave Chinner struct xfs_log_item *lip, 33166d1368SDave Chinner int *nvecs, 34166d1368SDave Chinner int *nbytes) 35c59d87c4SChristoph Hellwig { 36166d1368SDave Chinner *nvecs += 2; 37166d1368SDave Chinner *nbytes += sizeof(struct xfs_dq_logformat) + 38166d1368SDave Chinner sizeof(struct xfs_disk_dquot); 39c59d87c4SChristoph Hellwig } 40c59d87c4SChristoph Hellwig 41c59d87c4SChristoph Hellwig /* 42c59d87c4SChristoph Hellwig * fills in the vector of log iovecs for the given dquot log item. 43c59d87c4SChristoph Hellwig */ 44c59d87c4SChristoph Hellwig STATIC void 45c59d87c4SChristoph Hellwig xfs_qm_dquot_logitem_format( 46c59d87c4SChristoph Hellwig struct xfs_log_item *lip, 47bde7cff6SChristoph Hellwig struct xfs_log_vec *lv) 48c59d87c4SChristoph Hellwig { 490b0fa1d1SDarrick J. Wong struct xfs_disk_dquot ddq; 50c59d87c4SChristoph Hellwig struct xfs_dq_logitem *qlip = DQUOT_ITEM(lip); 51bde7cff6SChristoph Hellwig struct xfs_log_iovec *vecp = NULL; 52ce8e9629SChristoph Hellwig struct xfs_dq_logformat *qlf; 53c59d87c4SChristoph Hellwig 54ce8e9629SChristoph Hellwig qlf = xlog_prepare_iovec(lv, &vecp, XLOG_REG_TYPE_QFORMAT); 55ce8e9629SChristoph Hellwig qlf->qlf_type = XFS_LI_DQUOT; 56ce8e9629SChristoph Hellwig qlf->qlf_size = 2; 57c51df733SDarrick J. Wong qlf->qlf_id = qlip->qli_dquot->q_id; 58ce8e9629SChristoph Hellwig qlf->qlf_blkno = qlip->qli_dquot->q_blkno; 59ce8e9629SChristoph Hellwig qlf->qlf_len = 1; 60ce8e9629SChristoph Hellwig qlf->qlf_boffset = qlip->qli_dquot->q_bufoffset; 61ce8e9629SChristoph Hellwig xlog_finish_iovec(lv, vecp, sizeof(struct xfs_dq_logformat)); 62bde7cff6SChristoph Hellwig 630b0fa1d1SDarrick J. Wong xfs_dquot_to_disk(&ddq, qlip->qli_dquot); 640b0fa1d1SDarrick J. Wong 650b0fa1d1SDarrick J. Wong xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_DQUOT, &ddq, 66bde7cff6SChristoph Hellwig sizeof(struct xfs_disk_dquot)); 67c59d87c4SChristoph Hellwig } 68c59d87c4SChristoph Hellwig 69c59d87c4SChristoph Hellwig /* 70c59d87c4SChristoph Hellwig * Increment the pin count of the given dquot. 71c59d87c4SChristoph Hellwig */ 72c59d87c4SChristoph Hellwig STATIC void 73c59d87c4SChristoph Hellwig xfs_qm_dquot_logitem_pin( 74c59d87c4SChristoph Hellwig struct xfs_log_item *lip) 75c59d87c4SChristoph Hellwig { 76c59d87c4SChristoph Hellwig struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot; 77c59d87c4SChristoph Hellwig 78c59d87c4SChristoph Hellwig ASSERT(XFS_DQ_IS_LOCKED(dqp)); 79c59d87c4SChristoph Hellwig atomic_inc(&dqp->q_pincount); 80c59d87c4SChristoph Hellwig } 81c59d87c4SChristoph Hellwig 82c59d87c4SChristoph Hellwig /* 83c59d87c4SChristoph Hellwig * Decrement the pin count of the given dquot, and wake up 84c59d87c4SChristoph Hellwig * anyone in xfs_dqwait_unpin() if the count goes to 0. The 85c59d87c4SChristoph Hellwig * dquot must have been previously pinned with a call to 86c59d87c4SChristoph Hellwig * xfs_qm_dquot_logitem_pin(). 87c59d87c4SChristoph Hellwig */ 88c59d87c4SChristoph Hellwig STATIC void 89c59d87c4SChristoph Hellwig xfs_qm_dquot_logitem_unpin( 90c59d87c4SChristoph Hellwig struct xfs_log_item *lip, 91c59d87c4SChristoph Hellwig int remove) 92c59d87c4SChristoph Hellwig { 93c59d87c4SChristoph Hellwig struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot; 94c59d87c4SChristoph Hellwig 95c59d87c4SChristoph Hellwig ASSERT(atomic_read(&dqp->q_pincount) > 0); 96c59d87c4SChristoph Hellwig if (atomic_dec_and_test(&dqp->q_pincount)) 97c59d87c4SChristoph Hellwig wake_up(&dqp->q_pinwait); 98c59d87c4SChristoph Hellwig } 99c59d87c4SChristoph Hellwig 100c59d87c4SChristoph Hellwig /* 101c59d87c4SChristoph Hellwig * This is called to wait for the given dquot to be unpinned. 102c59d87c4SChristoph Hellwig * Most of these pin/unpin routines are plagiarized from inode code. 103c59d87c4SChristoph Hellwig */ 104c59d87c4SChristoph Hellwig void 105c59d87c4SChristoph Hellwig xfs_qm_dqunpin_wait( 106c59d87c4SChristoph Hellwig struct xfs_dquot *dqp) 107c59d87c4SChristoph Hellwig { 108c59d87c4SChristoph Hellwig ASSERT(XFS_DQ_IS_LOCKED(dqp)); 109c59d87c4SChristoph Hellwig if (atomic_read(&dqp->q_pincount) == 0) 110c59d87c4SChristoph Hellwig return; 111c59d87c4SChristoph Hellwig 112c59d87c4SChristoph Hellwig /* 113c59d87c4SChristoph Hellwig * Give the log a push so we don't wait here too long. 114c59d87c4SChristoph Hellwig */ 115c59d87c4SChristoph Hellwig xfs_log_force(dqp->q_mount, 0); 116c59d87c4SChristoph Hellwig wait_event(dqp->q_pinwait, (atomic_read(&dqp->q_pincount) == 0)); 117c59d87c4SChristoph Hellwig } 118c59d87c4SChristoph Hellwig 119c59d87c4SChristoph Hellwig STATIC uint 12043ff2122SChristoph Hellwig xfs_qm_dquot_logitem_push( 12143ff2122SChristoph Hellwig struct xfs_log_item *lip, 12257e80956SMatthew Wilcox struct list_head *buffer_list) 12357e80956SMatthew Wilcox __releases(&lip->li_ailp->ail_lock) 12457e80956SMatthew Wilcox __acquires(&lip->li_ailp->ail_lock) 125c59d87c4SChristoph Hellwig { 126c59d87c4SChristoph Hellwig struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot; 127373b0589SCarlos Maiolino struct xfs_buf *bp = lip->li_buf; 12843ff2122SChristoph Hellwig uint rval = XFS_ITEM_SUCCESS; 12943ff2122SChristoph Hellwig int error; 130c59d87c4SChristoph Hellwig 131c59d87c4SChristoph Hellwig if (atomic_read(&dqp->q_pincount) > 0) 132c59d87c4SChristoph Hellwig return XFS_ITEM_PINNED; 133c59d87c4SChristoph Hellwig 134800b484eSChristoph Hellwig if (!xfs_dqlock_nowait(dqp)) 135c59d87c4SChristoph Hellwig return XFS_ITEM_LOCKED; 136c59d87c4SChristoph Hellwig 137fe7257fdSChristoph Hellwig /* 138fe7257fdSChristoph Hellwig * Re-check the pincount now that we stabilized the value by 139fe7257fdSChristoph Hellwig * taking the quota lock. 140fe7257fdSChristoph Hellwig */ 141fe7257fdSChristoph Hellwig if (atomic_read(&dqp->q_pincount) > 0) { 14243ff2122SChristoph Hellwig rval = XFS_ITEM_PINNED; 14343ff2122SChristoph Hellwig goto out_unlock; 144fe7257fdSChristoph Hellwig } 145fe7257fdSChristoph Hellwig 146c59d87c4SChristoph Hellwig /* 14743ff2122SChristoph Hellwig * Someone else is already flushing the dquot. Nothing we can do 14843ff2122SChristoph Hellwig * here but wait for the flush to finish and remove the item from 14943ff2122SChristoph Hellwig * the AIL. 150c59d87c4SChristoph Hellwig */ 15143ff2122SChristoph Hellwig if (!xfs_dqflock_nowait(dqp)) { 15243ff2122SChristoph Hellwig rval = XFS_ITEM_FLUSHING; 15343ff2122SChristoph Hellwig goto out_unlock; 154c59d87c4SChristoph Hellwig } 155c59d87c4SChristoph Hellwig 15657e80956SMatthew Wilcox spin_unlock(&lip->li_ailp->ail_lock); 15743ff2122SChristoph Hellwig 15843ff2122SChristoph Hellwig error = xfs_qm_dqflush(dqp, &bp); 159609001bcSDarrick J. Wong if (!error) { 16043ff2122SChristoph Hellwig if (!xfs_buf_delwri_queue(bp, buffer_list)) 16143ff2122SChristoph Hellwig rval = XFS_ITEM_FLUSHING; 16243ff2122SChristoph Hellwig xfs_buf_relse(bp); 1638d3d7e2bSBrian Foster } else if (error == -EAGAIN) 1648d3d7e2bSBrian Foster rval = XFS_ITEM_LOCKED; 16543ff2122SChristoph Hellwig 16657e80956SMatthew Wilcox spin_lock(&lip->li_ailp->ail_lock); 16743ff2122SChristoph Hellwig out_unlock: 16843ff2122SChristoph Hellwig xfs_dqunlock(dqp); 16943ff2122SChristoph Hellwig return rval; 170c59d87c4SChristoph Hellwig } 171c59d87c4SChristoph Hellwig 172c59d87c4SChristoph Hellwig STATIC void 173ddf92053SChristoph Hellwig xfs_qm_dquot_logitem_release( 174c59d87c4SChristoph Hellwig struct xfs_log_item *lip) 175c59d87c4SChristoph Hellwig { 176c59d87c4SChristoph Hellwig struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot; 177c59d87c4SChristoph Hellwig 178c59d87c4SChristoph Hellwig ASSERT(XFS_DQ_IS_LOCKED(dqp)); 179c59d87c4SChristoph Hellwig 180c59d87c4SChristoph Hellwig /* 181c59d87c4SChristoph Hellwig * dquots are never 'held' from getting unlocked at the end of 182c59d87c4SChristoph Hellwig * a transaction. Their locking and unlocking is hidden inside the 183c59d87c4SChristoph Hellwig * transaction layer, within trans_commit. Hence, no LI_HOLD flag 184c59d87c4SChristoph Hellwig * for the logitem. 185c59d87c4SChristoph Hellwig */ 186c59d87c4SChristoph Hellwig xfs_dqunlock(dqp); 187c59d87c4SChristoph Hellwig } 188c59d87c4SChristoph Hellwig 189ddf92053SChristoph Hellwig STATIC void 190ddf92053SChristoph Hellwig xfs_qm_dquot_logitem_committing( 191ddf92053SChristoph Hellwig struct xfs_log_item *lip, 1925f9b4b0dSDave Chinner xfs_csn_t seq) 193ddf92053SChristoph Hellwig { 194ddf92053SChristoph Hellwig return xfs_qm_dquot_logitem_release(lip); 195ddf92053SChristoph Hellwig } 196ddf92053SChristoph Hellwig 197*c08d0399SDarrick J. Wong #ifdef DEBUG_EXPENSIVE 198*c08d0399SDarrick J. Wong static int 199*c08d0399SDarrick J. Wong xfs_qm_dquot_logitem_precommit( 200*c08d0399SDarrick J. Wong struct xfs_trans *tp, 201*c08d0399SDarrick J. Wong struct xfs_log_item *lip) 202*c08d0399SDarrick J. Wong { 203*c08d0399SDarrick J. Wong struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot; 204*c08d0399SDarrick J. Wong struct xfs_mount *mp = dqp->q_mount; 205*c08d0399SDarrick J. Wong struct xfs_disk_dquot ddq = { }; 206*c08d0399SDarrick J. Wong xfs_failaddr_t fa; 207*c08d0399SDarrick J. Wong 208*c08d0399SDarrick J. Wong xfs_dquot_to_disk(&ddq, dqp); 209*c08d0399SDarrick J. Wong fa = xfs_dquot_verify(mp, &ddq, dqp->q_id); 210*c08d0399SDarrick J. Wong if (fa) { 211*c08d0399SDarrick J. Wong XFS_CORRUPTION_ERROR("Bad dquot during logging", 212*c08d0399SDarrick J. Wong XFS_ERRLEVEL_LOW, mp, &ddq, sizeof(ddq)); 213*c08d0399SDarrick J. Wong xfs_alert(mp, 214*c08d0399SDarrick J. Wong "Metadata corruption detected at %pS, dquot 0x%x", 215*c08d0399SDarrick J. Wong fa, dqp->q_id); 216*c08d0399SDarrick J. Wong xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); 217*c08d0399SDarrick J. Wong ASSERT(fa == NULL); 218*c08d0399SDarrick J. Wong } 219*c08d0399SDarrick J. Wong 220*c08d0399SDarrick J. Wong return 0; 221*c08d0399SDarrick J. Wong } 222*c08d0399SDarrick J. Wong #else 223*c08d0399SDarrick J. Wong # define xfs_qm_dquot_logitem_precommit NULL 224*c08d0399SDarrick J. Wong #endif 225*c08d0399SDarrick J. Wong 226272e42b2SChristoph Hellwig static const struct xfs_item_ops xfs_dquot_item_ops = { 227c59d87c4SChristoph Hellwig .iop_size = xfs_qm_dquot_logitem_size, 228*c08d0399SDarrick J. Wong .iop_precommit = xfs_qm_dquot_logitem_precommit, 229c59d87c4SChristoph Hellwig .iop_format = xfs_qm_dquot_logitem_format, 230c59d87c4SChristoph Hellwig .iop_pin = xfs_qm_dquot_logitem_pin, 231c59d87c4SChristoph Hellwig .iop_unpin = xfs_qm_dquot_logitem_unpin, 232ddf92053SChristoph Hellwig .iop_release = xfs_qm_dquot_logitem_release, 233ddf92053SChristoph Hellwig .iop_committing = xfs_qm_dquot_logitem_committing, 234c59d87c4SChristoph Hellwig .iop_push = xfs_qm_dquot_logitem_push, 235c59d87c4SChristoph Hellwig }; 236c59d87c4SChristoph Hellwig 237c59d87c4SChristoph Hellwig /* 238c59d87c4SChristoph Hellwig * Initialize the dquot log item for a newly allocated dquot. 239c59d87c4SChristoph Hellwig * The dquot isn't locked at this point, but it isn't on any of the lists 240c59d87c4SChristoph Hellwig * either, so we don't care. 241c59d87c4SChristoph Hellwig */ 242c59d87c4SChristoph Hellwig void 243c59d87c4SChristoph Hellwig xfs_qm_dquot_logitem_init( 244c59d87c4SChristoph Hellwig struct xfs_dquot *dqp) 245c59d87c4SChristoph Hellwig { 246c59d87c4SChristoph Hellwig struct xfs_dq_logitem *lp = &dqp->q_logitem; 247c59d87c4SChristoph Hellwig 248c59d87c4SChristoph Hellwig xfs_log_item_init(dqp->q_mount, &lp->qli_item, XFS_LI_DQUOT, 249c59d87c4SChristoph Hellwig &xfs_dquot_item_ops); 250c59d87c4SChristoph Hellwig lp->qli_dquot = dqp; 251c59d87c4SChristoph Hellwig } 252