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 | |
21 | static inline struct xfs_dq_logitem *DQUOT_ITEM(struct xfs_log_item *lip) |
22 | { |
23 | return container_of(lip, struct xfs_dq_logitem, qli_item); |
24 | } |
25 | |
26 | /* |
27 | * returns the number of iovecs needed to log the given dquot item. |
28 | */ |
29 | STATIC void |
30 | xfs_qm_dquot_logitem_size( |
31 | struct xfs_log_item *lip, |
32 | int *nvecs, |
33 | int *nbytes) |
34 | { |
35 | *nvecs += 2; |
36 | *nbytes += sizeof(struct xfs_dq_logformat) + |
37 | sizeof(struct xfs_disk_dquot); |
38 | } |
39 | |
40 | /* |
41 | * fills in the vector of log iovecs for the given dquot log item. |
42 | */ |
43 | STATIC void |
44 | xfs_qm_dquot_logitem_format( |
45 | struct xfs_log_item *lip, |
46 | struct xfs_log_vec *lv) |
47 | { |
48 | struct xfs_disk_dquot ddq; |
49 | struct xfs_dq_logitem *qlip = DQUOT_ITEM(lip); |
50 | struct xfs_log_iovec *vecp = NULL; |
51 | struct xfs_dq_logformat *qlf; |
52 | |
53 | qlf = xlog_prepare_iovec(lv, &vecp, XLOG_REG_TYPE_QFORMAT); |
54 | qlf->qlf_type = XFS_LI_DQUOT; |
55 | qlf->qlf_size = 2; |
56 | qlf->qlf_id = qlip->qli_dquot->q_id; |
57 | qlf->qlf_blkno = qlip->qli_dquot->q_blkno; |
58 | qlf->qlf_len = 1; |
59 | qlf->qlf_boffset = qlip->qli_dquot->q_bufoffset; |
60 | xlog_finish_iovec(lv, vecp, sizeof(struct xfs_dq_logformat)); |
61 | |
62 | xfs_dquot_to_disk(ddqp: &ddq, dqp: qlip->qli_dquot); |
63 | |
64 | xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_DQUOT, &ddq, |
65 | sizeof(struct xfs_disk_dquot)); |
66 | } |
67 | |
68 | /* |
69 | * Increment the pin count of the given dquot. |
70 | */ |
71 | STATIC void |
72 | xfs_qm_dquot_logitem_pin( |
73 | struct xfs_log_item *lip) |
74 | { |
75 | struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot; |
76 | |
77 | ASSERT(XFS_DQ_IS_LOCKED(dqp)); |
78 | atomic_inc(v: &dqp->q_pincount); |
79 | } |
80 | |
81 | /* |
82 | * Decrement the pin count of the given dquot, and wake up |
83 | * anyone in xfs_dqwait_unpin() if the count goes to 0. The |
84 | * dquot must have been previously pinned with a call to |
85 | * xfs_qm_dquot_logitem_pin(). |
86 | */ |
87 | STATIC void |
88 | xfs_qm_dquot_logitem_unpin( |
89 | struct xfs_log_item *lip, |
90 | int remove) |
91 | { |
92 | struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot; |
93 | |
94 | ASSERT(atomic_read(&dqp->q_pincount) > 0); |
95 | if (atomic_dec_and_test(v: &dqp->q_pincount)) |
96 | wake_up(&dqp->q_pinwait); |
97 | } |
98 | |
99 | /* |
100 | * This is called to wait for the given dquot to be unpinned. |
101 | * Most of these pin/unpin routines are plagiarized from inode code. |
102 | */ |
103 | void |
104 | xfs_qm_dqunpin_wait( |
105 | struct xfs_dquot *dqp) |
106 | { |
107 | ASSERT(XFS_DQ_IS_LOCKED(dqp)); |
108 | if (atomic_read(v: &dqp->q_pincount) == 0) |
109 | return; |
110 | |
111 | /* |
112 | * Give the log a push so we don't wait here too long. |
113 | */ |
114 | xfs_log_force(mp: dqp->q_mount, flags: 0); |
115 | wait_event(dqp->q_pinwait, (atomic_read(&dqp->q_pincount) == 0)); |
116 | } |
117 | |
118 | STATIC uint |
119 | xfs_qm_dquot_logitem_push( |
120 | struct xfs_log_item *lip, |
121 | struct list_head *buffer_list) |
122 | __releases(&lip->li_ailp->ail_lock) |
123 | __acquires(&lip->li_ailp->ail_lock) |
124 | { |
125 | struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot; |
126 | struct xfs_buf *bp = lip->li_buf; |
127 | uint rval = XFS_ITEM_SUCCESS; |
128 | int error; |
129 | |
130 | if (atomic_read(v: &dqp->q_pincount) > 0) |
131 | return XFS_ITEM_PINNED; |
132 | |
133 | if (!xfs_dqlock_nowait(dqp)) |
134 | return XFS_ITEM_LOCKED; |
135 | |
136 | /* |
137 | * Re-check the pincount now that we stabilized the value by |
138 | * taking the quota lock. |
139 | */ |
140 | if (atomic_read(v: &dqp->q_pincount) > 0) { |
141 | rval = XFS_ITEM_PINNED; |
142 | goto out_unlock; |
143 | } |
144 | |
145 | /* |
146 | * Someone else is already flushing the dquot. Nothing we can do |
147 | * here but wait for the flush to finish and remove the item from |
148 | * the AIL. |
149 | */ |
150 | if (!xfs_dqflock_nowait(dqp)) { |
151 | rval = XFS_ITEM_FLUSHING; |
152 | goto out_unlock; |
153 | } |
154 | |
155 | spin_unlock(lock: &lip->li_ailp->ail_lock); |
156 | |
157 | error = xfs_qm_dqflush(dqp, bpp: &bp); |
158 | if (!error) { |
159 | if (!xfs_buf_delwri_queue(bp, buffer_list)) |
160 | rval = XFS_ITEM_FLUSHING; |
161 | xfs_buf_relse(bp); |
162 | } else if (error == -EAGAIN) |
163 | rval = XFS_ITEM_LOCKED; |
164 | |
165 | spin_lock(lock: &lip->li_ailp->ail_lock); |
166 | out_unlock: |
167 | xfs_dqunlock(dqp); |
168 | return rval; |
169 | } |
170 | |
171 | STATIC void |
172 | xfs_qm_dquot_logitem_release( |
173 | struct xfs_log_item *lip) |
174 | { |
175 | struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot; |
176 | |
177 | ASSERT(XFS_DQ_IS_LOCKED(dqp)); |
178 | |
179 | /* |
180 | * dquots are never 'held' from getting unlocked at the end of |
181 | * a transaction. Their locking and unlocking is hidden inside the |
182 | * transaction layer, within trans_commit. Hence, no LI_HOLD flag |
183 | * for the logitem. |
184 | */ |
185 | xfs_dqunlock(dqp); |
186 | } |
187 | |
188 | STATIC void |
189 | xfs_qm_dquot_logitem_committing( |
190 | struct xfs_log_item *lip, |
191 | xfs_csn_t seq) |
192 | { |
193 | return xfs_qm_dquot_logitem_release(lip); |
194 | } |
195 | |
196 | static const struct xfs_item_ops xfs_dquot_item_ops = { |
197 | .iop_size = xfs_qm_dquot_logitem_size, |
198 | .iop_format = xfs_qm_dquot_logitem_format, |
199 | .iop_pin = xfs_qm_dquot_logitem_pin, |
200 | .iop_unpin = xfs_qm_dquot_logitem_unpin, |
201 | .iop_release = xfs_qm_dquot_logitem_release, |
202 | .iop_committing = xfs_qm_dquot_logitem_committing, |
203 | .iop_push = xfs_qm_dquot_logitem_push, |
204 | }; |
205 | |
206 | /* |
207 | * Initialize the dquot log item for a newly allocated dquot. |
208 | * The dquot isn't locked at this point, but it isn't on any of the lists |
209 | * either, so we don't care. |
210 | */ |
211 | void |
212 | xfs_qm_dquot_logitem_init( |
213 | struct xfs_dquot *dqp) |
214 | { |
215 | struct xfs_dq_logitem *lp = &dqp->q_logitem; |
216 | |
217 | xfs_log_item_init(dqp->q_mount, &lp->qli_item, XFS_LI_DQUOT, |
218 | &xfs_dquot_item_ops); |
219 | lp->qli_dquot = dqp; |
220 | } |
221 | |