aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/quota/xfs_trans_dquot.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /fs/xfs/quota/xfs_trans_dquot.c
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'fs/xfs/quota/xfs_trans_dquot.c')
-rw-r--r--fs/xfs/quota/xfs_trans_dquot.c941
1 files changed, 941 insertions, 0 deletions
diff --git a/fs/xfs/quota/xfs_trans_dquot.c b/fs/xfs/quota/xfs_trans_dquot.c
new file mode 100644
index 000000000000..149b2a1fd949
--- /dev/null
+++ b/fs/xfs/quota/xfs_trans_dquot.c
@@ -0,0 +1,941 @@
1/*
2 * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
22 *
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
25 *
26 * http://www.sgi.com
27 *
28 * For further information regarding this notice, see:
29 *
30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
31 */
32
33#include "xfs.h"
34#include "xfs_fs.h"
35#include "xfs_inum.h"
36#include "xfs_log.h"
37#include "xfs_trans.h"
38#include "xfs_sb.h"
39#include "xfs_ag.h"
40#include "xfs_dir.h"
41#include "xfs_dir2.h"
42#include "xfs_alloc.h"
43#include "xfs_dmapi.h"
44#include "xfs_quota.h"
45#include "xfs_mount.h"
46#include "xfs_alloc_btree.h"
47#include "xfs_bmap_btree.h"
48#include "xfs_ialloc_btree.h"
49#include "xfs_btree.h"
50#include "xfs_ialloc.h"
51#include "xfs_attr_sf.h"
52#include "xfs_dir_sf.h"
53#include "xfs_dir2_sf.h"
54#include "xfs_dinode.h"
55#include "xfs_inode.h"
56#include "xfs_bmap.h"
57#include "xfs_bit.h"
58#include "xfs_rtalloc.h"
59#include "xfs_error.h"
60#include "xfs_itable.h"
61#include "xfs_rw.h"
62#include "xfs_acl.h"
63#include "xfs_cap.h"
64#include "xfs_mac.h"
65#include "xfs_attr.h"
66#include "xfs_buf_item.h"
67#include "xfs_trans_priv.h"
68
69#include "xfs_qm.h"
70
71STATIC void xfs_trans_alloc_dqinfo(xfs_trans_t *);
72
73/*
74 * Add the locked dquot to the transaction.
75 * The dquot must be locked, and it cannot be associated with any
76 * transaction.
77 */
78void
79xfs_trans_dqjoin(
80 xfs_trans_t *tp,
81 xfs_dquot_t *dqp)
82{
83 xfs_dq_logitem_t *lp;
84
85 ASSERT(! XFS_DQ_IS_ADDEDTO_TRX(tp, dqp));
86 ASSERT(XFS_DQ_IS_LOCKED(dqp));
87 ASSERT(XFS_DQ_IS_LOGITEM_INITD(dqp));
88 lp = &dqp->q_logitem;
89
90 /*
91 * Get a log_item_desc to point at the new item.
92 */
93 (void) xfs_trans_add_item(tp, (xfs_log_item_t*)(lp));
94
95 /*
96 * Initialize i_transp so we can later determine if this dquot is
97 * associated with this transaction.
98 */
99 dqp->q_transp = tp;
100}
101
102
103/*
104 * This is called to mark the dquot as needing
105 * to be logged when the transaction is committed. The dquot must
106 * already be associated with the given transaction.
107 * Note that it marks the entire transaction as dirty. In the ordinary
108 * case, this gets called via xfs_trans_commit, after the transaction
109 * is already dirty. However, there's nothing stop this from getting
110 * called directly, as done by xfs_qm_scall_setqlim. Hence, the TRANS_DIRTY
111 * flag.
112 */
113void
114xfs_trans_log_dquot(
115 xfs_trans_t *tp,
116 xfs_dquot_t *dqp)
117{
118 xfs_log_item_desc_t *lidp;
119
120 ASSERT(XFS_DQ_IS_ADDEDTO_TRX(tp, dqp));
121 ASSERT(XFS_DQ_IS_LOCKED(dqp));
122
123 lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)(&dqp->q_logitem));
124 ASSERT(lidp != NULL);
125
126 tp->t_flags |= XFS_TRANS_DIRTY;
127 lidp->lid_flags |= XFS_LID_DIRTY;
128}
129
130/*
131 * Carry forward whatever is left of the quota blk reservation to
132 * the spanky new transaction
133 */
134STATIC void
135xfs_trans_dup_dqinfo(
136 xfs_trans_t *otp,
137 xfs_trans_t *ntp)
138{
139 xfs_dqtrx_t *oq, *nq;
140 int i,j;
141 xfs_dqtrx_t *oqa, *nqa;
142
143 if (!otp->t_dqinfo)
144 return;
145
146 xfs_trans_alloc_dqinfo(ntp);
147 oqa = otp->t_dqinfo->dqa_usrdquots;
148 nqa = ntp->t_dqinfo->dqa_usrdquots;
149
150 /*
151 * Because the quota blk reservation is carried forward,
152 * it is also necessary to carry forward the DQ_DIRTY flag.
153 */
154 if(otp->t_flags & XFS_TRANS_DQ_DIRTY)
155 ntp->t_flags |= XFS_TRANS_DQ_DIRTY;
156
157 for (j = 0; j < 2; j++) {
158 for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
159 if (oqa[i].qt_dquot == NULL)
160 break;
161 oq = &oqa[i];
162 nq = &nqa[i];
163
164 nq->qt_dquot = oq->qt_dquot;
165 nq->qt_bcount_delta = nq->qt_icount_delta = 0;
166 nq->qt_rtbcount_delta = 0;
167
168 /*
169 * Transfer whatever is left of the reservations.
170 */
171 nq->qt_blk_res = oq->qt_blk_res - oq->qt_blk_res_used;
172 oq->qt_blk_res = oq->qt_blk_res_used;
173
174 nq->qt_rtblk_res = oq->qt_rtblk_res -
175 oq->qt_rtblk_res_used;
176 oq->qt_rtblk_res = oq->qt_rtblk_res_used;
177
178 nq->qt_ino_res = oq->qt_ino_res - oq->qt_ino_res_used;
179 oq->qt_ino_res = oq->qt_ino_res_used;
180
181 }
182 oqa = otp->t_dqinfo->dqa_grpdquots;
183 nqa = ntp->t_dqinfo->dqa_grpdquots;
184 }
185}
186
187/*
188 * Wrap around mod_dquot to account for both user and group quotas.
189 */
190void
191xfs_trans_mod_dquot_byino(
192 xfs_trans_t *tp,
193 xfs_inode_t *ip,
194 uint field,
195 long delta)
196{
197 xfs_mount_t *mp;
198
199 ASSERT(tp);
200 mp = tp->t_mountp;
201
202 if (!XFS_IS_QUOTA_ON(mp) ||
203 ip->i_ino == mp->m_sb.sb_uquotino ||
204 ip->i_ino == mp->m_sb.sb_gquotino)
205 return;
206
207 if (tp->t_dqinfo == NULL)
208 xfs_trans_alloc_dqinfo(tp);
209
210 if (XFS_IS_UQUOTA_ON(mp) && ip->i_udquot) {
211 (void) xfs_trans_mod_dquot(tp, ip->i_udquot, field, delta);
212 }
213 if (XFS_IS_GQUOTA_ON(mp) && ip->i_gdquot) {
214 (void) xfs_trans_mod_dquot(tp, ip->i_gdquot, field, delta);
215 }
216}
217
218STATIC xfs_dqtrx_t *
219xfs_trans_get_dqtrx(
220 xfs_trans_t *tp,
221 xfs_dquot_t *dqp)
222{
223 int i;
224 xfs_dqtrx_t *qa;
225
226 for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
227 qa = XFS_QM_DQP_TO_DQACCT(tp, dqp);
228
229 if (qa[i].qt_dquot == NULL ||
230 qa[i].qt_dquot == dqp) {
231 return (&qa[i]);
232 }
233 }
234
235 return (NULL);
236}
237
238/*
239 * Make the changes in the transaction structure.
240 * The moral equivalent to xfs_trans_mod_sb().
241 * We don't touch any fields in the dquot, so we don't care
242 * if it's locked or not (most of the time it won't be).
243 */
244void
245xfs_trans_mod_dquot(
246 xfs_trans_t *tp,
247 xfs_dquot_t *dqp,
248 uint field,
249 long delta)
250{
251 xfs_dqtrx_t *qtrx;
252
253 ASSERT(tp);
254 qtrx = NULL;
255
256 if (tp->t_dqinfo == NULL)
257 xfs_trans_alloc_dqinfo(tp);
258 /*
259 * Find either the first free slot or the slot that belongs
260 * to this dquot.
261 */
262 qtrx = xfs_trans_get_dqtrx(tp, dqp);
263 ASSERT(qtrx);
264 if (qtrx->qt_dquot == NULL)
265 qtrx->qt_dquot = dqp;
266
267 switch (field) {
268
269 /*
270 * regular disk blk reservation
271 */
272 case XFS_TRANS_DQ_RES_BLKS:
273 qtrx->qt_blk_res += (ulong)delta;
274 break;
275
276 /*
277 * inode reservation
278 */
279 case XFS_TRANS_DQ_RES_INOS:
280 qtrx->qt_ino_res += (ulong)delta;
281 break;
282
283 /*
284 * disk blocks used.
285 */
286 case XFS_TRANS_DQ_BCOUNT:
287 if (qtrx->qt_blk_res && delta > 0) {
288 qtrx->qt_blk_res_used += (ulong)delta;
289 ASSERT(qtrx->qt_blk_res >= qtrx->qt_blk_res_used);
290 }
291 qtrx->qt_bcount_delta += delta;
292 break;
293
294 case XFS_TRANS_DQ_DELBCOUNT:
295 qtrx->qt_delbcnt_delta += delta;
296 break;
297
298 /*
299 * Inode Count
300 */
301 case XFS_TRANS_DQ_ICOUNT:
302 if (qtrx->qt_ino_res && delta > 0) {
303 qtrx->qt_ino_res_used += (ulong)delta;
304 ASSERT(qtrx->qt_ino_res >= qtrx->qt_ino_res_used);
305 }
306 qtrx->qt_icount_delta += delta;
307 break;
308
309 /*
310 * rtblk reservation
311 */
312 case XFS_TRANS_DQ_RES_RTBLKS:
313 qtrx->qt_rtblk_res += (ulong)delta;
314 break;
315
316 /*
317 * rtblk count
318 */
319 case XFS_TRANS_DQ_RTBCOUNT:
320 if (qtrx->qt_rtblk_res && delta > 0) {
321 qtrx->qt_rtblk_res_used += (ulong)delta;
322 ASSERT(qtrx->qt_rtblk_res >= qtrx->qt_rtblk_res_used);
323 }
324 qtrx->qt_rtbcount_delta += delta;
325 break;
326
327 case XFS_TRANS_DQ_DELRTBCOUNT:
328 qtrx->qt_delrtb_delta += delta;
329 break;
330
331 default:
332 ASSERT(0);
333 }
334 tp->t_flags |= XFS_TRANS_DQ_DIRTY;
335}
336
337
338/*
339 * Given an array of dqtrx structures, lock all the dquots associated
340 * and join them to the transaction, provided they have been modified.
341 * We know that the highest number of dquots (of one type - usr OR grp),
342 * involved in a transaction is 2 and that both usr and grp combined - 3.
343 * So, we don't attempt to make this very generic.
344 */
345STATIC void
346xfs_trans_dqlockedjoin(
347 xfs_trans_t *tp,
348 xfs_dqtrx_t *q)
349{
350 ASSERT(q[0].qt_dquot != NULL);
351 if (q[1].qt_dquot == NULL) {
352 xfs_dqlock(q[0].qt_dquot);
353 xfs_trans_dqjoin(tp, q[0].qt_dquot);
354 } else {
355 ASSERT(XFS_QM_TRANS_MAXDQS == 2);
356 xfs_dqlock2(q[0].qt_dquot, q[1].qt_dquot);
357 xfs_trans_dqjoin(tp, q[0].qt_dquot);
358 xfs_trans_dqjoin(tp, q[1].qt_dquot);
359 }
360}
361
362
363/*
364 * Called by xfs_trans_commit() and similar in spirit to
365 * xfs_trans_apply_sb_deltas().
366 * Go thru all the dquots belonging to this transaction and modify the
367 * INCORE dquot to reflect the actual usages.
368 * Unreserve just the reservations done by this transaction.
369 * dquot is still left locked at exit.
370 */
371void
372xfs_trans_apply_dquot_deltas(
373 xfs_trans_t *tp)
374{
375 int i, j;
376 xfs_dquot_t *dqp;
377 xfs_dqtrx_t *qtrx, *qa;
378 xfs_disk_dquot_t *d;
379 long totalbdelta;
380 long totalrtbdelta;
381
382 if (! (tp->t_flags & XFS_TRANS_DQ_DIRTY))
383 return;
384
385 ASSERT(tp->t_dqinfo);
386 qa = tp->t_dqinfo->dqa_usrdquots;
387 for (j = 0; j < 2; j++) {
388 if (qa[0].qt_dquot == NULL) {
389 qa = tp->t_dqinfo->dqa_grpdquots;
390 continue;
391 }
392
393 /*
394 * Lock all of the dquots and join them to the transaction.
395 */
396 xfs_trans_dqlockedjoin(tp, qa);
397
398 for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
399 qtrx = &qa[i];
400 /*
401 * The array of dquots is filled
402 * sequentially, not sparsely.
403 */
404 if ((dqp = qtrx->qt_dquot) == NULL)
405 break;
406
407 ASSERT(XFS_DQ_IS_LOCKED(dqp));
408 ASSERT(XFS_DQ_IS_ADDEDTO_TRX(tp, dqp));
409
410 /*
411 * adjust the actual number of blocks used
412 */
413 d = &dqp->q_core;
414
415 /*
416 * The issue here is - sometimes we don't make a blkquota
417 * reservation intentionally to be fair to users
418 * (when the amount is small). On the other hand,
419 * delayed allocs do make reservations, but that's
420 * outside of a transaction, so we have no
421 * idea how much was really reserved.
422 * So, here we've accumulated delayed allocation blks and
423 * non-delay blks. The assumption is that the
424 * delayed ones are always reserved (outside of a
425 * transaction), and the others may or may not have
426 * quota reservations.
427 */
428 totalbdelta = qtrx->qt_bcount_delta +
429 qtrx->qt_delbcnt_delta;
430 totalrtbdelta = qtrx->qt_rtbcount_delta +
431 qtrx->qt_delrtb_delta;
432#ifdef QUOTADEBUG
433 if (totalbdelta < 0)
434 ASSERT(INT_GET(d->d_bcount, ARCH_CONVERT) >=
435 (xfs_qcnt_t) -totalbdelta);
436
437 if (totalrtbdelta < 0)
438 ASSERT(INT_GET(d->d_rtbcount, ARCH_CONVERT) >=
439 (xfs_qcnt_t) -totalrtbdelta);
440
441 if (qtrx->qt_icount_delta < 0)
442 ASSERT(INT_GET(d->d_icount, ARCH_CONVERT) >=
443 (xfs_qcnt_t) -qtrx->qt_icount_delta);
444#endif
445 if (totalbdelta)
446 INT_MOD(d->d_bcount, ARCH_CONVERT, (xfs_qcnt_t)totalbdelta);
447
448 if (qtrx->qt_icount_delta)
449 INT_MOD(d->d_icount, ARCH_CONVERT, (xfs_qcnt_t)qtrx->qt_icount_delta);
450
451 if (totalrtbdelta)
452 INT_MOD(d->d_rtbcount, ARCH_CONVERT, (xfs_qcnt_t)totalrtbdelta);
453
454 /*
455 * Get any default limits in use.
456 * Start/reset the timer(s) if needed.
457 */
458 if (d->d_id) {
459 xfs_qm_adjust_dqlimits(tp->t_mountp, d);
460 xfs_qm_adjust_dqtimers(tp->t_mountp, d);
461 }
462
463 dqp->dq_flags |= XFS_DQ_DIRTY;
464 /*
465 * add this to the list of items to get logged
466 */
467 xfs_trans_log_dquot(tp, dqp);
468 /*
469 * Take off what's left of the original reservation.
470 * In case of delayed allocations, there's no
471 * reservation that a transaction structure knows of.
472 */
473 if (qtrx->qt_blk_res != 0) {
474 if (qtrx->qt_blk_res != qtrx->qt_blk_res_used) {
475 if (qtrx->qt_blk_res >
476 qtrx->qt_blk_res_used)
477 dqp->q_res_bcount -= (xfs_qcnt_t)
478 (qtrx->qt_blk_res -
479 qtrx->qt_blk_res_used);
480 else
481 dqp->q_res_bcount -= (xfs_qcnt_t)
482 (qtrx->qt_blk_res_used -
483 qtrx->qt_blk_res);
484 }
485 } else {
486 /*
487 * These blks were never reserved, either inside
488 * a transaction or outside one (in a delayed
489 * allocation). Also, this isn't always a
490 * negative number since we sometimes
491 * deliberately skip quota reservations.
492 */
493 if (qtrx->qt_bcount_delta) {
494 dqp->q_res_bcount +=
495 (xfs_qcnt_t)qtrx->qt_bcount_delta;
496 }
497 }
498 /*
499 * Adjust the RT reservation.
500 */
501 if (qtrx->qt_rtblk_res != 0) {
502 if (qtrx->qt_blk_res != qtrx->qt_blk_res_used) {
503 if (qtrx->qt_rtblk_res >
504 qtrx->qt_rtblk_res_used)
505 dqp->q_res_rtbcount -= (xfs_qcnt_t)
506 (qtrx->qt_rtblk_res -
507 qtrx->qt_rtblk_res_used);
508 else
509 dqp->q_res_rtbcount -= (xfs_qcnt_t)
510 (qtrx->qt_rtblk_res_used -
511 qtrx->qt_rtblk_res);
512 }
513 } else {
514 if (qtrx->qt_rtbcount_delta)
515 dqp->q_res_rtbcount +=
516 (xfs_qcnt_t)qtrx->qt_rtbcount_delta;
517 }
518
519 /*
520 * Adjust the inode reservation.
521 */
522 if (qtrx->qt_ino_res != 0) {
523 ASSERT(qtrx->qt_ino_res >=
524 qtrx->qt_ino_res_used);
525 if (qtrx->qt_ino_res > qtrx->qt_ino_res_used)
526 dqp->q_res_icount -= (xfs_qcnt_t)
527 (qtrx->qt_ino_res -
528 qtrx->qt_ino_res_used);
529 } else {
530 if (qtrx->qt_icount_delta)
531 dqp->q_res_icount +=
532 (xfs_qcnt_t)qtrx->qt_icount_delta;
533 }
534
535
536#ifdef QUOTADEBUG
537 if (qtrx->qt_rtblk_res != 0)
538 cmn_err(CE_DEBUG, "RT res %d for 0x%p\n",
539 (int) qtrx->qt_rtblk_res, dqp);
540#endif
541 ASSERT(dqp->q_res_bcount >=
542 INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT));
543 ASSERT(dqp->q_res_icount >=
544 INT_GET(dqp->q_core.d_icount, ARCH_CONVERT));
545 ASSERT(dqp->q_res_rtbcount >=
546 INT_GET(dqp->q_core.d_rtbcount, ARCH_CONVERT));
547 }
548 /*
549 * Do the group quotas next
550 */
551 qa = tp->t_dqinfo->dqa_grpdquots;
552 }
553}
554
555/*
556 * Release the reservations, and adjust the dquots accordingly.
557 * This is called only when the transaction is being aborted. If by
558 * any chance we have done dquot modifications incore (ie. deltas) already,
559 * we simply throw those away, since that's the expected behavior
560 * when a transaction is curtailed without a commit.
561 */
562STATIC void
563xfs_trans_unreserve_and_mod_dquots(
564 xfs_trans_t *tp)
565{
566 int i, j;
567 xfs_dquot_t *dqp;
568 xfs_dqtrx_t *qtrx, *qa;
569 boolean_t locked;
570
571 if (!tp->t_dqinfo || !(tp->t_flags & XFS_TRANS_DQ_DIRTY))
572 return;
573
574 qa = tp->t_dqinfo->dqa_usrdquots;
575
576 for (j = 0; j < 2; j++) {
577 for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
578 qtrx = &qa[i];
579 /*
580 * We assume that the array of dquots is filled
581 * sequentially, not sparsely.
582 */
583 if ((dqp = qtrx->qt_dquot) == NULL)
584 break;
585 /*
586 * Unreserve the original reservation. We don't care
587 * about the number of blocks used field, or deltas.
588 * Also we don't bother to zero the fields.
589 */
590 locked = B_FALSE;
591 if (qtrx->qt_blk_res) {
592 xfs_dqlock(dqp);
593 locked = B_TRUE;
594 dqp->q_res_bcount -=
595 (xfs_qcnt_t)qtrx->qt_blk_res;
596 }
597 if (qtrx->qt_ino_res) {
598 if (!locked) {
599 xfs_dqlock(dqp);
600 locked = B_TRUE;
601 }
602 dqp->q_res_icount -=
603 (xfs_qcnt_t)qtrx->qt_ino_res;
604 }
605
606 if (qtrx->qt_rtblk_res) {
607 if (!locked) {
608 xfs_dqlock(dqp);
609 locked = B_TRUE;
610 }
611 dqp->q_res_rtbcount -=
612 (xfs_qcnt_t)qtrx->qt_rtblk_res;
613 }
614 if (locked)
615 xfs_dqunlock(dqp);
616
617 }
618 qa = tp->t_dqinfo->dqa_grpdquots;
619 }
620}
621
622/*
623 * This reserves disk blocks and inodes against a dquot.
624 * Flags indicate if the dquot is to be locked here and also
625 * if the blk reservation is for RT or regular blocks.
626 * Sending in XFS_QMOPT_FORCE_RES flag skips the quota check.
627 * Returns EDQUOT if quota is exceeded.
628 */
629STATIC int
630xfs_trans_dqresv(
631 xfs_trans_t *tp,
632 xfs_mount_t *mp,
633 xfs_dquot_t *dqp,
634 long nblks,
635 long ninos,
636 uint flags)
637{
638 int error;
639 xfs_qcnt_t hardlimit;
640 xfs_qcnt_t softlimit;
641 time_t btimer;
642 xfs_qcnt_t *resbcountp;
643 xfs_quotainfo_t *q = mp->m_quotainfo;
644
645 if (! (flags & XFS_QMOPT_DQLOCK)) {
646 xfs_dqlock(dqp);
647 }
648 ASSERT(XFS_DQ_IS_LOCKED(dqp));
649 if (flags & XFS_TRANS_DQ_RES_BLKS) {
650 hardlimit = INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT);
651 if (!hardlimit)
652 hardlimit = q->qi_bhardlimit;
653 softlimit = INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT);
654 if (!softlimit)
655 softlimit = q->qi_bsoftlimit;
656 btimer = INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT);
657 resbcountp = &dqp->q_res_bcount;
658 } else {
659 ASSERT(flags & XFS_TRANS_DQ_RES_RTBLKS);
660 hardlimit = INT_GET(dqp->q_core.d_rtb_hardlimit, ARCH_CONVERT);
661 if (!hardlimit)
662 hardlimit = q->qi_rtbhardlimit;
663 softlimit = INT_GET(dqp->q_core.d_rtb_softlimit, ARCH_CONVERT);
664 if (!softlimit)
665 softlimit = q->qi_rtbsoftlimit;
666 btimer = INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT);
667 resbcountp = &dqp->q_res_rtbcount;
668 }
669 error = 0;
670
671 if ((flags & XFS_QMOPT_FORCE_RES) == 0 &&
672 dqp->q_core.d_id &&
673 XFS_IS_QUOTA_ENFORCED(dqp->q_mount)) {
674#ifdef QUOTADEBUG
675 cmn_err(CE_DEBUG, "BLK Res: nblks=%ld + resbcount=%Ld"
676 " > hardlimit=%Ld?", nblks, *resbcountp, hardlimit);
677#endif
678 if (nblks > 0) {
679 /*
680 * dquot is locked already. See if we'd go over the
681 * hardlimit or exceed the timelimit if we allocate
682 * nblks.
683 */
684 if (hardlimit > 0ULL &&
685 (hardlimit <= nblks + *resbcountp)) {
686 error = EDQUOT;
687 goto error_return;
688 }
689
690 if (softlimit > 0ULL &&
691 (softlimit <= nblks + *resbcountp)) {
692 /*
693 * If timer or warnings has expired,
694 * return EDQUOT
695 */
696 if ((btimer != 0 && get_seconds() > btimer) ||
697 (dqp->q_core.d_bwarns &&
698 INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) >=
699 XFS_QI_BWARNLIMIT(dqp->q_mount))) {
700 error = EDQUOT;
701 goto error_return;
702 }
703 }
704 }
705 if (ninos > 0) {
706 hardlimit = INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT);
707 if (!hardlimit)
708 hardlimit = q->qi_ihardlimit;
709 softlimit = INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT);
710 if (!softlimit)
711 softlimit = q->qi_isoftlimit;
712 if (hardlimit > 0ULL &&
713 INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >= hardlimit) {
714 error = EDQUOT;
715 goto error_return;
716 } else if (softlimit > 0ULL &&
717 INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >= softlimit) {
718 /*
719 * If timer or warnings has expired,
720 * return EDQUOT
721 */
722 if ((dqp->q_core.d_itimer &&
723 get_seconds() > INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT)) ||
724 (dqp->q_core.d_iwarns &&
725 INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) >=
726 XFS_QI_IWARNLIMIT(dqp->q_mount))) {
727 error = EDQUOT;
728 goto error_return;
729 }
730 }
731 }
732 }
733
734 /*
735 * Change the reservation, but not the actual usage.
736 * Note that q_res_bcount = q_core.d_bcount + resv
737 */
738 (*resbcountp) += (xfs_qcnt_t)nblks;
739 if (ninos != 0)
740 dqp->q_res_icount += (xfs_qcnt_t)ninos;
741
742 /*
743 * note the reservation amt in the trans struct too,
744 * so that the transaction knows how much was reserved by
745 * it against this particular dquot.
746 * We don't do this when we are reserving for a delayed allocation,
747 * because we don't have the luxury of a transaction envelope then.
748 */
749 if (tp) {
750 ASSERT(tp->t_dqinfo);
751 ASSERT(flags & XFS_QMOPT_RESBLK_MASK);
752 if (nblks != 0)
753 xfs_trans_mod_dquot(tp, dqp,
754 flags & XFS_QMOPT_RESBLK_MASK,
755 nblks);
756 if (ninos != 0)
757 xfs_trans_mod_dquot(tp, dqp,
758 XFS_TRANS_DQ_RES_INOS,
759 ninos);
760 }
761 ASSERT(dqp->q_res_bcount >= INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT));
762 ASSERT(dqp->q_res_rtbcount >= INT_GET(dqp->q_core.d_rtbcount, ARCH_CONVERT));
763 ASSERT(dqp->q_res_icount >= INT_GET(dqp->q_core.d_icount, ARCH_CONVERT));
764
765error_return:
766 if (! (flags & XFS_QMOPT_DQLOCK)) {
767 xfs_dqunlock(dqp);
768 }
769 return (error);
770}
771
772
773/*
774 * Given a dquot(s), make disk block and/or inode reservations against them.
775 * The fact that this does the reservation against both the usr and
776 * grp quotas is important, because this follows a both-or-nothing
777 * approach.
778 *
779 * flags = XFS_QMOPT_DQLOCK indicate if dquot(s) need to be locked.
780 * XFS_QMOPT_FORCE_RES evades limit enforcement. Used by chown.
781 * XFS_TRANS_DQ_RES_BLKS reserves regular disk blocks
782 * XFS_TRANS_DQ_RES_RTBLKS reserves realtime disk blocks
783 * dquots are unlocked on return, if they were not locked by caller.
784 */
785int
786xfs_trans_reserve_quota_bydquots(
787 xfs_trans_t *tp,
788 xfs_mount_t *mp,
789 xfs_dquot_t *udqp,
790 xfs_dquot_t *gdqp,
791 long nblks,
792 long ninos,
793 uint flags)
794{
795 int resvd;
796
797 if (! XFS_IS_QUOTA_ON(mp))
798 return (0);
799
800 if (tp && tp->t_dqinfo == NULL)
801 xfs_trans_alloc_dqinfo(tp);
802
803 ASSERT(flags & XFS_QMOPT_RESBLK_MASK);
804 resvd = 0;
805
806 if (udqp) {
807 if (xfs_trans_dqresv(tp, mp, udqp, nblks, ninos, flags))
808 return (EDQUOT);
809 resvd = 1;
810 }
811
812 if (gdqp) {
813 if (xfs_trans_dqresv(tp, mp, gdqp, nblks, ninos, flags)) {
814 /*
815 * can't do it, so backout previous reservation
816 */
817 if (resvd) {
818 flags |= XFS_QMOPT_FORCE_RES;
819 xfs_trans_dqresv(tp, mp, udqp,
820 -nblks, -ninos, flags);
821 }
822 return (EDQUOT);
823 }
824 }
825
826 /*
827 * Didnt change anything critical, so, no need to log
828 */
829 return (0);
830}
831
832
833/*
834 * Lock the dquot and change the reservation if we can.
835 * This doesn't change the actual usage, just the reservation.
836 * The inode sent in is locked.
837 *
838 * Returns 0 on success, EDQUOT or other errors otherwise
839 */
840STATIC int
841xfs_trans_reserve_quota_nblks(
842 xfs_trans_t *tp,
843 xfs_mount_t *mp,
844 xfs_inode_t *ip,
845 long nblks,
846 long ninos,
847 uint type)
848{
849 int error;
850
851 if (!XFS_IS_QUOTA_ON(mp))
852 return (0);
853
854 ASSERT(ip->i_ino != mp->m_sb.sb_uquotino);
855 ASSERT(ip->i_ino != mp->m_sb.sb_gquotino);
856
857 ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
858 ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount));
859 ASSERT((type & ~XFS_QMOPT_FORCE_RES) == XFS_TRANS_DQ_RES_RTBLKS ||
860 (type & ~XFS_QMOPT_FORCE_RES) == XFS_TRANS_DQ_RES_BLKS);
861
862 /*
863 * Reserve nblks against these dquots, with trans as the mediator.
864 */
865 error = xfs_trans_reserve_quota_bydquots(tp, mp,
866 ip->i_udquot, ip->i_gdquot,
867 nblks, ninos,
868 type);
869 return (error);
870}
871
872/*
873 * This routine is called to allocate a quotaoff log item.
874 */
875xfs_qoff_logitem_t *
876xfs_trans_get_qoff_item(
877 xfs_trans_t *tp,
878 xfs_qoff_logitem_t *startqoff,
879 uint flags)
880{
881 xfs_qoff_logitem_t *q;
882
883 ASSERT(tp != NULL);
884
885 q = xfs_qm_qoff_logitem_init(tp->t_mountp, startqoff, flags);
886 ASSERT(q != NULL);
887
888 /*
889 * Get a log_item_desc to point at the new item.
890 */
891 (void) xfs_trans_add_item(tp, (xfs_log_item_t*)q);
892
893 return (q);
894}
895
896
897/*
898 * This is called to mark the quotaoff logitem as needing
899 * to be logged when the transaction is committed. The logitem must
900 * already be associated with the given transaction.
901 */
902void
903xfs_trans_log_quotaoff_item(
904 xfs_trans_t *tp,
905 xfs_qoff_logitem_t *qlp)
906{
907 xfs_log_item_desc_t *lidp;
908
909 lidp = xfs_trans_find_item(tp, (xfs_log_item_t *)qlp);
910 ASSERT(lidp != NULL);
911
912 tp->t_flags |= XFS_TRANS_DIRTY;
913 lidp->lid_flags |= XFS_LID_DIRTY;
914}
915
916STATIC void
917xfs_trans_alloc_dqinfo(
918 xfs_trans_t *tp)
919{
920 (tp)->t_dqinfo = kmem_zone_zalloc(xfs_Gqm->qm_dqtrxzone, KM_SLEEP);
921}
922
923STATIC void
924xfs_trans_free_dqinfo(
925 xfs_trans_t *tp)
926{
927 if (!tp->t_dqinfo)
928 return;
929 kmem_zone_free(xfs_Gqm->qm_dqtrxzone, (tp)->t_dqinfo);
930 (tp)->t_dqinfo = NULL;
931}
932
933xfs_dqtrxops_t xfs_trans_dquot_ops = {
934 .qo_dup_dqinfo = xfs_trans_dup_dqinfo,
935 .qo_free_dqinfo = xfs_trans_free_dqinfo,
936 .qo_mod_dquot_byino = xfs_trans_mod_dquot_byino,
937 .qo_apply_dquot_deltas = xfs_trans_apply_dquot_deltas,
938 .qo_reserve_quota_nblks = xfs_trans_reserve_quota_nblks,
939 .qo_reserve_quota_bydquots = xfs_trans_reserve_quota_bydquots,
940 .qo_unreserve_and_mod_dquots = xfs_trans_unreserve_and_mod_dquots,
941};