FILE
xfs_dquot_item.c
File preview with syntax highlighting.
linux-6.19.14/fs/xfs/xfs_dquot_item.c
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (c) 2000-2003 Silicon Graphics, Inc. 4 * All Rights Reserved. 5 */ 6#include "xfs.h" 7#include "xfs_fs.h" 8#include "xfs_shared.h" 9#include "xfs_format.h" 10#include "xfs_log_format.h" 11#include "xfs_trans_resv.h" 12#include "xfs_mount.h" 13#include "xfs_inode.h" 14#include "xfs_quota.h" 15#include "xfs_trans.h" 16#include "xfs_buf_item.h" 17#include "xfs_trans_priv.h" 18#include "xfs_qm.h" 19#include "xfs_log.h" 20#include "xfs_error.h" 21 22static inline struct xfs_dq_logitem *DQUOT_ITEM(struct xfs_log_item *lip) 23{ 24 return container_of(lip, struct xfs_dq_logitem, qli_item); 25} 26 27/* 28 * returns the number of iovecs needed to log the given dquot item. 29 */ 30STATIC void 31xfs_qm_dquot_logitem_size( 32 struct xfs_log_item *lip, 33 int *nvecs, 34 int *nbytes) 35{ 36 *nvecs += 2; 37 *nbytes += sizeof(struct xfs_dq_logformat) + 38 sizeof(struct xfs_disk_dquot); 39} 40 41/* 42 * fills in the vector of log iovecs for the given dquot log item. 43 */ 44STATIC void 45xfs_qm_dquot_logitem_format( 46 struct xfs_log_item *lip, 47 struct xfs_log_vec *lv) 48{ 49 struct xfs_disk_dquot ddq; 50 struct xfs_dq_logitem *qlip = DQUOT_ITEM(lip); 51 struct xfs_log_iovec *vecp = NULL; 52 struct xfs_dq_logformat *qlf; 53 54 qlf = xlog_prepare_iovec(lv, &vecp, XLOG_REG_TYPE_QFORMAT); 55 qlf->qlf_type = XFS_LI_DQUOT; 56 qlf->qlf_size = 2; 57 qlf->qlf_id = qlip->qli_dquot->q_id; 58 qlf->qlf_blkno = qlip->qli_dquot->q_blkno; 59 qlf->qlf_len = 1; 60 qlf->qlf_boffset = qlip->qli_dquot->q_bufoffset; 61 xlog_finish_iovec(lv, vecp, sizeof(struct xfs_dq_logformat)); 62 63 xfs_dquot_to_disk(&ddq, qlip->qli_dquot); 64 65 xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_DQUOT, &ddq, 66 sizeof(struct xfs_disk_dquot)); 67} 68 69/* 70 * Increment the pin count of the given dquot. 71 */ 72STATIC void 73xfs_qm_dquot_logitem_pin( 74 struct xfs_log_item *lip) 75{ 76 struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot; 77 78 ASSERT(XFS_DQ_IS_LOCKED(dqp)); 79 atomic_inc(&dqp->q_pincount); 80} 81 82/* 83 * Decrement the pin count of the given dquot, and wake up 84 * anyone in xfs_dqwait_unpin() if the count goes to 0. The 85 * dquot must have been previously pinned with a call to 86 * xfs_qm_dquot_logitem_pin(). 87 */ 88STATIC void 89xfs_qm_dquot_logitem_unpin( 90 struct xfs_log_item *lip, 91 int remove) 92{ 93 struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot; 94 95 ASSERT(atomic_read(&dqp->q_pincount) > 0); 96 if (atomic_dec_and_test(&dqp->q_pincount)) 97 wake_up(&dqp->q_pinwait); 98} 99 100/* 101 * This is called to wait for the given dquot to be unpinned. 102 * Most of these pin/unpin routines are plagiarized from inode code. 103 */ 104void 105xfs_qm_dqunpin_wait( 106 struct xfs_dquot *dqp) 107{ 108 ASSERT(XFS_DQ_IS_LOCKED(dqp)); 109 if (atomic_read(&dqp->q_pincount) == 0) 110 return; 111 112 /* 113 * Give the log a push so we don't wait here too long. 114 */ 115 xfs_log_force(dqp->q_mount, 0); 116 wait_event(dqp->q_pinwait, (atomic_read(&dqp->q_pincount) == 0)); 117} 118 119STATIC uint 120xfs_qm_dquot_logitem_push( 121 struct xfs_log_item *lip, 122 struct list_head *buffer_list) 123 __releases(&lip->li_ailp->ail_lock) 124 __acquires(&lip->li_ailp->ail_lock) 125{ 126 struct xfs_dq_logitem *qlip = DQUOT_ITEM(lip); 127 struct xfs_dquot *dqp = qlip->qli_dquot; 128 struct xfs_buf *bp; 129 struct xfs_ail *ailp = lip->li_ailp; 130 uint rval = XFS_ITEM_SUCCESS; 131 int error; 132 133 if (atomic_read(&dqp->q_pincount) > 0) 134 return XFS_ITEM_PINNED; 135 136 if (!mutex_trylock(&dqp->q_qlock)) 137 return XFS_ITEM_LOCKED; 138 139 /* 140 * Re-check the pincount now that we stabilized the value by 141 * taking the quota lock. 142 */ 143 if (atomic_read(&dqp->q_pincount) > 0) { 144 rval = XFS_ITEM_PINNED; 145 goto out_unlock; 146 } 147 148 /* 149 * Someone else is already flushing the dquot. Nothing we can do 150 * here but wait for the flush to finish and remove the item from 151 * the AIL. 152 */ 153 if (!xfs_dqflock_nowait(dqp)) { 154 rval = XFS_ITEM_FLUSHING; 155 goto out_unlock; 156 } 157 158 spin_unlock(&ailp->ail_lock); 159 160 error = xfs_dquot_use_attached_buf(dqp, &bp); 161 if (error == -EAGAIN) { 162 xfs_dqfunlock(dqp); 163 rval = XFS_ITEM_LOCKED; 164 goto out_relock_ail; 165 } 166 167 /* 168 * dqflush completes dqflock on error, and the delwri ioend does it on 169 * success. 170 */ 171 error = xfs_qm_dqflush(dqp, bp); 172 if (!error) { 173 if (!xfs_buf_delwri_queue(bp, buffer_list)) 174 rval = XFS_ITEM_FLUSHING; 175 } 176 xfs_buf_relse(bp); 177 /* 178 * The buffer no longer protects the log item from reclaim, so 179 * do not reference lip after this point. 180 */ 181 182out_relock_ail: 183 spin_lock(&ailp->ail_lock); 184out_unlock: 185 mutex_unlock(&dqp->q_qlock); 186 return rval; 187} 188 189STATIC void 190xfs_qm_dquot_logitem_release( 191 struct xfs_log_item *lip) 192{ 193 struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot; 194 195 ASSERT(XFS_DQ_IS_LOCKED(dqp)); 196 197 /* 198 * dquots are never 'held' from getting unlocked at the end of 199 * a transaction. Their locking and unlocking is hidden inside the 200 * transaction layer, within trans_commit. Hence, no LI_HOLD flag 201 * for the logitem. 202 */ 203 mutex_unlock(&dqp->q_qlock); 204} 205 206STATIC void 207xfs_qm_dquot_logitem_committing( 208 struct xfs_log_item *lip, 209 xfs_csn_t seq) 210{ 211 return xfs_qm_dquot_logitem_release(lip); 212} 213 214#ifdef DEBUG_EXPENSIVE 215static void 216xfs_qm_dquot_logitem_precommit_check( 217 struct xfs_dquot *dqp) 218{ 219 struct xfs_mount *mp = dqp->q_mount; 220 struct xfs_disk_dquot ddq = { }; 221 xfs_failaddr_t fa; 222 223 xfs_dquot_to_disk(&ddq, dqp); 224 fa = xfs_dquot_verify(mp, &ddq, dqp->q_id); 225 if (fa) { 226 XFS_CORRUPTION_ERROR("Bad dquot during logging", 227 XFS_ERRLEVEL_LOW, mp, &ddq, sizeof(ddq)); 228 xfs_alert(mp, 229 "Metadata corruption detected at %pS, dquot 0x%x", 230 fa, dqp->q_id); 231 xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); 232 ASSERT(fa == NULL); 233 } 234} 235#else 236# define xfs_qm_dquot_logitem_precommit_check(...) ((void)0) 237#endif 238 239static int 240xfs_qm_dquot_logitem_precommit( 241 struct xfs_trans *tp, 242 struct xfs_log_item *lip) 243{ 244 struct xfs_dq_logitem *qlip = DQUOT_ITEM(lip); 245 struct xfs_dquot *dqp = qlip->qli_dquot; 246 247 xfs_qm_dquot_logitem_precommit_check(dqp); 248 249 return xfs_dquot_attach_buf(tp, dqp); 250} 251 252static const struct xfs_item_ops xfs_dquot_item_ops = { 253 .iop_size = xfs_qm_dquot_logitem_size, 254 .iop_precommit = xfs_qm_dquot_logitem_precommit, 255 .iop_format = xfs_qm_dquot_logitem_format, 256 .iop_pin = xfs_qm_dquot_logitem_pin, 257 .iop_unpin = xfs_qm_dquot_logitem_unpin, 258 .iop_release = xfs_qm_dquot_logitem_release, 259 .iop_committing = xfs_qm_dquot_logitem_committing, 260 .iop_push = xfs_qm_dquot_logitem_push, 261}; 262 263/* 264 * Initialize the dquot log item for a newly allocated dquot. 265 * The dquot isn't locked at this point, but it isn't on any of the lists 266 * either, so we don't care. 267 */ 268void 269xfs_qm_dquot_logitem_init( 270 struct xfs_dquot *dqp) 271{ 272 struct xfs_dq_logitem *lp = &dqp->q_logitem; 273 274 xfs_log_item_init(dqp->q_mount, &lp->qli_item, XFS_LI_DQUOT, 275 &xfs_dquot_item_ops); 276 spin_lock_init(&lp->qli_lock); 277 lp->qli_dquot = dqp; 278 lp->qli_dirty = false; 279}
~/
Read-only file preview.