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
DQUOT_ITEM(struct xfs_log_item * lip)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
xfs_qm_dquot_logitem_size(struct xfs_log_item * lip,int * nvecs,int * nbytes)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
xfs_qm_dquot_logitem_format(struct xfs_log_item * lip,struct xfs_log_vec * lv)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
xfs_qm_dquot_logitem_pin(struct xfs_log_item * lip)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
xfs_qm_dquot_logitem_unpin(struct xfs_log_item * lip,int remove)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
xfs_qm_dqunpin_wait(struct xfs_dquot * dqp)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
xfs_qm_dquot_logitem_push(struct xfs_log_item * lip,struct list_head * buffer_list)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
xfs_qm_dquot_logitem_release(struct xfs_log_item * lip)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
xfs_qm_dquot_logitem_committing(struct xfs_log_item * lip,xfs_csn_t seq)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
xfs_qm_dquot_logitem_precommit(struct xfs_trans * tp,struct xfs_log_item * lip)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
xfs_qm_dquot_logitem_init(struct xfs_dquot * dqp)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