aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/quota
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
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')
-rw-r--r--fs/xfs/quota/xfs_dquot.c1648
-rw-r--r--fs/xfs/quota/xfs_dquot.h224
-rw-r--r--fs/xfs/quota/xfs_dquot_item.c715
-rw-r--r--fs/xfs/quota/xfs_dquot_item.h66
-rw-r--r--fs/xfs/quota/xfs_qm.c2848
-rw-r--r--fs/xfs/quota/xfs_qm.h236
-rw-r--r--fs/xfs/quota/xfs_qm_bhv.c410
-rw-r--r--fs/xfs/quota/xfs_qm_stats.c149
-rw-r--r--fs/xfs/quota/xfs_qm_stats.h68
-rw-r--r--fs/xfs/quota/xfs_qm_syscalls.c1458
-rw-r--r--fs/xfs/quota/xfs_quota_priv.h192
-rw-r--r--fs/xfs/quota/xfs_trans_dquot.c941
12 files changed, 8955 insertions, 0 deletions
diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/quota/xfs_dquot.c
new file mode 100644
index 000000000000..740d20d33187
--- /dev/null
+++ b/fs/xfs/quota/xfs_dquot.c
@@ -0,0 +1,1648 @@
1/*
2 * Copyright (c) 2000-2003 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_space.h"
68#include "xfs_trans_priv.h"
69
70#include "xfs_qm.h"
71
72
73/*
74 LOCK ORDER
75
76 inode lock (ilock)
77 dquot hash-chain lock (hashlock)
78 xqm dquot freelist lock (freelistlock
79 mount's dquot list lock (mplistlock)
80 user dquot lock - lock ordering among dquots is based on the uid or gid
81 group dquot lock - similar to udquots. Between the two dquots, the udquot
82 has to be locked first.
83 pin lock - the dquot lock must be held to take this lock.
84 flush lock - ditto.
85*/
86
87STATIC void xfs_qm_dqflush_done(xfs_buf_t *, xfs_dq_logitem_t *);
88
89#ifdef DEBUG
90xfs_buftarg_t *xfs_dqerror_target;
91int xfs_do_dqerror;
92int xfs_dqreq_num;
93int xfs_dqerror_mod = 33;
94#endif
95
96/*
97 * Allocate and initialize a dquot. We don't always allocate fresh memory;
98 * we try to reclaim a free dquot if the number of incore dquots are above
99 * a threshold.
100 * The only field inside the core that gets initialized at this point
101 * is the d_id field. The idea is to fill in the entire q_core
102 * when we read in the on disk dquot.
103 */
104xfs_dquot_t *
105xfs_qm_dqinit(
106 xfs_mount_t *mp,
107 xfs_dqid_t id,
108 uint type)
109{
110 xfs_dquot_t *dqp;
111 boolean_t brandnewdquot;
112
113 brandnewdquot = xfs_qm_dqalloc_incore(&dqp);
114 dqp->dq_flags = type;
115 INT_SET(dqp->q_core.d_id, ARCH_CONVERT, id);
116 dqp->q_mount = mp;
117
118 /*
119 * No need to re-initialize these if this is a reclaimed dquot.
120 */
121 if (brandnewdquot) {
122 dqp->dq_flnext = dqp->dq_flprev = dqp;
123 mutex_init(&dqp->q_qlock, MUTEX_DEFAULT, "xdq");
124 initnsema(&dqp->q_flock, 1, "fdq");
125 sv_init(&dqp->q_pinwait, SV_DEFAULT, "pdq");
126
127#ifdef XFS_DQUOT_TRACE
128 dqp->q_trace = ktrace_alloc(DQUOT_TRACE_SIZE, KM_SLEEP);
129 xfs_dqtrace_entry(dqp, "DQINIT");
130#endif
131 } else {
132 /*
133 * Only the q_core portion was zeroed in dqreclaim_one().
134 * So, we need to reset others.
135 */
136 dqp->q_nrefs = 0;
137 dqp->q_blkno = 0;
138 dqp->MPL_NEXT = dqp->HL_NEXT = NULL;
139 dqp->HL_PREVP = dqp->MPL_PREVP = NULL;
140 dqp->q_bufoffset = 0;
141 dqp->q_fileoffset = 0;
142 dqp->q_transp = NULL;
143 dqp->q_gdquot = NULL;
144 dqp->q_res_bcount = 0;
145 dqp->q_res_icount = 0;
146 dqp->q_res_rtbcount = 0;
147 dqp->q_pincount = 0;
148 dqp->q_hash = NULL;
149 ASSERT(dqp->dq_flnext == dqp->dq_flprev);
150
151#ifdef XFS_DQUOT_TRACE
152 ASSERT(dqp->q_trace);
153 xfs_dqtrace_entry(dqp, "DQRECLAIMED_INIT");
154#endif
155 }
156
157 /*
158 * log item gets initialized later
159 */
160 return (dqp);
161}
162
163/*
164 * This is called to free all the memory associated with a dquot
165 */
166void
167xfs_qm_dqdestroy(
168 xfs_dquot_t *dqp)
169{
170 ASSERT(! XFS_DQ_IS_ON_FREELIST(dqp));
171
172 mutex_destroy(&dqp->q_qlock);
173 freesema(&dqp->q_flock);
174 sv_destroy(&dqp->q_pinwait);
175
176#ifdef XFS_DQUOT_TRACE
177 if (dqp->q_trace)
178 ktrace_free(dqp->q_trace);
179 dqp->q_trace = NULL;
180#endif
181 kmem_zone_free(xfs_Gqm->qm_dqzone, dqp);
182 atomic_dec(&xfs_Gqm->qm_totaldquots);
183}
184
185/*
186 * This is what a 'fresh' dquot inside a dquot chunk looks like on disk.
187 */
188STATIC void
189xfs_qm_dqinit_core(
190 xfs_dqid_t id,
191 uint type,
192 xfs_dqblk_t *d)
193{
194 /*
195 * Caller has zero'd the entire dquot 'chunk' already.
196 */
197 INT_SET(d->dd_diskdq.d_magic, ARCH_CONVERT, XFS_DQUOT_MAGIC);
198 INT_SET(d->dd_diskdq.d_version, ARCH_CONVERT, XFS_DQUOT_VERSION);
199 INT_SET(d->dd_diskdq.d_id, ARCH_CONVERT, id);
200 INT_SET(d->dd_diskdq.d_flags, ARCH_CONVERT, type);
201}
202
203
204#ifdef XFS_DQUOT_TRACE
205/*
206 * Dquot tracing for debugging.
207 */
208/* ARGSUSED */
209void
210__xfs_dqtrace_entry(
211 xfs_dquot_t *dqp,
212 char *func,
213 void *retaddr,
214 xfs_inode_t *ip)
215{
216 xfs_dquot_t *udqp = NULL;
217 xfs_ino_t ino = 0;
218
219 ASSERT(dqp->q_trace);
220 if (ip) {
221 ino = ip->i_ino;
222 udqp = ip->i_udquot;
223 }
224 ktrace_enter(dqp->q_trace,
225 (void *)(__psint_t)DQUOT_KTRACE_ENTRY,
226 (void *)func,
227 (void *)(__psint_t)dqp->q_nrefs,
228 (void *)(__psint_t)dqp->dq_flags,
229 (void *)(__psint_t)dqp->q_res_bcount,
230 (void *)(__psint_t)INT_GET(dqp->q_core.d_bcount,
231 ARCH_CONVERT),
232 (void *)(__psint_t)INT_GET(dqp->q_core.d_icount,
233 ARCH_CONVERT),
234 (void *)(__psint_t)INT_GET(dqp->q_core.d_blk_hardlimit,
235 ARCH_CONVERT),
236 (void *)(__psint_t)INT_GET(dqp->q_core.d_blk_softlimit,
237 ARCH_CONVERT),
238 (void *)(__psint_t)INT_GET(dqp->q_core.d_ino_hardlimit,
239 ARCH_CONVERT),
240 (void *)(__psint_t)INT_GET(dqp->q_core.d_ino_softlimit,
241 ARCH_CONVERT),
242 (void *)(__psint_t)INT_GET(dqp->q_core.d_id, ARCH_CONVERT),
243 (void *)(__psint_t)current_pid(),
244 (void *)(__psint_t)ino,
245 (void *)(__psint_t)retaddr,
246 (void *)(__psint_t)udqp);
247 return;
248}
249#endif
250
251
252/*
253 * If default limits are in force, push them into the dquot now.
254 * We overwrite the dquot limits only if they are zero and this
255 * is not the root dquot.
256 */
257void
258xfs_qm_adjust_dqlimits(
259 xfs_mount_t *mp,
260 xfs_disk_dquot_t *d)
261{
262 xfs_quotainfo_t *q = mp->m_quotainfo;
263
264 ASSERT(d->d_id);
265
266 if (q->qi_bsoftlimit && !d->d_blk_softlimit)
267 INT_SET(d->d_blk_softlimit, ARCH_CONVERT, q->qi_bsoftlimit);
268 if (q->qi_bhardlimit && !d->d_blk_hardlimit)
269 INT_SET(d->d_blk_hardlimit, ARCH_CONVERT, q->qi_bhardlimit);
270 if (q->qi_isoftlimit && !d->d_ino_softlimit)
271 INT_SET(d->d_ino_softlimit, ARCH_CONVERT, q->qi_isoftlimit);
272 if (q->qi_ihardlimit && !d->d_ino_hardlimit)
273 INT_SET(d->d_ino_hardlimit, ARCH_CONVERT, q->qi_ihardlimit);
274 if (q->qi_rtbsoftlimit && !d->d_rtb_softlimit)
275 INT_SET(d->d_rtb_softlimit, ARCH_CONVERT, q->qi_rtbsoftlimit);
276 if (q->qi_rtbhardlimit && !d->d_rtb_hardlimit)
277 INT_SET(d->d_rtb_hardlimit, ARCH_CONVERT, q->qi_rtbhardlimit);
278}
279
280/*
281 * Check the limits and timers of a dquot and start or reset timers
282 * if necessary.
283 * This gets called even when quota enforcement is OFF, which makes our
284 * life a little less complicated. (We just don't reject any quota
285 * reservations in that case, when enforcement is off).
286 * We also return 0 as the values of the timers in Q_GETQUOTA calls, when
287 * enforcement's off.
288 * In contrast, warnings are a little different in that they don't
289 * 'automatically' get started when limits get exceeded.
290 */
291void
292xfs_qm_adjust_dqtimers(
293 xfs_mount_t *mp,
294 xfs_disk_dquot_t *d)
295{
296 ASSERT(d->d_id);
297
298#ifdef QUOTADEBUG
299 if (INT_GET(d->d_blk_hardlimit, ARCH_CONVERT))
300 ASSERT(INT_GET(d->d_blk_softlimit, ARCH_CONVERT) <=
301 INT_GET(d->d_blk_hardlimit, ARCH_CONVERT));
302 if (INT_GET(d->d_ino_hardlimit, ARCH_CONVERT))
303 ASSERT(INT_GET(d->d_ino_softlimit, ARCH_CONVERT) <=
304 INT_GET(d->d_ino_hardlimit, ARCH_CONVERT));
305 if (INT_GET(d->d_rtb_hardlimit, ARCH_CONVERT))
306 ASSERT(INT_GET(d->d_rtb_softlimit, ARCH_CONVERT) <=
307 INT_GET(d->d_rtb_hardlimit, ARCH_CONVERT));
308#endif
309 if (!d->d_btimer) {
310 if ((INT_GET(d->d_blk_softlimit, ARCH_CONVERT) &&
311 (INT_GET(d->d_bcount, ARCH_CONVERT) >=
312 INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) ||
313 (INT_GET(d->d_blk_hardlimit, ARCH_CONVERT) &&
314 (INT_GET(d->d_bcount, ARCH_CONVERT) >=
315 INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)))) {
316 INT_SET(d->d_btimer, ARCH_CONVERT,
317 get_seconds() + XFS_QI_BTIMELIMIT(mp));
318 }
319 } else {
320 if ((!d->d_blk_softlimit ||
321 (INT_GET(d->d_bcount, ARCH_CONVERT) <
322 INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) &&
323 (!d->d_blk_hardlimit ||
324 (INT_GET(d->d_bcount, ARCH_CONVERT) <
325 INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)))) {
326 d->d_btimer = 0;
327 }
328 }
329
330 if (!d->d_itimer) {
331 if ((INT_GET(d->d_ino_softlimit, ARCH_CONVERT) &&
332 (INT_GET(d->d_icount, ARCH_CONVERT) >=
333 INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) ||
334 (INT_GET(d->d_ino_hardlimit, ARCH_CONVERT) &&
335 (INT_GET(d->d_icount, ARCH_CONVERT) >=
336 INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)))) {
337 INT_SET(d->d_itimer, ARCH_CONVERT,
338 get_seconds() + XFS_QI_ITIMELIMIT(mp));
339 }
340 } else {
341 if ((!d->d_ino_softlimit ||
342 (INT_GET(d->d_icount, ARCH_CONVERT) <
343 INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) &&
344 (!d->d_ino_hardlimit ||
345 (INT_GET(d->d_icount, ARCH_CONVERT) <
346 INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)))) {
347 d->d_itimer = 0;
348 }
349 }
350
351 if (!d->d_rtbtimer) {
352 if ((INT_GET(d->d_rtb_softlimit, ARCH_CONVERT) &&
353 (INT_GET(d->d_rtbcount, ARCH_CONVERT) >=
354 INT_GET(d->d_rtb_softlimit, ARCH_CONVERT))) ||
355 (INT_GET(d->d_rtb_hardlimit, ARCH_CONVERT) &&
356 (INT_GET(d->d_rtbcount, ARCH_CONVERT) >=
357 INT_GET(d->d_rtb_hardlimit, ARCH_CONVERT)))) {
358 INT_SET(d->d_rtbtimer, ARCH_CONVERT,
359 get_seconds() + XFS_QI_RTBTIMELIMIT(mp));
360 }
361 } else {
362 if ((!d->d_rtb_softlimit ||
363 (INT_GET(d->d_rtbcount, ARCH_CONVERT) <
364 INT_GET(d->d_rtb_softlimit, ARCH_CONVERT))) &&
365 (!d->d_rtb_hardlimit ||
366 (INT_GET(d->d_rtbcount, ARCH_CONVERT) <
367 INT_GET(d->d_rtb_hardlimit, ARCH_CONVERT)))) {
368 d->d_rtbtimer = 0;
369 }
370 }
371}
372
373/*
374 * Increment or reset warnings of a given dquot.
375 */
376int
377xfs_qm_dqwarn(
378 xfs_disk_dquot_t *d,
379 uint flags)
380{
381 int warned;
382
383 /*
384 * root's limits are not real limits.
385 */
386 if (!d->d_id)
387 return (0);
388
389 warned = 0;
390 if (INT_GET(d->d_blk_softlimit, ARCH_CONVERT) &&
391 (INT_GET(d->d_bcount, ARCH_CONVERT) >=
392 INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) {
393 if (flags & XFS_QMOPT_DOWARN) {
394 INT_MOD(d->d_bwarns, ARCH_CONVERT, +1);
395 warned++;
396 }
397 } else {
398 if (!d->d_blk_softlimit ||
399 (INT_GET(d->d_bcount, ARCH_CONVERT) <
400 INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) {
401 d->d_bwarns = 0;
402 }
403 }
404
405 if (INT_GET(d->d_ino_softlimit, ARCH_CONVERT) > 0 &&
406 (INT_GET(d->d_icount, ARCH_CONVERT) >=
407 INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) {
408 if (flags & XFS_QMOPT_DOWARN) {
409 INT_MOD(d->d_iwarns, ARCH_CONVERT, +1);
410 warned++;
411 }
412 } else {
413 if (!d->d_ino_softlimit ||
414 (INT_GET(d->d_icount, ARCH_CONVERT) <
415 INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) {
416 d->d_iwarns = 0;
417 }
418 }
419#ifdef QUOTADEBUG
420 if (INT_GET(d->d_iwarns, ARCH_CONVERT))
421 cmn_err(CE_DEBUG,
422 "--------@@Inode warnings running : %Lu >= %Lu",
423 INT_GET(d->d_icount, ARCH_CONVERT),
424 INT_GET(d->d_ino_softlimit, ARCH_CONVERT));
425 if (INT_GET(d->d_bwarns, ARCH_CONVERT))
426 cmn_err(CE_DEBUG,
427 "--------@@Blks warnings running : %Lu >= %Lu",
428 INT_GET(d->d_bcount, ARCH_CONVERT),
429 INT_GET(d->d_blk_softlimit, ARCH_CONVERT));
430#endif
431 return (warned);
432}
433
434
435/*
436 * initialize a buffer full of dquots and log the whole thing
437 */
438STATIC void
439xfs_qm_init_dquot_blk(
440 xfs_trans_t *tp,
441 xfs_mount_t *mp,
442 xfs_dqid_t id,
443 uint type,
444 xfs_buf_t *bp)
445{
446 xfs_dqblk_t *d;
447 int curid, i;
448
449 ASSERT(tp);
450 ASSERT(XFS_BUF_ISBUSY(bp));
451 ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
452
453 d = (xfs_dqblk_t *)XFS_BUF_PTR(bp);
454
455 /*
456 * ID of the first dquot in the block - id's are zero based.
457 */
458 curid = id - (id % XFS_QM_DQPERBLK(mp));
459 ASSERT(curid >= 0);
460 memset(d, 0, BBTOB(XFS_QI_DQCHUNKLEN(mp)));
461 for (i = 0; i < XFS_QM_DQPERBLK(mp); i++, d++, curid++)
462 xfs_qm_dqinit_core(curid, type, d);
463 xfs_trans_dquot_buf(tp, bp,
464 type & XFS_DQ_USER ?
465 XFS_BLI_UDQUOT_BUF :
466 XFS_BLI_GDQUOT_BUF);
467 xfs_trans_log_buf(tp, bp, 0, BBTOB(XFS_QI_DQCHUNKLEN(mp)) - 1);
468}
469
470
471
472/*
473 * Allocate a block and fill it with dquots.
474 * This is called when the bmapi finds a hole.
475 */
476STATIC int
477xfs_qm_dqalloc(
478 xfs_trans_t *tp,
479 xfs_mount_t *mp,
480 xfs_dquot_t *dqp,
481 xfs_inode_t *quotip,
482 xfs_fileoff_t offset_fsb,
483 xfs_buf_t **O_bpp)
484{
485 xfs_fsblock_t firstblock;
486 xfs_bmap_free_t flist;
487 xfs_bmbt_irec_t map;
488 int nmaps, error, committed;
489 xfs_buf_t *bp;
490
491 ASSERT(tp != NULL);
492 xfs_dqtrace_entry(dqp, "DQALLOC");
493
494 /*
495 * Initialize the bmap freelist prior to calling bmapi code.
496 */
497 XFS_BMAP_INIT(&flist, &firstblock);
498 xfs_ilock(quotip, XFS_ILOCK_EXCL);
499 /*
500 * Return if this type of quotas is turned off while we didn't
501 * have an inode lock
502 */
503 if (XFS_IS_THIS_QUOTA_OFF(dqp)) {
504 xfs_iunlock(quotip, XFS_ILOCK_EXCL);
505 return (ESRCH);
506 }
507
508 /*
509 * xfs_trans_commit normally decrements the vnode ref count
510 * when it unlocks the inode. Since we want to keep the quota
511 * inode around, we bump the vnode ref count now.
512 */
513 VN_HOLD(XFS_ITOV(quotip));
514
515 xfs_trans_ijoin(tp, quotip, XFS_ILOCK_EXCL);
516 nmaps = 1;
517 if ((error = xfs_bmapi(tp, quotip,
518 offset_fsb, XFS_DQUOT_CLUSTER_SIZE_FSB,
519 XFS_BMAPI_METADATA | XFS_BMAPI_WRITE,
520 &firstblock,
521 XFS_QM_DQALLOC_SPACE_RES(mp),
522 &map, &nmaps, &flist))) {
523 goto error0;
524 }
525 ASSERT(map.br_blockcount == XFS_DQUOT_CLUSTER_SIZE_FSB);
526 ASSERT(nmaps == 1);
527 ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
528 (map.br_startblock != HOLESTARTBLOCK));
529
530 /*
531 * Keep track of the blkno to save a lookup later
532 */
533 dqp->q_blkno = XFS_FSB_TO_DADDR(mp, map.br_startblock);
534
535 /* now we can just get the buffer (there's nothing to read yet) */
536 bp = xfs_trans_get_buf(tp, mp->m_ddev_targp,
537 dqp->q_blkno,
538 XFS_QI_DQCHUNKLEN(mp),
539 0);
540 if (!bp || (error = XFS_BUF_GETERROR(bp)))
541 goto error1;
542 /*
543 * Make a chunk of dquots out of this buffer and log
544 * the entire thing.
545 */
546 xfs_qm_init_dquot_blk(tp, mp, INT_GET(dqp->q_core.d_id, ARCH_CONVERT),
547 dqp->dq_flags & (XFS_DQ_USER|XFS_DQ_GROUP),
548 bp);
549
550 if ((error = xfs_bmap_finish(&tp, &flist, firstblock, &committed))) {
551 goto error1;
552 }
553
554 *O_bpp = bp;
555 return 0;
556
557 error1:
558 xfs_bmap_cancel(&flist);
559 error0:
560 xfs_iunlock(quotip, XFS_ILOCK_EXCL);
561
562 return (error);
563}
564
565/*
566 * Maps a dquot to the buffer containing its on-disk version.
567 * This returns a ptr to the buffer containing the on-disk dquot
568 * in the bpp param, and a ptr to the on-disk dquot within that buffer
569 */
570STATIC int
571xfs_qm_dqtobp(
572 xfs_trans_t *tp,
573 xfs_dquot_t *dqp,
574 xfs_disk_dquot_t **O_ddpp,
575 xfs_buf_t **O_bpp,
576 uint flags)
577{
578 xfs_bmbt_irec_t map;
579 int nmaps, error;
580 xfs_buf_t *bp;
581 xfs_inode_t *quotip;
582 xfs_mount_t *mp;
583 xfs_disk_dquot_t *ddq;
584 xfs_dqid_t id;
585 boolean_t newdquot;
586
587 mp = dqp->q_mount;
588 id = INT_GET(dqp->q_core.d_id, ARCH_CONVERT);
589 nmaps = 1;
590 newdquot = B_FALSE;
591
592 /*
593 * If we don't know where the dquot lives, find out.
594 */
595 if (dqp->q_blkno == (xfs_daddr_t) 0) {
596 /* We use the id as an index */
597 dqp->q_fileoffset = (xfs_fileoff_t) ((uint)id /
598 XFS_QM_DQPERBLK(mp));
599 nmaps = 1;
600 quotip = XFS_DQ_TO_QIP(dqp);
601 xfs_ilock(quotip, XFS_ILOCK_SHARED);
602 /*
603 * Return if this type of quotas is turned off while we didn't
604 * have an inode lock
605 */
606 if (XFS_IS_THIS_QUOTA_OFF(dqp)) {
607 xfs_iunlock(quotip, XFS_ILOCK_SHARED);
608 return (ESRCH);
609 }
610 /*
611 * Find the block map; no allocations yet
612 */
613 error = xfs_bmapi(NULL, quotip, dqp->q_fileoffset,
614 XFS_DQUOT_CLUSTER_SIZE_FSB,
615 XFS_BMAPI_METADATA,
616 NULL, 0, &map, &nmaps, NULL);
617
618 xfs_iunlock(quotip, XFS_ILOCK_SHARED);
619 if (error)
620 return (error);
621 ASSERT(nmaps == 1);
622 ASSERT(map.br_blockcount == 1);
623
624 /*
625 * offset of dquot in the (fixed sized) dquot chunk.
626 */
627 dqp->q_bufoffset = (id % XFS_QM_DQPERBLK(mp)) *
628 sizeof(xfs_dqblk_t);
629 if (map.br_startblock == HOLESTARTBLOCK) {
630 /*
631 * We don't allocate unless we're asked to
632 */
633 if (!(flags & XFS_QMOPT_DQALLOC))
634 return (ENOENT);
635
636 ASSERT(tp);
637 if ((error = xfs_qm_dqalloc(tp, mp, dqp, quotip,
638 dqp->q_fileoffset, &bp)))
639 return (error);
640 newdquot = B_TRUE;
641 } else {
642 /*
643 * store the blkno etc so that we don't have to do the
644 * mapping all the time
645 */
646 dqp->q_blkno = XFS_FSB_TO_DADDR(mp, map.br_startblock);
647 }
648 }
649 ASSERT(dqp->q_blkno != DELAYSTARTBLOCK);
650 ASSERT(dqp->q_blkno != HOLESTARTBLOCK);
651
652 /*
653 * Read in the buffer, unless we've just done the allocation
654 * (in which case we already have the buf).
655 */
656 if (! newdquot) {
657 xfs_dqtrace_entry(dqp, "DQTOBP READBUF");
658 if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
659 dqp->q_blkno,
660 XFS_QI_DQCHUNKLEN(mp),
661 0, &bp))) {
662 return (error);
663 }
664 if (error || !bp)
665 return XFS_ERROR(error);
666 }
667 ASSERT(XFS_BUF_ISBUSY(bp));
668 ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
669
670 /*
671 * calculate the location of the dquot inside the buffer.
672 */
673 ddq = (xfs_disk_dquot_t *)((char *)XFS_BUF_PTR(bp) + dqp->q_bufoffset);
674
675 /*
676 * A simple sanity check in case we got a corrupted dquot...
677 */
678 if (xfs_qm_dqcheck(ddq, id,
679 dqp->dq_flags & (XFS_DQ_USER|XFS_DQ_GROUP),
680 flags & (XFS_QMOPT_DQREPAIR|XFS_QMOPT_DOWARN),
681 "dqtobp")) {
682 if (!(flags & XFS_QMOPT_DQREPAIR)) {
683 xfs_trans_brelse(tp, bp);
684 return XFS_ERROR(EIO);
685 }
686 XFS_BUF_BUSY(bp); /* We dirtied this */
687 }
688
689 *O_bpp = bp;
690 *O_ddpp = ddq;
691
692 return (0);
693}
694
695
696/*
697 * Read in the ondisk dquot using dqtobp() then copy it to an incore version,
698 * and release the buffer immediately.
699 *
700 */
701/* ARGSUSED */
702STATIC int
703xfs_qm_dqread(
704 xfs_trans_t *tp,
705 xfs_dqid_t id,
706 xfs_dquot_t *dqp, /* dquot to get filled in */
707 uint flags)
708{
709 xfs_disk_dquot_t *ddqp;
710 xfs_buf_t *bp;
711 int error;
712
713 /*
714 * get a pointer to the on-disk dquot and the buffer containing it
715 * dqp already knows its own type (GROUP/USER).
716 */
717 xfs_dqtrace_entry(dqp, "DQREAD");
718 if ((error = xfs_qm_dqtobp(tp, dqp, &ddqp, &bp, flags))) {
719 return (error);
720 }
721
722 /* copy everything from disk dquot to the incore dquot */
723 memcpy(&dqp->q_core, ddqp, sizeof(xfs_disk_dquot_t));
724 ASSERT(INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id);
725 xfs_qm_dquot_logitem_init(dqp);
726
727 /*
728 * Reservation counters are defined as reservation plus current usage
729 * to avoid having to add everytime.
730 */
731 dqp->q_res_bcount = INT_GET(ddqp->d_bcount, ARCH_CONVERT);
732 dqp->q_res_icount = INT_GET(ddqp->d_icount, ARCH_CONVERT);
733 dqp->q_res_rtbcount = INT_GET(ddqp->d_rtbcount, ARCH_CONVERT);
734
735 /* Mark the buf so that this will stay incore a little longer */
736 XFS_BUF_SET_VTYPE_REF(bp, B_FS_DQUOT, XFS_DQUOT_REF);
737
738 /*
739 * We got the buffer with a xfs_trans_read_buf() (in dqtobp())
740 * So we need to release with xfs_trans_brelse().
741 * The strategy here is identical to that of inodes; we lock
742 * the dquot in xfs_qm_dqget() before making it accessible to
743 * others. This is because dquots, like inodes, need a good level of
744 * concurrency, and we don't want to take locks on the entire buffers
745 * for dquot accesses.
746 * Note also that the dquot buffer may even be dirty at this point, if
747 * this particular dquot was repaired. We still aren't afraid to
748 * brelse it because we have the changes incore.
749 */
750 ASSERT(XFS_BUF_ISBUSY(bp));
751 ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
752 xfs_trans_brelse(tp, bp);
753
754 return (error);
755}
756
757
758/*
759 * allocate an incore dquot from the kernel heap,
760 * and fill its core with quota information kept on disk.
761 * If XFS_QMOPT_DQALLOC is set, it'll allocate a dquot on disk
762 * if it wasn't already allocated.
763 */
764STATIC int
765xfs_qm_idtodq(
766 xfs_mount_t *mp,
767 xfs_dqid_t id, /* gid or uid, depending on type */
768 uint type, /* UDQUOT or GDQUOT */
769 uint flags, /* DQALLOC, DQREPAIR */
770 xfs_dquot_t **O_dqpp)/* OUT : incore dquot, not locked */
771{
772 xfs_dquot_t *dqp;
773 int error;
774 xfs_trans_t *tp;
775 int cancelflags=0;
776
777 dqp = xfs_qm_dqinit(mp, id, type);
778 tp = NULL;
779 if (flags & XFS_QMOPT_DQALLOC) {
780 tp = xfs_trans_alloc(mp, XFS_TRANS_QM_DQALLOC);
781 if ((error = xfs_trans_reserve(tp,
782 XFS_QM_DQALLOC_SPACE_RES(mp),
783 XFS_WRITE_LOG_RES(mp) +
784 BBTOB(XFS_QI_DQCHUNKLEN(mp)) - 1 +
785 128,
786 0,
787 XFS_TRANS_PERM_LOG_RES,
788 XFS_WRITE_LOG_COUNT))) {
789 cancelflags = 0;
790 goto error0;
791 }
792 cancelflags = XFS_TRANS_RELEASE_LOG_RES;
793 }
794
795 /*
796 * Read it from disk; xfs_dqread() takes care of
797 * all the necessary initialization of dquot's fields (locks, etc)
798 */
799 if ((error = xfs_qm_dqread(tp, id, dqp, flags))) {
800 /*
801 * This can happen if quotas got turned off (ESRCH),
802 * or if the dquot didn't exist on disk and we ask to
803 * allocate (ENOENT).
804 */
805 xfs_dqtrace_entry(dqp, "DQREAD FAIL");
806 cancelflags |= XFS_TRANS_ABORT;
807 goto error0;
808 }
809 if (tp) {
810 if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES,
811 NULL)))
812 goto error1;
813 }
814
815 *O_dqpp = dqp;
816 return (0);
817
818 error0:
819 ASSERT(error);
820 if (tp)
821 xfs_trans_cancel(tp, cancelflags);
822 error1:
823 xfs_qm_dqdestroy(dqp);
824 *O_dqpp = NULL;
825 return (error);
826}
827
828/*
829 * Lookup a dquot in the incore dquot hashtable. We keep two separate
830 * hashtables for user and group dquots; and, these are global tables
831 * inside the XQM, not per-filesystem tables.
832 * The hash chain must be locked by caller, and it is left locked
833 * on return. Returning dquot is locked.
834 */
835STATIC int
836xfs_qm_dqlookup(
837 xfs_mount_t *mp,
838 xfs_dqid_t id,
839 xfs_dqhash_t *qh,
840 xfs_dquot_t **O_dqpp)
841{
842 xfs_dquot_t *dqp;
843 uint flist_locked;
844 xfs_dquot_t *d;
845
846 ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));
847
848 flist_locked = B_FALSE;
849
850 /*
851 * Traverse the hashchain looking for a match
852 */
853 for (dqp = qh->qh_next; dqp != NULL; dqp = dqp->HL_NEXT) {
854 /*
855 * We already have the hashlock. We don't need the
856 * dqlock to look at the id field of the dquot, since the
857 * id can't be modified without the hashlock anyway.
858 */
859 if (INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id && dqp->q_mount == mp) {
860 xfs_dqtrace_entry(dqp, "DQFOUND BY LOOKUP");
861 /*
862 * All in core dquots must be on the dqlist of mp
863 */
864 ASSERT(dqp->MPL_PREVP != NULL);
865
866 xfs_dqlock(dqp);
867 if (dqp->q_nrefs == 0) {
868 ASSERT (XFS_DQ_IS_ON_FREELIST(dqp));
869 if (! xfs_qm_freelist_lock_nowait(xfs_Gqm)) {
870 xfs_dqtrace_entry(dqp, "DQLOOKUP: WANT");
871
872 /*
873 * We may have raced with dqreclaim_one()
874 * (and lost). So, flag that we don't
875 * want the dquot to be reclaimed.
876 */
877 dqp->dq_flags |= XFS_DQ_WANT;
878 xfs_dqunlock(dqp);
879 xfs_qm_freelist_lock(xfs_Gqm);
880 xfs_dqlock(dqp);
881 dqp->dq_flags &= ~(XFS_DQ_WANT);
882 }
883 flist_locked = B_TRUE;
884 }
885
886 /*
887 * id couldn't have changed; we had the hashlock all
888 * along
889 */
890 ASSERT(INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id);
891
892 if (flist_locked) {
893 if (dqp->q_nrefs != 0) {
894 xfs_qm_freelist_unlock(xfs_Gqm);
895 flist_locked = B_FALSE;
896 } else {
897 /*
898 * take it off the freelist
899 */
900 xfs_dqtrace_entry(dqp,
901 "DQLOOKUP: TAKEOFF FL");
902 XQM_FREELIST_REMOVE(dqp);
903 /* xfs_qm_freelist_print(&(xfs_Gqm->
904 qm_dqfreelist),
905 "after removal"); */
906 }
907 }
908
909 /*
910 * grab a reference
911 */
912 XFS_DQHOLD(dqp);
913
914 if (flist_locked)
915 xfs_qm_freelist_unlock(xfs_Gqm);
916 /*
917 * move the dquot to the front of the hashchain
918 */
919 ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));
920 if (dqp->HL_PREVP != &qh->qh_next) {
921 xfs_dqtrace_entry(dqp,
922 "DQLOOKUP: HASH MOVETOFRONT");
923 if ((d = dqp->HL_NEXT))
924 d->HL_PREVP = dqp->HL_PREVP;
925 *(dqp->HL_PREVP) = d;
926 d = qh->qh_next;
927 d->HL_PREVP = &dqp->HL_NEXT;
928 dqp->HL_NEXT = d;
929 dqp->HL_PREVP = &qh->qh_next;
930 qh->qh_next = dqp;
931 }
932 xfs_dqtrace_entry(dqp, "LOOKUP END");
933 *O_dqpp = dqp;
934 ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));
935 return (0);
936 }
937 }
938
939 *O_dqpp = NULL;
940 ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));
941 return (1);
942}
943
944/*
945 * Given the file system, inode OR id, and type (UDQUOT/GDQUOT), return a
946 * a locked dquot, doing an allocation (if requested) as needed.
947 * When both an inode and an id are given, the inode's id takes precedence.
948 * That is, if the id changes while we don't hold the ilock inside this
949 * function, the new dquot is returned, not necessarily the one requested
950 * in the id argument.
951 */
952int
953xfs_qm_dqget(
954 xfs_mount_t *mp,
955 xfs_inode_t *ip, /* locked inode (optional) */
956 xfs_dqid_t id, /* gid or uid, depending on type */
957 uint type, /* UDQUOT or GDQUOT */
958 uint flags, /* DQALLOC, DQSUSER, DQREPAIR, DOWARN */
959 xfs_dquot_t **O_dqpp) /* OUT : locked incore dquot */
960{
961 xfs_dquot_t *dqp;
962 xfs_dqhash_t *h;
963 uint version;
964 int error;
965
966 ASSERT(XFS_IS_QUOTA_RUNNING(mp));
967 if ((! XFS_IS_UQUOTA_ON(mp) && type == XFS_DQ_USER) ||
968 (! XFS_IS_GQUOTA_ON(mp) && type == XFS_DQ_GROUP)) {
969 return (ESRCH);
970 }
971 h = XFS_DQ_HASH(mp, id, type);
972
973#ifdef DEBUG
974 if (xfs_do_dqerror) {
975 if ((xfs_dqerror_target == mp->m_ddev_targp) &&
976 (xfs_dqreq_num++ % xfs_dqerror_mod) == 0) {
977 cmn_err(CE_DEBUG, "Returning error in dqget");
978 return (EIO);
979 }
980 }
981#endif
982
983 again:
984
985#ifdef DEBUG
986 ASSERT(type == XFS_DQ_USER || type == XFS_DQ_GROUP);
987 if (ip) {
988 ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
989 if (type == XFS_DQ_USER)
990 ASSERT(ip->i_udquot == NULL);
991 else
992 ASSERT(ip->i_gdquot == NULL);
993 }
994#endif
995 XFS_DQ_HASH_LOCK(h);
996
997 /*
998 * Look in the cache (hashtable).
999 * The chain is kept locked during lookup.
1000 */
1001 if (xfs_qm_dqlookup(mp, id, h, O_dqpp) == 0) {
1002 XQM_STATS_INC(xqmstats.xs_qm_dqcachehits);
1003 /*
1004 * The dquot was found, moved to the front of the chain,
1005 * taken off the freelist if it was on it, and locked
1006 * at this point. Just unlock the hashchain and return.
1007 */
1008 ASSERT(*O_dqpp);
1009 ASSERT(XFS_DQ_IS_LOCKED(*O_dqpp));
1010 XFS_DQ_HASH_UNLOCK(h);
1011 xfs_dqtrace_entry(*O_dqpp, "DQGET DONE (FROM CACHE)");
1012 return (0); /* success */
1013 }
1014 XQM_STATS_INC(xqmstats.xs_qm_dqcachemisses);
1015
1016 /*
1017 * Dquot cache miss. We don't want to keep the inode lock across
1018 * a (potential) disk read. Also we don't want to deal with the lock
1019 * ordering between quotainode and this inode. OTOH, dropping the inode
1020 * lock here means dealing with a chown that can happen before
1021 * we re-acquire the lock.
1022 */
1023 if (ip)
1024 xfs_iunlock(ip, XFS_ILOCK_EXCL);
1025 /*
1026 * Save the hashchain version stamp, and unlock the chain, so that
1027 * we don't keep the lock across a disk read
1028 */
1029 version = h->qh_version;
1030 XFS_DQ_HASH_UNLOCK(h);
1031
1032 /*
1033 * Allocate the dquot on the kernel heap, and read the ondisk
1034 * portion off the disk. Also, do all the necessary initialization
1035 * This can return ENOENT if dquot didn't exist on disk and we didn't
1036 * ask it to allocate; ESRCH if quotas got turned off suddenly.
1037 */
1038 if ((error = xfs_qm_idtodq(mp, id, type,
1039 flags & (XFS_QMOPT_DQALLOC|XFS_QMOPT_DQREPAIR|
1040 XFS_QMOPT_DOWARN),
1041 &dqp))) {
1042 if (ip)
1043 xfs_ilock(ip, XFS_ILOCK_EXCL);
1044 return (error);
1045 }
1046
1047 /*
1048 * See if this is mount code calling to look at the overall quota limits
1049 * which are stored in the id == 0 user or group's dquot.
1050 * Since we may not have done a quotacheck by this point, just return
1051 * the dquot without attaching it to any hashtables, lists, etc, or even
1052 * taking a reference.
1053 * The caller must dqdestroy this once done.
1054 */
1055 if (flags & XFS_QMOPT_DQSUSER) {
1056 ASSERT(id == 0);
1057 ASSERT(! ip);
1058 goto dqret;
1059 }
1060
1061 /*
1062 * Dquot lock comes after hashlock in the lock ordering
1063 */
1064 if (ip) {
1065 xfs_ilock(ip, XFS_ILOCK_EXCL);
1066 if (! XFS_IS_DQTYPE_ON(mp, type)) {
1067 /* inode stays locked on return */
1068 xfs_qm_dqdestroy(dqp);
1069 return XFS_ERROR(ESRCH);
1070 }
1071 /*
1072 * A dquot could be attached to this inode by now, since
1073 * we had dropped the ilock.
1074 */
1075 if (type == XFS_DQ_USER) {
1076 if (ip->i_udquot) {
1077 xfs_qm_dqdestroy(dqp);
1078 dqp = ip->i_udquot;
1079 xfs_dqlock(dqp);
1080 goto dqret;
1081 }
1082 } else {
1083 if (ip->i_gdquot) {
1084 xfs_qm_dqdestroy(dqp);
1085 dqp = ip->i_gdquot;
1086 xfs_dqlock(dqp);
1087 goto dqret;
1088 }
1089 }
1090 }
1091
1092 /*
1093 * Hashlock comes after ilock in lock order
1094 */
1095 XFS_DQ_HASH_LOCK(h);
1096 if (version != h->qh_version) {
1097 xfs_dquot_t *tmpdqp;
1098 /*
1099 * Now, see if somebody else put the dquot in the
1100 * hashtable before us. This can happen because we didn't
1101 * keep the hashchain lock. We don't have to worry about
1102 * lock order between the two dquots here since dqp isn't
1103 * on any findable lists yet.
1104 */
1105 if (xfs_qm_dqlookup(mp, id, h, &tmpdqp) == 0) {
1106 /*
1107 * Duplicate found. Just throw away the new dquot
1108 * and start over.
1109 */
1110 xfs_qm_dqput(tmpdqp);
1111 XFS_DQ_HASH_UNLOCK(h);
1112 xfs_qm_dqdestroy(dqp);
1113 XQM_STATS_INC(xqmstats.xs_qm_dquot_dups);
1114 goto again;
1115 }
1116 }
1117
1118 /*
1119 * Put the dquot at the beginning of the hash-chain and mp's list
1120 * LOCK ORDER: hashlock, freelistlock, mplistlock, udqlock, gdqlock ..
1121 */
1122 ASSERT(XFS_DQ_IS_HASH_LOCKED(h));
1123 dqp->q_hash = h;
1124 XQM_HASHLIST_INSERT(h, dqp);
1125
1126 /*
1127 * Attach this dquot to this filesystem's list of all dquots,
1128 * kept inside the mount structure in m_quotainfo field
1129 */
1130 xfs_qm_mplist_lock(mp);
1131
1132 /*
1133 * We return a locked dquot to the caller, with a reference taken
1134 */
1135 xfs_dqlock(dqp);
1136 dqp->q_nrefs = 1;
1137
1138 XQM_MPLIST_INSERT(&(XFS_QI_MPL_LIST(mp)), dqp);
1139
1140 xfs_qm_mplist_unlock(mp);
1141 XFS_DQ_HASH_UNLOCK(h);
1142 dqret:
1143 ASSERT((ip == NULL) || XFS_ISLOCKED_INODE_EXCL(ip));
1144 xfs_dqtrace_entry(dqp, "DQGET DONE");
1145 *O_dqpp = dqp;
1146 return (0);
1147}
1148
1149
1150/*
1151 * Release a reference to the dquot (decrement ref-count)
1152 * and unlock it. If there is a group quota attached to this
1153 * dquot, carefully release that too without tripping over
1154 * deadlocks'n'stuff.
1155 */
1156void
1157xfs_qm_dqput(
1158 xfs_dquot_t *dqp)
1159{
1160 xfs_dquot_t *gdqp;
1161
1162 ASSERT(dqp->q_nrefs > 0);
1163 ASSERT(XFS_DQ_IS_LOCKED(dqp));
1164 xfs_dqtrace_entry(dqp, "DQPUT");
1165
1166 if (dqp->q_nrefs != 1) {
1167 dqp->q_nrefs--;
1168 xfs_dqunlock(dqp);
1169 return;
1170 }
1171
1172 /*
1173 * drop the dqlock and acquire the freelist and dqlock
1174 * in the right order; but try to get it out-of-order first
1175 */
1176 if (! xfs_qm_freelist_lock_nowait(xfs_Gqm)) {
1177 xfs_dqtrace_entry(dqp, "DQPUT: FLLOCK-WAIT");
1178 xfs_dqunlock(dqp);
1179 xfs_qm_freelist_lock(xfs_Gqm);
1180 xfs_dqlock(dqp);
1181 }
1182
1183 while (1) {
1184 gdqp = NULL;
1185
1186 /* We can't depend on nrefs being == 1 here */
1187 if (--dqp->q_nrefs == 0) {
1188 xfs_dqtrace_entry(dqp, "DQPUT: ON FREELIST");
1189 /*
1190 * insert at end of the freelist.
1191 */
1192 XQM_FREELIST_INSERT(&(xfs_Gqm->qm_dqfreelist), dqp);
1193
1194 /*
1195 * If we just added a udquot to the freelist, then
1196 * we want to release the gdquot reference that
1197 * it (probably) has. Otherwise it'll keep the
1198 * gdquot from getting reclaimed.
1199 */
1200 if ((gdqp = dqp->q_gdquot)) {
1201 /*
1202 * Avoid a recursive dqput call
1203 */
1204 xfs_dqlock(gdqp);
1205 dqp->q_gdquot = NULL;
1206 }
1207
1208 /* xfs_qm_freelist_print(&(xfs_Gqm->qm_dqfreelist),
1209 "@@@@@++ Free list (after append) @@@@@+");
1210 */
1211 }
1212 xfs_dqunlock(dqp);
1213
1214 /*
1215 * If we had a group quota inside the user quota as a hint,
1216 * release it now.
1217 */
1218 if (! gdqp)
1219 break;
1220 dqp = gdqp;
1221 }
1222 xfs_qm_freelist_unlock(xfs_Gqm);
1223}
1224
1225/*
1226 * Release a dquot. Flush it if dirty, then dqput() it.
1227 * dquot must not be locked.
1228 */
1229void
1230xfs_qm_dqrele(
1231 xfs_dquot_t *dqp)
1232{
1233 ASSERT(dqp);
1234 xfs_dqtrace_entry(dqp, "DQRELE");
1235
1236 xfs_dqlock(dqp);
1237 /*
1238 * We don't care to flush it if the dquot is dirty here.
1239 * That will create stutters that we want to avoid.
1240 * Instead we do a delayed write when we try to reclaim
1241 * a dirty dquot. Also xfs_sync will take part of the burden...
1242 */
1243 xfs_qm_dqput(dqp);
1244}
1245
1246
1247/*
1248 * Write a modified dquot to disk.
1249 * The dquot must be locked and the flush lock too taken by caller.
1250 * The flush lock will not be unlocked until the dquot reaches the disk,
1251 * but the dquot is free to be unlocked and modified by the caller
1252 * in the interim. Dquot is still locked on return. This behavior is
1253 * identical to that of inodes.
1254 */
1255int
1256xfs_qm_dqflush(
1257 xfs_dquot_t *dqp,
1258 uint flags)
1259{
1260 xfs_mount_t *mp;
1261 xfs_buf_t *bp;
1262 xfs_disk_dquot_t *ddqp;
1263 int error;
1264 SPLDECL(s);
1265
1266 ASSERT(XFS_DQ_IS_LOCKED(dqp));
1267 ASSERT(XFS_DQ_IS_FLUSH_LOCKED(dqp));
1268 xfs_dqtrace_entry(dqp, "DQFLUSH");
1269
1270 /*
1271 * If not dirty, nada.
1272 */
1273 if (!XFS_DQ_IS_DIRTY(dqp)) {
1274 xfs_dqfunlock(dqp);
1275 return (0);
1276 }
1277
1278 /*
1279 * Cant flush a pinned dquot. Wait for it.
1280 */
1281 xfs_qm_dqunpin_wait(dqp);
1282
1283 /*
1284 * This may have been unpinned because the filesystem is shutting
1285 * down forcibly. If that's the case we must not write this dquot
1286 * to disk, because the log record didn't make it to disk!
1287 */
1288 if (XFS_FORCED_SHUTDOWN(dqp->q_mount)) {
1289 dqp->dq_flags &= ~(XFS_DQ_DIRTY);
1290 xfs_dqfunlock(dqp);
1291 return XFS_ERROR(EIO);
1292 }
1293
1294 /*
1295 * Get the buffer containing the on-disk dquot
1296 * We don't need a transaction envelope because we know that the
1297 * the ondisk-dquot has already been allocated for.
1298 */
1299 if ((error = xfs_qm_dqtobp(NULL, dqp, &ddqp, &bp, XFS_QMOPT_DOWARN))) {
1300 xfs_dqtrace_entry(dqp, "DQTOBP FAIL");
1301 ASSERT(error != ENOENT);
1302 /*
1303 * Quotas could have gotten turned off (ESRCH)
1304 */
1305 xfs_dqfunlock(dqp);
1306 return (error);
1307 }
1308
1309 if (xfs_qm_dqcheck(&dqp->q_core, INT_GET(ddqp->d_id, ARCH_CONVERT), 0, XFS_QMOPT_DOWARN,
1310 "dqflush (incore copy)")) {
1311 xfs_force_shutdown(dqp->q_mount, XFS_CORRUPT_INCORE);
1312 return XFS_ERROR(EIO);
1313 }
1314
1315 /* This is the only portion of data that needs to persist */
1316 memcpy(ddqp, &(dqp->q_core), sizeof(xfs_disk_dquot_t));
1317
1318 /*
1319 * Clear the dirty field and remember the flush lsn for later use.
1320 */
1321 dqp->dq_flags &= ~(XFS_DQ_DIRTY);
1322 mp = dqp->q_mount;
1323
1324 /* lsn is 64 bits */
1325 AIL_LOCK(mp, s);
1326 dqp->q_logitem.qli_flush_lsn = dqp->q_logitem.qli_item.li_lsn;
1327 AIL_UNLOCK(mp, s);
1328
1329 /*
1330 * Attach an iodone routine so that we can remove this dquot from the
1331 * AIL and release the flush lock once the dquot is synced to disk.
1332 */
1333 xfs_buf_attach_iodone(bp, (void(*)(xfs_buf_t *, xfs_log_item_t *))
1334 xfs_qm_dqflush_done, &(dqp->q_logitem.qli_item));
1335 /*
1336 * If the buffer is pinned then push on the log so we won't
1337 * get stuck waiting in the write for too long.
1338 */
1339 if (XFS_BUF_ISPINNED(bp)) {
1340 xfs_dqtrace_entry(dqp, "DQFLUSH LOG FORCE");
1341 xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE);
1342 }
1343
1344 if (flags & XFS_QMOPT_DELWRI) {
1345 xfs_bdwrite(mp, bp);
1346 } else if (flags & XFS_QMOPT_ASYNC) {
1347 xfs_bawrite(mp, bp);
1348 } else {
1349 error = xfs_bwrite(mp, bp);
1350 }
1351 xfs_dqtrace_entry(dqp, "DQFLUSH END");
1352 /*
1353 * dqp is still locked, but caller is free to unlock it now.
1354 */
1355 return (error);
1356
1357}
1358
1359/*
1360 * This is the dquot flushing I/O completion routine. It is called
1361 * from interrupt level when the buffer containing the dquot is
1362 * flushed to disk. It is responsible for removing the dquot logitem
1363 * from the AIL if it has not been re-logged, and unlocking the dquot's
1364 * flush lock. This behavior is very similar to that of inodes..
1365 */
1366/*ARGSUSED*/
1367STATIC void
1368xfs_qm_dqflush_done(
1369 xfs_buf_t *bp,
1370 xfs_dq_logitem_t *qip)
1371{
1372 xfs_dquot_t *dqp;
1373 SPLDECL(s);
1374
1375 dqp = qip->qli_dquot;
1376
1377 /*
1378 * We only want to pull the item from the AIL if its
1379 * location in the log has not changed since we started the flush.
1380 * Thus, we only bother if the dquot's lsn has
1381 * not changed. First we check the lsn outside the lock
1382 * since it's cheaper, and then we recheck while
1383 * holding the lock before removing the dquot from the AIL.
1384 */
1385 if ((qip->qli_item.li_flags & XFS_LI_IN_AIL) &&
1386 qip->qli_item.li_lsn == qip->qli_flush_lsn) {
1387
1388 AIL_LOCK(dqp->q_mount, s);
1389 /*
1390 * xfs_trans_delete_ail() drops the AIL lock.
1391 */
1392 if (qip->qli_item.li_lsn == qip->qli_flush_lsn)
1393 xfs_trans_delete_ail(dqp->q_mount,
1394 (xfs_log_item_t*)qip, s);
1395 else
1396 AIL_UNLOCK(dqp->q_mount, s);
1397 }
1398
1399 /*
1400 * Release the dq's flush lock since we're done with it.
1401 */
1402 xfs_dqfunlock(dqp);
1403}
1404
1405
1406int
1407xfs_qm_dqflock_nowait(
1408 xfs_dquot_t *dqp)
1409{
1410 int locked;
1411
1412 locked = cpsema(&((dqp)->q_flock));
1413
1414 /* XXX ifdef these out */
1415 if (locked)
1416 (dqp)->dq_flags |= XFS_DQ_FLOCKED;
1417 return (locked);
1418}
1419
1420
1421int
1422xfs_qm_dqlock_nowait(
1423 xfs_dquot_t *dqp)
1424{
1425 return (mutex_trylock(&((dqp)->q_qlock)));
1426}
1427
1428void
1429xfs_dqlock(
1430 xfs_dquot_t *dqp)
1431{
1432 mutex_lock(&(dqp->q_qlock), PINOD);
1433}
1434
1435void
1436xfs_dqunlock(
1437 xfs_dquot_t *dqp)
1438{
1439 mutex_unlock(&(dqp->q_qlock));
1440 if (dqp->q_logitem.qli_dquot == dqp) {
1441 /* Once was dqp->q_mount, but might just have been cleared */
1442 xfs_trans_unlocked_item(dqp->q_logitem.qli_item.li_mountp,
1443 (xfs_log_item_t*)&(dqp->q_logitem));
1444 }
1445}
1446
1447
1448void
1449xfs_dqunlock_nonotify(
1450 xfs_dquot_t *dqp)
1451{
1452 mutex_unlock(&(dqp->q_qlock));
1453}
1454
1455void
1456xfs_dqlock2(
1457 xfs_dquot_t *d1,
1458 xfs_dquot_t *d2)
1459{
1460 if (d1 && d2) {
1461 ASSERT(d1 != d2);
1462 if (INT_GET(d1->q_core.d_id, ARCH_CONVERT) > INT_GET(d2->q_core.d_id, ARCH_CONVERT)) {
1463 xfs_dqlock(d2);
1464 xfs_dqlock(d1);
1465 } else {
1466 xfs_dqlock(d1);
1467 xfs_dqlock(d2);
1468 }
1469 } else {
1470 if (d1) {
1471 xfs_dqlock(d1);
1472 } else if (d2) {
1473 xfs_dqlock(d2);
1474 }
1475 }
1476}
1477
1478
1479/*
1480 * Take a dquot out of the mount's dqlist as well as the hashlist.
1481 * This is called via unmount as well as quotaoff, and the purge
1482 * will always succeed unless there are soft (temp) references
1483 * outstanding.
1484 *
1485 * This returns 0 if it was purged, 1 if it wasn't. It's not an error code
1486 * that we're returning! XXXsup - not cool.
1487 */
1488/* ARGSUSED */
1489int
1490xfs_qm_dqpurge(
1491 xfs_dquot_t *dqp,
1492 uint flags)
1493{
1494 xfs_dqhash_t *thishash;
1495 xfs_mount_t *mp;
1496
1497 mp = dqp->q_mount;
1498
1499 ASSERT(XFS_QM_IS_MPLIST_LOCKED(mp));
1500 ASSERT(XFS_DQ_IS_HASH_LOCKED(dqp->q_hash));
1501
1502 xfs_dqlock(dqp);
1503 /*
1504 * We really can't afford to purge a dquot that is
1505 * referenced, because these are hard refs.
1506 * It shouldn't happen in general because we went thru _all_ inodes in
1507 * dqrele_all_inodes before calling this and didn't let the mountlock go.
1508 * However it is possible that we have dquots with temporary
1509 * references that are not attached to an inode. e.g. see xfs_setattr().
1510 */
1511 if (dqp->q_nrefs != 0) {
1512 xfs_dqunlock(dqp);
1513 XFS_DQ_HASH_UNLOCK(dqp->q_hash);
1514 return (1);
1515 }
1516
1517 ASSERT(XFS_DQ_IS_ON_FREELIST(dqp));
1518
1519 /*
1520 * If we're turning off quotas, we have to make sure that, for
1521 * example, we don't delete quota disk blocks while dquots are
1522 * in the process of getting written to those disk blocks.
1523 * This dquot might well be on AIL, and we can't leave it there
1524 * if we're turning off quotas. Basically, we need this flush
1525 * lock, and are willing to block on it.
1526 */
1527 if (! xfs_qm_dqflock_nowait(dqp)) {
1528 /*
1529 * Block on the flush lock after nudging dquot buffer,
1530 * if it is incore.
1531 */
1532 xfs_qm_dqflock_pushbuf_wait(dqp);
1533 }
1534
1535 /*
1536 * XXXIf we're turning this type of quotas off, we don't care
1537 * about the dirty metadata sitting in this dquot. OTOH, if
1538 * we're unmounting, we do care, so we flush it and wait.
1539 */
1540 if (XFS_DQ_IS_DIRTY(dqp)) {
1541 xfs_dqtrace_entry(dqp, "DQPURGE ->DQFLUSH: DQDIRTY");
1542 /* dqflush unlocks dqflock */
1543 /*
1544 * Given that dqpurge is a very rare occurrence, it is OK
1545 * that we're holding the hashlist and mplist locks
1546 * across the disk write. But, ... XXXsup
1547 *
1548 * We don't care about getting disk errors here. We need
1549 * to purge this dquot anyway, so we go ahead regardless.
1550 */
1551 (void) xfs_qm_dqflush(dqp, XFS_QMOPT_SYNC);
1552 xfs_dqflock(dqp);
1553 }
1554 ASSERT(dqp->q_pincount == 0);
1555 ASSERT(XFS_FORCED_SHUTDOWN(mp) ||
1556 !(dqp->q_logitem.qli_item.li_flags & XFS_LI_IN_AIL));
1557
1558 thishash = dqp->q_hash;
1559 XQM_HASHLIST_REMOVE(thishash, dqp);
1560 XQM_MPLIST_REMOVE(&(XFS_QI_MPL_LIST(mp)), dqp);
1561 /*
1562 * XXX Move this to the front of the freelist, if we can get the
1563 * freelist lock.
1564 */
1565 ASSERT(XFS_DQ_IS_ON_FREELIST(dqp));
1566
1567 dqp->q_mount = NULL;
1568 dqp->q_hash = NULL;
1569 dqp->dq_flags = XFS_DQ_INACTIVE;
1570 memset(&dqp->q_core, 0, sizeof(dqp->q_core));
1571 xfs_dqfunlock(dqp);
1572 xfs_dqunlock(dqp);
1573 XFS_DQ_HASH_UNLOCK(thishash);
1574 return (0);
1575}
1576
1577
1578#ifdef QUOTADEBUG
1579void
1580xfs_qm_dqprint(xfs_dquot_t *dqp)
1581{
1582 cmn_err(CE_DEBUG, "-----------KERNEL DQUOT----------------");
1583 cmn_err(CE_DEBUG, "---- dquotID = %d",
1584 (int)INT_GET(dqp->q_core.d_id, ARCH_CONVERT));
1585 cmn_err(CE_DEBUG, "---- type = %s",
1586 XFS_QM_ISUDQ(dqp) ? "USR" : "GRP");
1587 cmn_err(CE_DEBUG, "---- fs = 0x%p", dqp->q_mount);
1588 cmn_err(CE_DEBUG, "---- blkno = 0x%x", (int) dqp->q_blkno);
1589 cmn_err(CE_DEBUG, "---- boffset = 0x%x", (int) dqp->q_bufoffset);
1590 cmn_err(CE_DEBUG, "---- blkhlimit = %Lu (0x%x)",
1591 INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT),
1592 (int) INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT));
1593 cmn_err(CE_DEBUG, "---- blkslimit = %Lu (0x%x)",
1594 INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT),
1595 (int)INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT));
1596 cmn_err(CE_DEBUG, "---- inohlimit = %Lu (0x%x)",
1597 INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT),
1598 (int)INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT));
1599 cmn_err(CE_DEBUG, "---- inoslimit = %Lu (0x%x)",
1600 INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT),
1601 (int)INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT));
1602 cmn_err(CE_DEBUG, "---- bcount = %Lu (0x%x)",
1603 INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT),
1604 (int)INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT));
1605 cmn_err(CE_DEBUG, "---- icount = %Lu (0x%x)",
1606 INT_GET(dqp->q_core.d_icount, ARCH_CONVERT),
1607 (int)INT_GET(dqp->q_core.d_icount, ARCH_CONVERT));
1608 cmn_err(CE_DEBUG, "---- btimer = %d",
1609 (int)INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT));
1610 cmn_err(CE_DEBUG, "---- itimer = %d",
1611 (int)INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT));
1612 cmn_err(CE_DEBUG, "---------------------------");
1613}
1614#endif
1615
1616/*
1617 * Give the buffer a little push if it is incore and
1618 * wait on the flush lock.
1619 */
1620void
1621xfs_qm_dqflock_pushbuf_wait(
1622 xfs_dquot_t *dqp)
1623{
1624 xfs_buf_t *bp;
1625
1626 /*
1627 * Check to see if the dquot has been flushed delayed
1628 * write. If so, grab its buffer and send it
1629 * out immediately. We'll be able to acquire
1630 * the flush lock when the I/O completes.
1631 */
1632 bp = xfs_incore(dqp->q_mount->m_ddev_targp, dqp->q_blkno,
1633 XFS_QI_DQCHUNKLEN(dqp->q_mount),
1634 XFS_INCORE_TRYLOCK);
1635 if (bp != NULL) {
1636 if (XFS_BUF_ISDELAYWRITE(bp)) {
1637 if (XFS_BUF_ISPINNED(bp)) {
1638 xfs_log_force(dqp->q_mount,
1639 (xfs_lsn_t)0,
1640 XFS_LOG_FORCE);
1641 }
1642 xfs_bawrite(dqp->q_mount, bp);
1643 } else {
1644 xfs_buf_relse(bp);
1645 }
1646 }
1647 xfs_dqflock(dqp);
1648}
diff --git a/fs/xfs/quota/xfs_dquot.h b/fs/xfs/quota/xfs_dquot.h
new file mode 100644
index 000000000000..0c3fe3175baa
--- /dev/null
+++ b/fs/xfs/quota/xfs_dquot.h
@@ -0,0 +1,224 @@
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#ifndef __XFS_DQUOT_H__
33#define __XFS_DQUOT_H__
34
35/*
36 * Dquots are structures that hold quota information about a user or a group,
37 * much like inodes are for files. In fact, dquots share many characteristics
38 * with inodes. However, dquots can also be a centralized resource, relative
39 * to a collection of inodes. In this respect, dquots share some characteristics
40 * of the superblock.
41 * XFS dquots exploit both those in its algorithms. They make every attempt
42 * to not be a bottleneck when quotas are on and have minimal impact, if any,
43 * when quotas are off.
44 */
45
46/*
47 * The hash chain headers (hash buckets)
48 */
49typedef struct xfs_dqhash {
50 struct xfs_dquot *qh_next;
51 mutex_t qh_lock;
52 uint qh_version; /* ever increasing version */
53 uint qh_nelems; /* number of dquots on the list */
54} xfs_dqhash_t;
55
56typedef struct xfs_dqlink {
57 struct xfs_dquot *ql_next; /* forward link */
58 struct xfs_dquot **ql_prevp; /* pointer to prev ql_next */
59} xfs_dqlink_t;
60
61struct xfs_mount;
62struct xfs_trans;
63
64/*
65 * This is the marker which is designed to occupy the first few
66 * bytes of the xfs_dquot_t structure. Even inside this, the freelist pointers
67 * must come first.
68 * This serves as the marker ("sentinel") when we have to restart list
69 * iterations because of locking considerations.
70 */
71typedef struct xfs_dqmarker {
72 struct xfs_dquot*dqm_flnext; /* link to freelist: must be first */
73 struct xfs_dquot*dqm_flprev;
74 xfs_dqlink_t dqm_mplist; /* link to mount's list of dquots */
75 xfs_dqlink_t dqm_hashlist; /* link to the hash chain */
76 uint dqm_flags; /* various flags (XFS_DQ_*) */
77} xfs_dqmarker_t;
78
79/*
80 * The incore dquot structure
81 */
82typedef struct xfs_dquot {
83 xfs_dqmarker_t q_lists; /* list ptrs, q_flags (marker) */
84 xfs_dqhash_t *q_hash; /* the hashchain header */
85 struct xfs_mount*q_mount; /* filesystem this relates to */
86 struct xfs_trans*q_transp; /* trans this belongs to currently */
87 uint q_nrefs; /* # active refs from inodes */
88 xfs_daddr_t q_blkno; /* blkno of dquot buffer */
89 int q_bufoffset; /* off of dq in buffer (# dquots) */
90 xfs_fileoff_t q_fileoffset; /* offset in quotas file */
91
92 struct xfs_dquot*q_gdquot; /* group dquot, hint only */
93 xfs_disk_dquot_t q_core; /* actual usage & quotas */
94 xfs_dq_logitem_t q_logitem; /* dquot log item */
95 xfs_qcnt_t q_res_bcount; /* total regular nblks used+reserved */
96 xfs_qcnt_t q_res_icount; /* total inos allocd+reserved */
97 xfs_qcnt_t q_res_rtbcount;/* total realtime blks used+reserved */
98 mutex_t q_qlock; /* quota lock */
99 sema_t q_flock; /* flush lock */
100 uint q_pincount; /* pin count for this dquot */
101 sv_t q_pinwait; /* sync var for pinning */
102#ifdef XFS_DQUOT_TRACE
103 struct ktrace *q_trace; /* trace header structure */
104#endif
105} xfs_dquot_t;
106
107
108#define dq_flnext q_lists.dqm_flnext
109#define dq_flprev q_lists.dqm_flprev
110#define dq_mplist q_lists.dqm_mplist
111#define dq_hashlist q_lists.dqm_hashlist
112#define dq_flags q_lists.dqm_flags
113
114#define XFS_DQHOLD(dqp) ((dqp)->q_nrefs++)
115
116/*
117 * Quota Accounting flags
118 */
119#define XFS_ALL_QUOTA_ACCT (XFS_UQUOTA_ACCT | XFS_GQUOTA_ACCT)
120#define XFS_ALL_QUOTA_ENFD (XFS_UQUOTA_ENFD | XFS_GQUOTA_ENFD)
121#define XFS_ALL_QUOTA_CHKD (XFS_UQUOTA_CHKD | XFS_GQUOTA_CHKD)
122#define XFS_ALL_QUOTA_ACTV (XFS_UQUOTA_ACTIVE | XFS_GQUOTA_ACTIVE)
123#define XFS_ALL_QUOTA_ACCT_ENFD (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
124 XFS_GQUOTA_ACCT|XFS_GQUOTA_ENFD)
125
126#define XFS_IS_QUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_ALL_QUOTA_ACCT)
127#define XFS_IS_UQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_UQUOTA_ACCT)
128#define XFS_IS_GQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_GQUOTA_ACCT)
129
130/*
131 * Quota Limit Enforcement flags
132 */
133#define XFS_IS_QUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_ALL_QUOTA_ENFD)
134#define XFS_IS_UQUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_UQUOTA_ENFD)
135#define XFS_IS_GQUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_GQUOTA_ENFD)
136
137#ifdef DEBUG
138static inline int
139XFS_DQ_IS_LOCKED(xfs_dquot_t *dqp)
140{
141 if (mutex_trylock(&dqp->q_qlock)) {
142 mutex_unlock(&dqp->q_qlock);
143 return 0;
144 }
145 return 1;
146}
147#endif
148
149
150/*
151 * The following three routines simply manage the q_flock
152 * semaphore embedded in the dquot. This semaphore synchronizes
153 * processes attempting to flush the in-core dquot back to disk.
154 */
155#define xfs_dqflock(dqp) { psema(&((dqp)->q_flock), PINOD | PRECALC);\
156 (dqp)->dq_flags |= XFS_DQ_FLOCKED; }
157#define xfs_dqfunlock(dqp) { ASSERT(valusema(&((dqp)->q_flock)) <= 0); \
158 vsema(&((dqp)->q_flock)); \
159 (dqp)->dq_flags &= ~(XFS_DQ_FLOCKED); }
160
161#define XFS_DQ_PINLOCK(dqp) mutex_spinlock( \
162 &(XFS_DQ_TO_QINF(dqp)->qi_pinlock))
163#define XFS_DQ_PINUNLOCK(dqp, s) mutex_spinunlock( \
164 &(XFS_DQ_TO_QINF(dqp)->qi_pinlock), s)
165
166#define XFS_DQ_IS_FLUSH_LOCKED(dqp) (valusema(&((dqp)->q_flock)) <= 0)
167#define XFS_DQ_IS_ON_FREELIST(dqp) ((dqp)->dq_flnext != (dqp))
168#define XFS_DQ_IS_DIRTY(dqp) ((dqp)->dq_flags & XFS_DQ_DIRTY)
169#define XFS_QM_ISUDQ(dqp) ((dqp)->dq_flags & XFS_DQ_USER)
170#define XFS_DQ_TO_QINF(dqp) ((dqp)->q_mount->m_quotainfo)
171#define XFS_DQ_TO_QIP(dqp) (XFS_QM_ISUDQ(dqp) ? \
172 XFS_DQ_TO_QINF(dqp)->qi_uquotaip : \
173 XFS_DQ_TO_QINF(dqp)->qi_gquotaip)
174
175#define XFS_IS_THIS_QUOTA_OFF(d) (! (XFS_QM_ISUDQ(d) ? \
176 (XFS_IS_UQUOTA_ON((d)->q_mount)) : \
177 (XFS_IS_GQUOTA_ON((d)->q_mount))))
178
179#ifdef XFS_DQUOT_TRACE
180/*
181 * Dquot Tracing stuff.
182 */
183#define DQUOT_TRACE_SIZE 64
184#define DQUOT_KTRACE_ENTRY 1
185
186extern void __xfs_dqtrace_entry(xfs_dquot_t *dqp, char *func,
187 void *, xfs_inode_t *);
188#define xfs_dqtrace_entry_ino(a,b,ip) \
189 __xfs_dqtrace_entry((a), (b), (void*)__return_address, (ip))
190#define xfs_dqtrace_entry(a,b) \
191 __xfs_dqtrace_entry((a), (b), (void*)__return_address, NULL)
192#else
193#define xfs_dqtrace_entry(a,b)
194#define xfs_dqtrace_entry_ino(a,b,ip)
195#endif
196
197#ifdef QUOTADEBUG
198extern void xfs_qm_dqprint(xfs_dquot_t *);
199#else
200#define xfs_qm_dqprint(a)
201#endif
202
203extern void xfs_qm_dqdestroy(xfs_dquot_t *);
204extern int xfs_qm_dqflush(xfs_dquot_t *, uint);
205extern int xfs_qm_dqpurge(xfs_dquot_t *, uint);
206extern void xfs_qm_dqunpin_wait(xfs_dquot_t *);
207extern int xfs_qm_dqlock_nowait(xfs_dquot_t *);
208extern int xfs_qm_dqflock_nowait(xfs_dquot_t *);
209extern void xfs_qm_dqflock_pushbuf_wait(xfs_dquot_t *dqp);
210extern void xfs_qm_adjust_dqtimers(xfs_mount_t *,
211 xfs_disk_dquot_t *);
212extern void xfs_qm_adjust_dqlimits(xfs_mount_t *,
213 xfs_disk_dquot_t *);
214extern int xfs_qm_dqwarn(xfs_disk_dquot_t *, uint);
215extern int xfs_qm_dqget(xfs_mount_t *, xfs_inode_t *,
216 xfs_dqid_t, uint, uint, xfs_dquot_t **);
217extern void xfs_qm_dqput(xfs_dquot_t *);
218extern void xfs_qm_dqrele(xfs_dquot_t *);
219extern void xfs_dqlock(xfs_dquot_t *);
220extern void xfs_dqlock2(xfs_dquot_t *, xfs_dquot_t *);
221extern void xfs_dqunlock(xfs_dquot_t *);
222extern void xfs_dqunlock_nonotify(xfs_dquot_t *);
223
224#endif /* __XFS_DQUOT_H__ */
diff --git a/fs/xfs/quota/xfs_dquot_item.c b/fs/xfs/quota/xfs_dquot_item.c
new file mode 100644
index 000000000000..a5425ee6e7bd
--- /dev/null
+++ b/fs/xfs/quota/xfs_dquot_item.c
@@ -0,0 +1,715 @@
1/*
2 * Copyright (c) 2000-2003 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
71
72/*
73 * returns the number of iovecs needed to log the given dquot item.
74 */
75/* ARGSUSED */
76STATIC uint
77xfs_qm_dquot_logitem_size(
78 xfs_dq_logitem_t *logitem)
79{
80 /*
81 * we need only two iovecs, one for the format, one for the real thing
82 */
83 return (2);
84}
85
86/*
87 * fills in the vector of log iovecs for the given dquot log item.
88 */
89STATIC void
90xfs_qm_dquot_logitem_format(
91 xfs_dq_logitem_t *logitem,
92 xfs_log_iovec_t *logvec)
93{
94 ASSERT(logitem);
95 ASSERT(logitem->qli_dquot);
96
97 logvec->i_addr = (xfs_caddr_t)&logitem->qli_format;
98 logvec->i_len = sizeof(xfs_dq_logformat_t);
99 logvec++;
100 logvec->i_addr = (xfs_caddr_t)&logitem->qli_dquot->q_core;
101 logvec->i_len = sizeof(xfs_disk_dquot_t);
102
103 ASSERT(2 == logitem->qli_item.li_desc->lid_size);
104 logitem->qli_format.qlf_size = 2;
105
106}
107
108/*
109 * Increment the pin count of the given dquot.
110 * This value is protected by pinlock spinlock in the xQM structure.
111 */
112STATIC void
113xfs_qm_dquot_logitem_pin(
114 xfs_dq_logitem_t *logitem)
115{
116 unsigned long s;
117 xfs_dquot_t *dqp;
118
119 dqp = logitem->qli_dquot;
120 ASSERT(XFS_DQ_IS_LOCKED(dqp));
121 s = XFS_DQ_PINLOCK(dqp);
122 dqp->q_pincount++;
123 XFS_DQ_PINUNLOCK(dqp, s);
124}
125
126/*
127 * Decrement the pin count of the given dquot, and wake up
128 * anyone in xfs_dqwait_unpin() if the count goes to 0. The
129 * dquot must have been previously pinned with a call to xfs_dqpin().
130 */
131/* ARGSUSED */
132STATIC void
133xfs_qm_dquot_logitem_unpin(
134 xfs_dq_logitem_t *logitem,
135 int stale)
136{
137 unsigned long s;
138 xfs_dquot_t *dqp;
139
140 dqp = logitem->qli_dquot;
141 ASSERT(dqp->q_pincount > 0);
142 s = XFS_DQ_PINLOCK(dqp);
143 dqp->q_pincount--;
144 if (dqp->q_pincount == 0) {
145 sv_broadcast(&dqp->q_pinwait);
146 }
147 XFS_DQ_PINUNLOCK(dqp, s);
148}
149
150/* ARGSUSED */
151STATIC void
152xfs_qm_dquot_logitem_unpin_remove(
153 xfs_dq_logitem_t *logitem,
154 xfs_trans_t *tp)
155{
156 xfs_qm_dquot_logitem_unpin(logitem, 0);
157}
158
159/*
160 * Given the logitem, this writes the corresponding dquot entry to disk
161 * asynchronously. This is called with the dquot entry securely locked;
162 * we simply get xfs_qm_dqflush() to do the work, and unlock the dquot
163 * at the end.
164 */
165STATIC void
166xfs_qm_dquot_logitem_push(
167 xfs_dq_logitem_t *logitem)
168{
169 xfs_dquot_t *dqp;
170
171 dqp = logitem->qli_dquot;
172
173 ASSERT(XFS_DQ_IS_LOCKED(dqp));
174 ASSERT(XFS_DQ_IS_FLUSH_LOCKED(dqp));
175
176 /*
177 * Since we were able to lock the dquot's flush lock and
178 * we found it on the AIL, the dquot must be dirty. This
179 * is because the dquot is removed from the AIL while still
180 * holding the flush lock in xfs_dqflush_done(). Thus, if
181 * we found it in the AIL and were able to obtain the flush
182 * lock without sleeping, then there must not have been
183 * anyone in the process of flushing the dquot.
184 */
185 xfs_qm_dqflush(dqp, XFS_B_DELWRI);
186 xfs_dqunlock(dqp);
187}
188
189/*ARGSUSED*/
190STATIC xfs_lsn_t
191xfs_qm_dquot_logitem_committed(
192 xfs_dq_logitem_t *l,
193 xfs_lsn_t lsn)
194{
195 /*
196 * We always re-log the entire dquot when it becomes dirty,
197 * so, the latest copy _is_ the only one that matters.
198 */
199 return (lsn);
200}
201
202
203/*
204 * This is called to wait for the given dquot to be unpinned.
205 * Most of these pin/unpin routines are plagiarized from inode code.
206 */
207void
208xfs_qm_dqunpin_wait(
209 xfs_dquot_t *dqp)
210{
211 SPLDECL(s);
212
213 ASSERT(XFS_DQ_IS_LOCKED(dqp));
214 if (dqp->q_pincount == 0) {
215 return;
216 }
217
218 /*
219 * Give the log a push so we don't wait here too long.
220 */
221 xfs_log_force(dqp->q_mount, (xfs_lsn_t)0, XFS_LOG_FORCE);
222 s = XFS_DQ_PINLOCK(dqp);
223 if (dqp->q_pincount == 0) {
224 XFS_DQ_PINUNLOCK(dqp, s);
225 return;
226 }
227 sv_wait(&(dqp->q_pinwait), PINOD,
228 &(XFS_DQ_TO_QINF(dqp)->qi_pinlock), s);
229}
230
231/*
232 * This is called when IOP_TRYLOCK returns XFS_ITEM_PUSHBUF to indicate that
233 * the dquot is locked by us, but the flush lock isn't. So, here we are
234 * going to see if the relevant dquot buffer is incore, waiting on DELWRI.
235 * If so, we want to push it out to help us take this item off the AIL as soon
236 * as possible.
237 *
238 * We must not be holding the AIL_LOCK at this point. Calling incore() to
239 * search the buffercache can be a time consuming thing, and AIL_LOCK is a
240 * spinlock.
241 */
242STATIC void
243xfs_qm_dquot_logitem_pushbuf(
244 xfs_dq_logitem_t *qip)
245{
246 xfs_dquot_t *dqp;
247 xfs_mount_t *mp;
248 xfs_buf_t *bp;
249 uint dopush;
250
251 dqp = qip->qli_dquot;
252 ASSERT(XFS_DQ_IS_LOCKED(dqp));
253
254 /*
255 * The qli_pushbuf_flag keeps others from
256 * trying to duplicate our effort.
257 */
258 ASSERT(qip->qli_pushbuf_flag != 0);
259 ASSERT(qip->qli_push_owner == get_thread_id());
260
261 /*
262 * If flushlock isn't locked anymore, chances are that the
263 * inode flush completed and the inode was taken off the AIL.
264 * So, just get out.
265 */
266 if ((valusema(&(dqp->q_flock)) > 0) ||
267 ((qip->qli_item.li_flags & XFS_LI_IN_AIL) == 0)) {
268 qip->qli_pushbuf_flag = 0;
269 xfs_dqunlock(dqp);
270 return;
271 }
272 mp = dqp->q_mount;
273 bp = xfs_incore(mp->m_ddev_targp, qip->qli_format.qlf_blkno,
274 XFS_QI_DQCHUNKLEN(mp),
275 XFS_INCORE_TRYLOCK);
276 if (bp != NULL) {
277 if (XFS_BUF_ISDELAYWRITE(bp)) {
278 dopush = ((qip->qli_item.li_flags & XFS_LI_IN_AIL) &&
279 (valusema(&(dqp->q_flock)) <= 0));
280 qip->qli_pushbuf_flag = 0;
281 xfs_dqunlock(dqp);
282
283 if (XFS_BUF_ISPINNED(bp)) {
284 xfs_log_force(mp, (xfs_lsn_t)0,
285 XFS_LOG_FORCE);
286 }
287 if (dopush) {
288#ifdef XFSRACEDEBUG
289 delay_for_intr();
290 delay(300);
291#endif
292 xfs_bawrite(mp, bp);
293 } else {
294 xfs_buf_relse(bp);
295 }
296 } else {
297 qip->qli_pushbuf_flag = 0;
298 xfs_dqunlock(dqp);
299 xfs_buf_relse(bp);
300 }
301 return;
302 }
303
304 qip->qli_pushbuf_flag = 0;
305 xfs_dqunlock(dqp);
306}
307
308/*
309 * This is called to attempt to lock the dquot associated with this
310 * dquot log item. Don't sleep on the dquot lock or the flush lock.
311 * If the flush lock is already held, indicating that the dquot has
312 * been or is in the process of being flushed, then see if we can
313 * find the dquot's buffer in the buffer cache without sleeping. If
314 * we can and it is marked delayed write, then we want to send it out.
315 * We delay doing so until the push routine, though, to avoid sleeping
316 * in any device strategy routines.
317 */
318STATIC uint
319xfs_qm_dquot_logitem_trylock(
320 xfs_dq_logitem_t *qip)
321{
322 xfs_dquot_t *dqp;
323 uint retval;
324
325 dqp = qip->qli_dquot;
326 if (dqp->q_pincount > 0)
327 return (XFS_ITEM_PINNED);
328
329 if (! xfs_qm_dqlock_nowait(dqp))
330 return (XFS_ITEM_LOCKED);
331
332 retval = XFS_ITEM_SUCCESS;
333 if (! xfs_qm_dqflock_nowait(dqp)) {
334 /*
335 * The dquot is already being flushed. It may have been
336 * flushed delayed write, however, and we don't want to
337 * get stuck waiting for that to complete. So, we want to check
338 * to see if we can lock the dquot's buffer without sleeping.
339 * If we can and it is marked for delayed write, then we
340 * hold it and send it out from the push routine. We don't
341 * want to do that now since we might sleep in the device
342 * strategy routine. We also don't want to grab the buffer lock
343 * here because we'd like not to call into the buffer cache
344 * while holding the AIL_LOCK.
345 * Make sure to only return PUSHBUF if we set pushbuf_flag
346 * ourselves. If someone else is doing it then we don't
347 * want to go to the push routine and duplicate their efforts.
348 */
349 if (qip->qli_pushbuf_flag == 0) {
350 qip->qli_pushbuf_flag = 1;
351 ASSERT(qip->qli_format.qlf_blkno == dqp->q_blkno);
352#ifdef DEBUG
353 qip->qli_push_owner = get_thread_id();
354#endif
355 /*
356 * The dquot is left locked.
357 */
358 retval = XFS_ITEM_PUSHBUF;
359 } else {
360 retval = XFS_ITEM_FLUSHING;
361 xfs_dqunlock_nonotify(dqp);
362 }
363 }
364
365 ASSERT(qip->qli_item.li_flags & XFS_LI_IN_AIL);
366 return (retval);
367}
368
369
370/*
371 * Unlock the dquot associated with the log item.
372 * Clear the fields of the dquot and dquot log item that
373 * are specific to the current transaction. If the
374 * hold flags is set, do not unlock the dquot.
375 */
376STATIC void
377xfs_qm_dquot_logitem_unlock(
378 xfs_dq_logitem_t *ql)
379{
380 xfs_dquot_t *dqp;
381
382 ASSERT(ql != NULL);
383 dqp = ql->qli_dquot;
384 ASSERT(XFS_DQ_IS_LOCKED(dqp));
385
386 /*
387 * Clear the transaction pointer in the dquot
388 */
389 dqp->q_transp = NULL;
390
391 /*
392 * dquots are never 'held' from getting unlocked at the end of
393 * a transaction. Their locking and unlocking is hidden inside the
394 * transaction layer, within trans_commit. Hence, no LI_HOLD flag
395 * for the logitem.
396 */
397 xfs_dqunlock(dqp);
398}
399
400
401/*
402 * The transaction with the dquot locked has aborted. The dquot
403 * must not be dirty within the transaction. We simply unlock just
404 * as if the transaction had been cancelled.
405 */
406STATIC void
407xfs_qm_dquot_logitem_abort(
408 xfs_dq_logitem_t *ql)
409{
410 xfs_qm_dquot_logitem_unlock(ql);
411}
412
413/*
414 * this needs to stamp an lsn into the dquot, I think.
415 * rpc's that look at user dquot's would then have to
416 * push on the dependency recorded in the dquot
417 */
418/* ARGSUSED */
419STATIC void
420xfs_qm_dquot_logitem_committing(
421 xfs_dq_logitem_t *l,
422 xfs_lsn_t lsn)
423{
424 return;
425}
426
427
428/*
429 * This is the ops vector for dquots
430 */
431struct xfs_item_ops xfs_dquot_item_ops = {
432 .iop_size = (uint(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_size,
433 .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
434 xfs_qm_dquot_logitem_format,
435 .iop_pin = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_pin,
436 .iop_unpin = (void(*)(xfs_log_item_t*, int))
437 xfs_qm_dquot_logitem_unpin,
438 .iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t*))
439 xfs_qm_dquot_logitem_unpin_remove,
440 .iop_trylock = (uint(*)(xfs_log_item_t*))
441 xfs_qm_dquot_logitem_trylock,
442 .iop_unlock = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_unlock,
443 .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
444 xfs_qm_dquot_logitem_committed,
445 .iop_push = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_push,
446 .iop_abort = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_abort,
447 .iop_pushbuf = (void(*)(xfs_log_item_t*))
448 xfs_qm_dquot_logitem_pushbuf,
449 .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
450 xfs_qm_dquot_logitem_committing
451};
452
453/*
454 * Initialize the dquot log item for a newly allocated dquot.
455 * The dquot isn't locked at this point, but it isn't on any of the lists
456 * either, so we don't care.
457 */
458void
459xfs_qm_dquot_logitem_init(
460 struct xfs_dquot *dqp)
461{
462 xfs_dq_logitem_t *lp;
463 lp = &dqp->q_logitem;
464
465 lp->qli_item.li_type = XFS_LI_DQUOT;
466 lp->qli_item.li_ops = &xfs_dquot_item_ops;
467 lp->qli_item.li_mountp = dqp->q_mount;
468 lp->qli_dquot = dqp;
469 lp->qli_format.qlf_type = XFS_LI_DQUOT;
470 lp->qli_format.qlf_id = INT_GET(dqp->q_core.d_id, ARCH_CONVERT);
471 lp->qli_format.qlf_blkno = dqp->q_blkno;
472 lp->qli_format.qlf_len = 1;
473 /*
474 * This is just the offset of this dquot within its buffer
475 * (which is currently 1 FSB and probably won't change).
476 * Hence 32 bits for this offset should be just fine.
477 * Alternatively, we can store (bufoffset / sizeof(xfs_dqblk_t))
478 * here, and recompute it at recovery time.
479 */
480 lp->qli_format.qlf_boffset = (__uint32_t)dqp->q_bufoffset;
481}
482
483/*------------------ QUOTAOFF LOG ITEMS -------------------*/
484
485/*
486 * This returns the number of iovecs needed to log the given quotaoff item.
487 * We only need 1 iovec for an quotaoff item. It just logs the
488 * quotaoff_log_format structure.
489 */
490/*ARGSUSED*/
491STATIC uint
492xfs_qm_qoff_logitem_size(xfs_qoff_logitem_t *qf)
493{
494 return (1);
495}
496
497/*
498 * This is called to fill in the vector of log iovecs for the
499 * given quotaoff log item. We use only 1 iovec, and we point that
500 * at the quotaoff_log_format structure embedded in the quotaoff item.
501 * It is at this point that we assert that all of the extent
502 * slots in the quotaoff item have been filled.
503 */
504STATIC void
505xfs_qm_qoff_logitem_format(xfs_qoff_logitem_t *qf,
506 xfs_log_iovec_t *log_vector)
507{
508 ASSERT(qf->qql_format.qf_type == XFS_LI_QUOTAOFF);
509
510 log_vector->i_addr = (xfs_caddr_t)&(qf->qql_format);
511 log_vector->i_len = sizeof(xfs_qoff_logitem_t);
512 qf->qql_format.qf_size = 1;
513}
514
515
516/*
517 * Pinning has no meaning for an quotaoff item, so just return.
518 */
519/*ARGSUSED*/
520STATIC void
521xfs_qm_qoff_logitem_pin(xfs_qoff_logitem_t *qf)
522{
523 return;
524}
525
526
527/*
528 * Since pinning has no meaning for an quotaoff item, unpinning does
529 * not either.
530 */
531/*ARGSUSED*/
532STATIC void
533xfs_qm_qoff_logitem_unpin(xfs_qoff_logitem_t *qf, int stale)
534{
535 return;
536}
537
538/*ARGSUSED*/
539STATIC void
540xfs_qm_qoff_logitem_unpin_remove(xfs_qoff_logitem_t *qf, xfs_trans_t *tp)
541{
542 return;
543}
544
545/*
546 * Quotaoff items have no locking, so just return success.
547 */
548/*ARGSUSED*/
549STATIC uint
550xfs_qm_qoff_logitem_trylock(xfs_qoff_logitem_t *qf)
551{
552 return XFS_ITEM_LOCKED;
553}
554
555/*
556 * Quotaoff items have no locking or pushing, so return failure
557 * so that the caller doesn't bother with us.
558 */
559/*ARGSUSED*/
560STATIC void
561xfs_qm_qoff_logitem_unlock(xfs_qoff_logitem_t *qf)
562{
563 return;
564}
565
566/*
567 * The quotaoff-start-item is logged only once and cannot be moved in the log,
568 * so simply return the lsn at which it's been logged.
569 */
570/*ARGSUSED*/
571STATIC xfs_lsn_t
572xfs_qm_qoff_logitem_committed(xfs_qoff_logitem_t *qf, xfs_lsn_t lsn)
573{
574 return (lsn);
575}
576
577/*
578 * The transaction of which this QUOTAOFF is a part has been aborted.
579 * Just clean up after ourselves.
580 * Shouldn't this never happen in the case of qoffend logitems? XXX
581 */
582STATIC void
583xfs_qm_qoff_logitem_abort(xfs_qoff_logitem_t *qf)
584{
585 kmem_free(qf, sizeof(xfs_qoff_logitem_t));
586}
587
588/*
589 * There isn't much you can do to push on an quotaoff item. It is simply
590 * stuck waiting for the log to be flushed to disk.
591 */
592/*ARGSUSED*/
593STATIC void
594xfs_qm_qoff_logitem_push(xfs_qoff_logitem_t *qf)
595{
596 return;
597}
598
599
600/*ARGSUSED*/
601STATIC xfs_lsn_t
602xfs_qm_qoffend_logitem_committed(
603 xfs_qoff_logitem_t *qfe,
604 xfs_lsn_t lsn)
605{
606 xfs_qoff_logitem_t *qfs;
607 SPLDECL(s);
608
609 qfs = qfe->qql_start_lip;
610 AIL_LOCK(qfs->qql_item.li_mountp,s);
611 /*
612 * Delete the qoff-start logitem from the AIL.
613 * xfs_trans_delete_ail() drops the AIL lock.
614 */
615 xfs_trans_delete_ail(qfs->qql_item.li_mountp, (xfs_log_item_t *)qfs, s);
616 kmem_free(qfs, sizeof(xfs_qoff_logitem_t));
617 kmem_free(qfe, sizeof(xfs_qoff_logitem_t));
618 return (xfs_lsn_t)-1;
619}
620
621/*
622 * XXX rcc - don't know quite what to do with this. I think we can
623 * just ignore it. The only time that isn't the case is if we allow
624 * the client to somehow see that quotas have been turned off in which
625 * we can't allow that to get back until the quotaoff hits the disk.
626 * So how would that happen? Also, do we need different routines for
627 * quotaoff start and quotaoff end? I suspect the answer is yes but
628 * to be sure, I need to look at the recovery code and see how quota off
629 * recovery is handled (do we roll forward or back or do something else).
630 * If we roll forwards or backwards, then we need two separate routines,
631 * one that does nothing and one that stamps in the lsn that matters
632 * (truly makes the quotaoff irrevocable). If we do something else,
633 * then maybe we don't need two.
634 */
635/* ARGSUSED */
636STATIC void
637xfs_qm_qoff_logitem_committing(xfs_qoff_logitem_t *qip, xfs_lsn_t commit_lsn)
638{
639 return;
640}
641
642/* ARGSUSED */
643STATIC void
644xfs_qm_qoffend_logitem_committing(xfs_qoff_logitem_t *qip, xfs_lsn_t commit_lsn)
645{
646 return;
647}
648
649struct xfs_item_ops xfs_qm_qoffend_logitem_ops = {
650 .iop_size = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size,
651 .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
652 xfs_qm_qoff_logitem_format,
653 .iop_pin = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_pin,
654 .iop_unpin = (void(*)(xfs_log_item_t* ,int))
655 xfs_qm_qoff_logitem_unpin,
656 .iop_unpin_remove = (void(*)(xfs_log_item_t*,xfs_trans_t*))
657 xfs_qm_qoff_logitem_unpin_remove,
658 .iop_trylock = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_trylock,
659 .iop_unlock = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unlock,
660 .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
661 xfs_qm_qoffend_logitem_committed,
662 .iop_push = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_push,
663 .iop_abort = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_abort,
664 .iop_pushbuf = NULL,
665 .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
666 xfs_qm_qoffend_logitem_committing
667};
668
669/*
670 * This is the ops vector shared by all quotaoff-start log items.
671 */
672struct xfs_item_ops xfs_qm_qoff_logitem_ops = {
673 .iop_size = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size,
674 .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
675 xfs_qm_qoff_logitem_format,
676 .iop_pin = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_pin,
677 .iop_unpin = (void(*)(xfs_log_item_t*, int))
678 xfs_qm_qoff_logitem_unpin,
679 .iop_unpin_remove = (void(*)(xfs_log_item_t*,xfs_trans_t*))
680 xfs_qm_qoff_logitem_unpin_remove,
681 .iop_trylock = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_trylock,
682 .iop_unlock = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unlock,
683 .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
684 xfs_qm_qoff_logitem_committed,
685 .iop_push = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_push,
686 .iop_abort = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_abort,
687 .iop_pushbuf = NULL,
688 .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
689 xfs_qm_qoff_logitem_committing
690};
691
692/*
693 * Allocate and initialize an quotaoff item of the correct quota type(s).
694 */
695xfs_qoff_logitem_t *
696xfs_qm_qoff_logitem_init(
697 struct xfs_mount *mp,
698 xfs_qoff_logitem_t *start,
699 uint flags)
700{
701 xfs_qoff_logitem_t *qf;
702
703 qf = (xfs_qoff_logitem_t*) kmem_zalloc(sizeof(xfs_qoff_logitem_t), KM_SLEEP);
704
705 qf->qql_item.li_type = XFS_LI_QUOTAOFF;
706 if (start)
707 qf->qql_item.li_ops = &xfs_qm_qoffend_logitem_ops;
708 else
709 qf->qql_item.li_ops = &xfs_qm_qoff_logitem_ops;
710 qf->qql_item.li_mountp = mp;
711 qf->qql_format.qf_type = XFS_LI_QUOTAOFF;
712 qf->qql_format.qf_flags = flags;
713 qf->qql_start_lip = start;
714 return (qf);
715}
diff --git a/fs/xfs/quota/xfs_dquot_item.h b/fs/xfs/quota/xfs_dquot_item.h
new file mode 100644
index 000000000000..9c6500dabcaa
--- /dev/null
+++ b/fs/xfs/quota/xfs_dquot_item.h
@@ -0,0 +1,66 @@
1/*
2 * Copyright (c) 2000-2003 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#ifndef __XFS_DQUOT_ITEM_H__
33#define __XFS_DQUOT_ITEM_H__
34
35struct xfs_dquot;
36struct xfs_trans;
37struct xfs_mount;
38struct xfs_qoff_logitem;
39
40typedef struct xfs_dq_logitem {
41 xfs_log_item_t qli_item; /* common portion */
42 struct xfs_dquot *qli_dquot; /* dquot ptr */
43 xfs_lsn_t qli_flush_lsn; /* lsn at last flush */
44 unsigned short qli_pushbuf_flag; /* 1 bit used in push_ail */
45#ifdef DEBUG
46 uint64_t qli_push_owner;
47#endif
48 xfs_dq_logformat_t qli_format; /* logged structure */
49} xfs_dq_logitem_t;
50
51typedef struct xfs_qoff_logitem {
52 xfs_log_item_t qql_item; /* common portion */
53 struct xfs_qoff_logitem *qql_start_lip; /* qoff-start logitem, if any */
54 xfs_qoff_logformat_t qql_format; /* logged structure */
55} xfs_qoff_logitem_t;
56
57
58extern void xfs_qm_dquot_logitem_init(struct xfs_dquot *);
59extern xfs_qoff_logitem_t *xfs_qm_qoff_logitem_init(struct xfs_mount *,
60 struct xfs_qoff_logitem *, uint);
61extern xfs_qoff_logitem_t *xfs_trans_get_qoff_item(struct xfs_trans *,
62 struct xfs_qoff_logitem *, uint);
63extern void xfs_trans_log_quotaoff_item(struct xfs_trans *,
64 struct xfs_qoff_logitem *);
65
66#endif /* __XFS_DQUOT_ITEM_H__ */
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c
new file mode 100644
index 000000000000..89f2cd656ebf
--- /dev/null
+++ b/fs/xfs/quota/xfs_qm.c
@@ -0,0 +1,2848 @@
1/*
2 * Copyright (c) 2000-2004 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_clnt.h"
38#include "xfs_trans.h"
39#include "xfs_sb.h"
40#include "xfs_ag.h"
41#include "xfs_dir.h"
42#include "xfs_dir2.h"
43#include "xfs_alloc.h"
44#include "xfs_dmapi.h"
45#include "xfs_quota.h"
46#include "xfs_mount.h"
47#include "xfs_alloc_btree.h"
48#include "xfs_bmap_btree.h"
49#include "xfs_ialloc_btree.h"
50#include "xfs_btree.h"
51#include "xfs_ialloc.h"
52#include "xfs_attr_sf.h"
53#include "xfs_dir_sf.h"
54#include "xfs_dir2_sf.h"
55#include "xfs_dinode.h"
56#include "xfs_inode.h"
57#include "xfs_bmap.h"
58#include "xfs_bit.h"
59#include "xfs_rtalloc.h"
60#include "xfs_error.h"
61#include "xfs_itable.h"
62#include "xfs_rw.h"
63#include "xfs_acl.h"
64#include "xfs_cap.h"
65#include "xfs_mac.h"
66#include "xfs_attr.h"
67#include "xfs_buf_item.h"
68#include "xfs_trans_space.h"
69#include "xfs_utils.h"
70
71#include "xfs_qm.h"
72
73/*
74 * The global quota manager. There is only one of these for the entire
75 * system, _not_ one per file system. XQM keeps track of the overall
76 * quota functionality, including maintaining the freelist and hash
77 * tables of dquots.
78 */
79mutex_t xfs_Gqm_lock;
80struct xfs_qm *xfs_Gqm;
81
82kmem_zone_t *qm_dqzone;
83kmem_zone_t *qm_dqtrxzone;
84kmem_shaker_t xfs_qm_shaker;
85
86STATIC void xfs_qm_list_init(xfs_dqlist_t *, char *, int);
87STATIC void xfs_qm_list_destroy(xfs_dqlist_t *);
88
89STATIC int xfs_qm_init_quotainos(xfs_mount_t *);
90STATIC int xfs_qm_shake(int, unsigned int);
91
92#ifdef DEBUG
93extern mutex_t qcheck_lock;
94#endif
95
96#ifdef QUOTADEBUG
97#define XQM_LIST_PRINT(l, NXT, title) \
98{ \
99 xfs_dquot_t *dqp; int i = 0; \
100 cmn_err(CE_DEBUG, "%s (#%d)", title, (int) (l)->qh_nelems); \
101 for (dqp = (l)->qh_next; dqp != NULL; dqp = dqp->NXT) { \
102 cmn_err(CE_DEBUG, " %d. \"%d (%s)\" " \
103 "bcnt = %d, icnt = %d, refs = %d", \
104 ++i, (int) INT_GET(dqp->q_core.d_id, ARCH_CONVERT), \
105 DQFLAGTO_TYPESTR(dqp), \
106 (int) INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT), \
107 (int) INT_GET(dqp->q_core.d_icount, ARCH_CONVERT), \
108 (int) dqp->q_nrefs); } \
109}
110#else
111#define XQM_LIST_PRINT(l, NXT, title) do { } while (0)
112#endif
113
114/*
115 * Initialize the XQM structure.
116 * Note that there is not one quota manager per file system.
117 */
118STATIC struct xfs_qm *
119xfs_Gqm_init(void)
120{
121 xfs_qm_t *xqm;
122 int hsize, i;
123
124 xqm = kmem_zalloc(sizeof(xfs_qm_t), KM_SLEEP);
125 ASSERT(xqm);
126
127 /*
128 * Initialize the dquot hash tables.
129 */
130 hsize = (DQUOT_HASH_HEURISTIC < XFS_QM_NCSIZE_THRESHOLD) ?
131 XFS_QM_HASHSIZE_LOW : XFS_QM_HASHSIZE_HIGH;
132 xqm->qm_dqhashmask = hsize - 1;
133
134 xqm->qm_usr_dqhtable = (xfs_dqhash_t *)kmem_zalloc(hsize *
135 sizeof(xfs_dqhash_t),
136 KM_SLEEP);
137 xqm->qm_grp_dqhtable = (xfs_dqhash_t *)kmem_zalloc(hsize *
138 sizeof(xfs_dqhash_t),
139 KM_SLEEP);
140 ASSERT(xqm->qm_usr_dqhtable != NULL);
141 ASSERT(xqm->qm_grp_dqhtable != NULL);
142
143 for (i = 0; i < hsize; i++) {
144 xfs_qm_list_init(&(xqm->qm_usr_dqhtable[i]), "uxdqh", i);
145 xfs_qm_list_init(&(xqm->qm_grp_dqhtable[i]), "gxdqh", i);
146 }
147
148 /*
149 * Freelist of all dquots of all file systems
150 */
151 xfs_qm_freelist_init(&(xqm->qm_dqfreelist));
152
153 /*
154 * dquot zone. we register our own low-memory callback.
155 */
156 if (!qm_dqzone) {
157 xqm->qm_dqzone = kmem_zone_init(sizeof(xfs_dquot_t),
158 "xfs_dquots");
159 qm_dqzone = xqm->qm_dqzone;
160 } else
161 xqm->qm_dqzone = qm_dqzone;
162
163 xfs_qm_shaker = kmem_shake_register(xfs_qm_shake);
164
165 /*
166 * The t_dqinfo portion of transactions.
167 */
168 if (!qm_dqtrxzone) {
169 xqm->qm_dqtrxzone = kmem_zone_init(sizeof(xfs_dquot_acct_t),
170 "xfs_dqtrx");
171 qm_dqtrxzone = xqm->qm_dqtrxzone;
172 } else
173 xqm->qm_dqtrxzone = qm_dqtrxzone;
174
175 atomic_set(&xqm->qm_totaldquots, 0);
176 xqm->qm_dqfree_ratio = XFS_QM_DQFREE_RATIO;
177 xqm->qm_nrefs = 0;
178#ifdef DEBUG
179 mutex_init(&qcheck_lock, MUTEX_DEFAULT, "qchk");
180#endif
181 return xqm;
182}
183
184/*
185 * Destroy the global quota manager when its reference count goes to zero.
186 */
187void
188xfs_qm_destroy(
189 struct xfs_qm *xqm)
190{
191 int hsize, i;
192
193 ASSERT(xqm != NULL);
194 ASSERT(xqm->qm_nrefs == 0);
195 kmem_shake_deregister(xfs_qm_shaker);
196 hsize = xqm->qm_dqhashmask + 1;
197 for (i = 0; i < hsize; i++) {
198 xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i]));
199 xfs_qm_list_destroy(&(xqm->qm_grp_dqhtable[i]));
200 }
201 kmem_free(xqm->qm_usr_dqhtable, hsize * sizeof(xfs_dqhash_t));
202 kmem_free(xqm->qm_grp_dqhtable, hsize * sizeof(xfs_dqhash_t));
203 xqm->qm_usr_dqhtable = NULL;
204 xqm->qm_grp_dqhtable = NULL;
205 xqm->qm_dqhashmask = 0;
206 xfs_qm_freelist_destroy(&(xqm->qm_dqfreelist));
207#ifdef DEBUG
208 mutex_destroy(&qcheck_lock);
209#endif
210 kmem_free(xqm, sizeof(xfs_qm_t));
211}
212
213/*
214 * Called at mount time to let XQM know that another file system is
215 * starting quotas. This isn't crucial information as the individual mount
216 * structures are pretty independent, but it helps the XQM keep a
217 * global view of what's going on.
218 */
219/* ARGSUSED */
220STATIC int
221xfs_qm_hold_quotafs_ref(
222 struct xfs_mount *mp)
223{
224 /*
225 * Need to lock the xfs_Gqm structure for things like this. For example,
226 * the structure could disappear between the entry to this routine and
227 * a HOLD operation if not locked.
228 */
229 XFS_QM_LOCK(xfs_Gqm);
230
231 if (xfs_Gqm == NULL)
232 xfs_Gqm = xfs_Gqm_init();
233 /*
234 * We can keep a list of all filesystems with quotas mounted for
235 * debugging and statistical purposes, but ...
236 * Just take a reference and get out.
237 */
238 XFS_QM_HOLD(xfs_Gqm);
239 XFS_QM_UNLOCK(xfs_Gqm);
240
241 return 0;
242}
243
244
245/*
246 * Release the reference that a filesystem took at mount time,
247 * so that we know when we need to destroy the entire quota manager.
248 */
249/* ARGSUSED */
250STATIC void
251xfs_qm_rele_quotafs_ref(
252 struct xfs_mount *mp)
253{
254 xfs_dquot_t *dqp, *nextdqp;
255
256 ASSERT(xfs_Gqm);
257 ASSERT(xfs_Gqm->qm_nrefs > 0);
258
259 /*
260 * Go thru the freelist and destroy all inactive dquots.
261 */
262 xfs_qm_freelist_lock(xfs_Gqm);
263
264 for (dqp = xfs_Gqm->qm_dqfreelist.qh_next;
265 dqp != (xfs_dquot_t *)&(xfs_Gqm->qm_dqfreelist); ) {
266 xfs_dqlock(dqp);
267 nextdqp = dqp->dq_flnext;
268 if (dqp->dq_flags & XFS_DQ_INACTIVE) {
269 ASSERT(dqp->q_mount == NULL);
270 ASSERT(! XFS_DQ_IS_DIRTY(dqp));
271 ASSERT(dqp->HL_PREVP == NULL);
272 ASSERT(dqp->MPL_PREVP == NULL);
273 XQM_FREELIST_REMOVE(dqp);
274 xfs_dqunlock(dqp);
275 xfs_qm_dqdestroy(dqp);
276 } else {
277 xfs_dqunlock(dqp);
278 }
279 dqp = nextdqp;
280 }
281 xfs_qm_freelist_unlock(xfs_Gqm);
282
283 /*
284 * Destroy the entire XQM. If somebody mounts with quotaon, this'll
285 * be restarted.
286 */
287 XFS_QM_LOCK(xfs_Gqm);
288 XFS_QM_RELE(xfs_Gqm);
289 if (xfs_Gqm->qm_nrefs == 0) {
290 xfs_qm_destroy(xfs_Gqm);
291 xfs_Gqm = NULL;
292 }
293 XFS_QM_UNLOCK(xfs_Gqm);
294}
295
296/*
297 * This is called at mount time from xfs_mountfs to initialize the quotainfo
298 * structure and start the global quotamanager (xfs_Gqm) if it hasn't done
299 * so already. Note that the superblock has not been read in yet.
300 */
301void
302xfs_qm_mount_quotainit(
303 xfs_mount_t *mp,
304 uint flags)
305{
306 /*
307 * User or group quotas has to be on.
308 */
309 ASSERT(flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA));
310
311 /*
312 * Initialize the flags in the mount structure. From this point
313 * onwards we look at m_qflags to figure out if quotas's ON/OFF, etc.
314 * Note that we enforce nothing if accounting is off.
315 * ie. XFSMNT_*QUOTA must be ON for XFSMNT_*QUOTAENF.
316 * It isn't necessary to take the quotaoff lock to do this; this is
317 * called from mount.
318 */
319 if (flags & XFSMNT_UQUOTA) {
320 mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE);
321 if (flags & XFSMNT_UQUOTAENF)
322 mp->m_qflags |= XFS_UQUOTA_ENFD;
323 }
324 if (flags & XFSMNT_GQUOTA) {
325 mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE);
326 if (flags & XFSMNT_GQUOTAENF)
327 mp->m_qflags |= XFS_GQUOTA_ENFD;
328 }
329}
330
331/*
332 * Just destroy the quotainfo structure.
333 */
334void
335xfs_qm_unmount_quotadestroy(
336 xfs_mount_t *mp)
337{
338 if (mp->m_quotainfo)
339 xfs_qm_destroy_quotainfo(mp);
340}
341
342
343/*
344 * This is called from xfs_mountfs to start quotas and initialize all
345 * necessary data structures like quotainfo. This is also responsible for
346 * running a quotacheck as necessary. We are guaranteed that the superblock
347 * is consistently read in at this point.
348 */
349int
350xfs_qm_mount_quotas(
351 xfs_mount_t *mp,
352 int mfsi_flags)
353{
354 unsigned long s;
355 int error = 0;
356 uint sbf;
357
358 /*
359 * If a file system had quotas running earlier, but decided to
360 * mount without -o quota/uquota/gquota options, revoke the
361 * quotachecked license, and bail out.
362 */
363 if (! XFS_IS_QUOTA_ON(mp) &&
364 (mp->m_sb.sb_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT))) {
365 mp->m_qflags = 0;
366 goto write_changes;
367 }
368
369 /*
370 * If quotas on realtime volumes is not supported, we disable
371 * quotas immediately.
372 */
373 if (mp->m_sb.sb_rextents) {
374 cmn_err(CE_NOTE,
375 "Cannot turn on quotas for realtime filesystem %s",
376 mp->m_fsname);
377 mp->m_qflags = 0;
378 goto write_changes;
379 }
380
381#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
382 cmn_err(CE_NOTE, "Attempting to turn on disk quotas.");
383#endif
384
385 ASSERT(XFS_IS_QUOTA_RUNNING(mp));
386 /*
387 * Allocate the quotainfo structure inside the mount struct, and
388 * create quotainode(s), and change/rev superblock if necessary.
389 */
390 if ((error = xfs_qm_init_quotainfo(mp))) {
391 /*
392 * We must turn off quotas.
393 */
394 ASSERT(mp->m_quotainfo == NULL);
395 mp->m_qflags = 0;
396 goto write_changes;
397 }
398 /*
399 * If any of the quotas are not consistent, do a quotacheck.
400 */
401 if (XFS_QM_NEED_QUOTACHECK(mp) &&
402 !(mfsi_flags & XFS_MFSI_NO_QUOTACHECK)) {
403#ifdef DEBUG
404 cmn_err(CE_NOTE, "Doing a quotacheck. Please wait.");
405#endif
406 if ((error = xfs_qm_quotacheck(mp))) {
407 /* Quotacheck has failed and quotas have
408 * been disabled.
409 */
410 return XFS_ERROR(error);
411 }
412#ifdef DEBUG
413 cmn_err(CE_NOTE, "Done quotacheck.");
414#endif
415 }
416 write_changes:
417 /*
418 * We actually don't have to acquire the SB_LOCK at all.
419 * This can only be called from mount, and that's single threaded. XXX
420 */
421 s = XFS_SB_LOCK(mp);
422 sbf = mp->m_sb.sb_qflags;
423 mp->m_sb.sb_qflags = mp->m_qflags & XFS_MOUNT_QUOTA_ALL;
424 XFS_SB_UNLOCK(mp, s);
425
426 if (sbf != (mp->m_qflags & XFS_MOUNT_QUOTA_ALL)) {
427 if (xfs_qm_write_sb_changes(mp, XFS_SB_QFLAGS)) {
428 /*
429 * We could only have been turning quotas off.
430 * We aren't in very good shape actually because
431 * the incore structures are convinced that quotas are
432 * off, but the on disk superblock doesn't know that !
433 */
434 ASSERT(!(XFS_IS_QUOTA_RUNNING(mp)));
435 xfs_fs_cmn_err(CE_ALERT, mp,
436 "XFS mount_quotas: Superblock update failed!");
437 }
438 }
439
440 if (error) {
441 xfs_fs_cmn_err(CE_WARN, mp,
442 "Failed to initialize disk quotas.");
443 }
444 return XFS_ERROR(error);
445}
446
447/*
448 * Called from the vfsops layer.
449 */
450int
451xfs_qm_unmount_quotas(
452 xfs_mount_t *mp)
453{
454 xfs_inode_t *uqp, *gqp;
455 int error = 0;
456
457 /*
458 * Release the dquots that root inode, et al might be holding,
459 * before we flush quotas and blow away the quotainfo structure.
460 */
461 ASSERT(mp->m_rootip);
462 xfs_qm_dqdetach(mp->m_rootip);
463 if (mp->m_rbmip)
464 xfs_qm_dqdetach(mp->m_rbmip);
465 if (mp->m_rsumip)
466 xfs_qm_dqdetach(mp->m_rsumip);
467
468 /*
469 * Flush out the quota inodes.
470 */
471 uqp = gqp = NULL;
472 if (mp->m_quotainfo) {
473 if ((uqp = mp->m_quotainfo->qi_uquotaip) != NULL) {
474 xfs_ilock(uqp, XFS_ILOCK_EXCL);
475 xfs_iflock(uqp);
476 error = xfs_iflush(uqp, XFS_IFLUSH_SYNC);
477 xfs_iunlock(uqp, XFS_ILOCK_EXCL);
478 if (unlikely(error == EFSCORRUPTED)) {
479 XFS_ERROR_REPORT("xfs_qm_unmount_quotas(1)",
480 XFS_ERRLEVEL_LOW, mp);
481 goto out;
482 }
483 }
484 if ((gqp = mp->m_quotainfo->qi_gquotaip) != NULL) {
485 xfs_ilock(gqp, XFS_ILOCK_EXCL);
486 xfs_iflock(gqp);
487 error = xfs_iflush(gqp, XFS_IFLUSH_SYNC);
488 xfs_iunlock(gqp, XFS_ILOCK_EXCL);
489 if (unlikely(error == EFSCORRUPTED)) {
490 XFS_ERROR_REPORT("xfs_qm_unmount_quotas(2)",
491 XFS_ERRLEVEL_LOW, mp);
492 goto out;
493 }
494 }
495 }
496 if (uqp) {
497 XFS_PURGE_INODE(uqp);
498 mp->m_quotainfo->qi_uquotaip = NULL;
499 }
500 if (gqp) {
501 XFS_PURGE_INODE(gqp);
502 mp->m_quotainfo->qi_gquotaip = NULL;
503 }
504out:
505 return XFS_ERROR(error);
506}
507
508/*
509 * Flush all dquots of the given file system to disk. The dquots are
510 * _not_ purged from memory here, just their data written to disk.
511 */
512int
513xfs_qm_dqflush_all(
514 xfs_mount_t *mp,
515 int flags)
516{
517 int recl;
518 xfs_dquot_t *dqp;
519 int niters;
520 int error;
521
522 if (mp->m_quotainfo == NULL)
523 return (0);
524 niters = 0;
525again:
526 xfs_qm_mplist_lock(mp);
527 FOREACH_DQUOT_IN_MP(dqp, mp) {
528 xfs_dqlock(dqp);
529 if (! XFS_DQ_IS_DIRTY(dqp)) {
530 xfs_dqunlock(dqp);
531 continue;
532 }
533 xfs_dqtrace_entry(dqp, "FLUSHALL: DQDIRTY");
534 /* XXX a sentinel would be better */
535 recl = XFS_QI_MPLRECLAIMS(mp);
536 if (! xfs_qm_dqflock_nowait(dqp)) {
537 /*
538 * If we can't grab the flush lock then check
539 * to see if the dquot has been flushed delayed
540 * write. If so, grab its buffer and send it
541 * out immediately. We'll be able to acquire
542 * the flush lock when the I/O completes.
543 */
544 xfs_qm_dqflock_pushbuf_wait(dqp);
545 }
546 /*
547 * Let go of the mplist lock. We don't want to hold it
548 * across a disk write.
549 */
550 xfs_qm_mplist_unlock(mp);
551 error = xfs_qm_dqflush(dqp, flags);
552 xfs_dqunlock(dqp);
553 if (error)
554 return (error);
555
556 xfs_qm_mplist_lock(mp);
557 if (recl != XFS_QI_MPLRECLAIMS(mp)) {
558 xfs_qm_mplist_unlock(mp);
559 /* XXX restart limit */
560 goto again;
561 }
562 }
563
564 xfs_qm_mplist_unlock(mp);
565 /* return ! busy */
566 return (0);
567}
568/*
569 * Release the group dquot pointers the user dquots may be
570 * carrying around as a hint. mplist is locked on entry and exit.
571 */
572STATIC void
573xfs_qm_detach_gdquots(
574 xfs_mount_t *mp)
575{
576 xfs_dquot_t *dqp, *gdqp;
577 int nrecl;
578
579 again:
580 ASSERT(XFS_QM_IS_MPLIST_LOCKED(mp));
581 dqp = XFS_QI_MPLNEXT(mp);
582 while (dqp) {
583 xfs_dqlock(dqp);
584 if ((gdqp = dqp->q_gdquot)) {
585 xfs_dqlock(gdqp);
586 dqp->q_gdquot = NULL;
587 }
588 xfs_dqunlock(dqp);
589
590 if (gdqp) {
591 /*
592 * Can't hold the mplist lock across a dqput.
593 * XXXmust convert to marker based iterations here.
594 */
595 nrecl = XFS_QI_MPLRECLAIMS(mp);
596 xfs_qm_mplist_unlock(mp);
597 xfs_qm_dqput(gdqp);
598
599 xfs_qm_mplist_lock(mp);
600 if (nrecl != XFS_QI_MPLRECLAIMS(mp))
601 goto again;
602 }
603 dqp = dqp->MPL_NEXT;
604 }
605}
606
607/*
608 * Go through all the incore dquots of this file system and take them
609 * off the mplist and hashlist, if the dquot type matches the dqtype
610 * parameter. This is used when turning off quota accounting for
611 * users and/or groups, as well as when the filesystem is unmounting.
612 */
613STATIC int
614xfs_qm_dqpurge_int(
615 xfs_mount_t *mp,
616 uint flags) /* QUOTAOFF/UMOUNTING/UQUOTA/GQUOTA */
617{
618 xfs_dquot_t *dqp;
619 uint dqtype;
620 int nrecl;
621 xfs_dquot_t *nextdqp;
622 int nmisses;
623
624 if (mp->m_quotainfo == NULL)
625 return (0);
626
627 dqtype = (flags & XFS_QMOPT_UQUOTA) ? XFS_DQ_USER : 0;
628 dqtype |= (flags & XFS_QMOPT_GQUOTA) ? XFS_DQ_GROUP : 0;
629
630 xfs_qm_mplist_lock(mp);
631
632 /*
633 * In the first pass through all incore dquots of this filesystem,
634 * we release the group dquot pointers the user dquots may be
635 * carrying around as a hint. We need to do this irrespective of
636 * what's being turned off.
637 */
638 xfs_qm_detach_gdquots(mp);
639
640 again:
641 nmisses = 0;
642 ASSERT(XFS_QM_IS_MPLIST_LOCKED(mp));
643 /*
644 * Try to get rid of all of the unwanted dquots. The idea is to
645 * get them off mplist and hashlist, but leave them on freelist.
646 */
647 dqp = XFS_QI_MPLNEXT(mp);
648 while (dqp) {
649 /*
650 * It's OK to look at the type without taking dqlock here.
651 * We're holding the mplist lock here, and that's needed for
652 * a dqreclaim.
653 */
654 if ((dqp->dq_flags & dqtype) == 0) {
655 dqp = dqp->MPL_NEXT;
656 continue;
657 }
658
659 if (! xfs_qm_dqhashlock_nowait(dqp)) {
660 nrecl = XFS_QI_MPLRECLAIMS(mp);
661 xfs_qm_mplist_unlock(mp);
662 XFS_DQ_HASH_LOCK(dqp->q_hash);
663 xfs_qm_mplist_lock(mp);
664
665 /*
666 * XXXTheoretically, we can get into a very long
667 * ping pong game here.
668 * No one can be adding dquots to the mplist at
669 * this point, but somebody might be taking things off.
670 */
671 if (nrecl != XFS_QI_MPLRECLAIMS(mp)) {
672 XFS_DQ_HASH_UNLOCK(dqp->q_hash);
673 goto again;
674 }
675 }
676
677 /*
678 * Take the dquot off the mplist and hashlist. It may remain on
679 * freelist in INACTIVE state.
680 */
681 nextdqp = dqp->MPL_NEXT;
682 nmisses += xfs_qm_dqpurge(dqp, flags);
683 dqp = nextdqp;
684 }
685 xfs_qm_mplist_unlock(mp);
686 return nmisses;
687}
688
689int
690xfs_qm_dqpurge_all(
691 xfs_mount_t *mp,
692 uint flags)
693{
694 int ndquots;
695
696 /*
697 * Purge the dquot cache.
698 * None of the dquots should really be busy at this point.
699 */
700 if (mp->m_quotainfo) {
701 while ((ndquots = xfs_qm_dqpurge_int(mp, flags))) {
702 delay(ndquots * 10);
703 }
704 }
705 return 0;
706}
707
708STATIC int
709xfs_qm_dqattach_one(
710 xfs_inode_t *ip,
711 xfs_dqid_t id,
712 uint type,
713 uint doalloc,
714 uint dolock,
715 xfs_dquot_t *udqhint, /* hint */
716 xfs_dquot_t **IO_idqpp)
717{
718 xfs_dquot_t *dqp;
719 int error;
720
721 ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
722 error = 0;
723 /*
724 * See if we already have it in the inode itself. IO_idqpp is
725 * &i_udquot or &i_gdquot. This made the code look weird, but
726 * made the logic a lot simpler.
727 */
728 if ((dqp = *IO_idqpp)) {
729 if (dolock)
730 xfs_dqlock(dqp);
731 xfs_dqtrace_entry(dqp, "DQATTACH: found in ip");
732 goto done;
733 }
734
735 /*
736 * udqhint is the i_udquot field in inode, and is non-NULL only
737 * when the type arg is XFS_DQ_GROUP. Its purpose is to save a
738 * lookup by dqid (xfs_qm_dqget) by caching a group dquot inside
739 * the user dquot.
740 */
741 ASSERT(!udqhint || type == XFS_DQ_GROUP);
742 if (udqhint && !dolock)
743 xfs_dqlock(udqhint);
744
745 /*
746 * No need to take dqlock to look at the id.
747 * The ID can't change until it gets reclaimed, and it won't
748 * be reclaimed as long as we have a ref from inode and we hold
749 * the ilock.
750 */
751 if (udqhint &&
752 (dqp = udqhint->q_gdquot) &&
753 (INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id)) {
754 ASSERT(XFS_DQ_IS_LOCKED(udqhint));
755 xfs_dqlock(dqp);
756 XFS_DQHOLD(dqp);
757 ASSERT(*IO_idqpp == NULL);
758 *IO_idqpp = dqp;
759 if (!dolock) {
760 xfs_dqunlock(dqp);
761 xfs_dqunlock(udqhint);
762 }
763 goto done;
764 }
765 /*
766 * We can't hold a dquot lock when we call the dqget code.
767 * We'll deadlock in no time, because of (not conforming to)
768 * lock ordering - the inodelock comes before any dquot lock,
769 * and we may drop and reacquire the ilock in xfs_qm_dqget().
770 */
771 if (udqhint)
772 xfs_dqunlock(udqhint);
773 /*
774 * Find the dquot from somewhere. This bumps the
775 * reference count of dquot and returns it locked.
776 * This can return ENOENT if dquot didn't exist on
777 * disk and we didn't ask it to allocate;
778 * ESRCH if quotas got turned off suddenly.
779 */
780 if ((error = xfs_qm_dqget(ip->i_mount, ip, id, type,
781 doalloc|XFS_QMOPT_DOWARN, &dqp))) {
782 if (udqhint && dolock)
783 xfs_dqlock(udqhint);
784 goto done;
785 }
786
787 xfs_dqtrace_entry(dqp, "DQATTACH: found by dqget");
788 /*
789 * dqget may have dropped and re-acquired the ilock, but it guarantees
790 * that the dquot returned is the one that should go in the inode.
791 */
792 *IO_idqpp = dqp;
793 ASSERT(dqp);
794 ASSERT(XFS_DQ_IS_LOCKED(dqp));
795 if (! dolock) {
796 xfs_dqunlock(dqp);
797 goto done;
798 }
799 if (! udqhint)
800 goto done;
801
802 ASSERT(udqhint);
803 ASSERT(dolock);
804 ASSERT(XFS_DQ_IS_LOCKED(dqp));
805 if (! xfs_qm_dqlock_nowait(udqhint)) {
806 xfs_dqunlock(dqp);
807 xfs_dqlock(udqhint);
808 xfs_dqlock(dqp);
809 }
810 done:
811#ifdef QUOTADEBUG
812 if (udqhint) {
813 if (dolock)
814 ASSERT(XFS_DQ_IS_LOCKED(udqhint));
815 }
816 if (! error) {
817 if (dolock)
818 ASSERT(XFS_DQ_IS_LOCKED(dqp));
819 }
820#endif
821 return (error);
822}
823
824
825/*
826 * Given a udquot and gdquot, attach a ptr to the group dquot in the
827 * udquot as a hint for future lookups. The idea sounds simple, but the
828 * execution isn't, because the udquot might have a group dquot attached
829 * already and getting rid of that gets us into lock ordering contraints.
830 * The process is complicated more by the fact that the dquots may or may not
831 * be locked on entry.
832 */
833STATIC void
834xfs_qm_dqattach_grouphint(
835 xfs_dquot_t *udq,
836 xfs_dquot_t *gdq,
837 uint locked)
838{
839 xfs_dquot_t *tmp;
840
841#ifdef QUOTADEBUG
842 if (locked) {
843 ASSERT(XFS_DQ_IS_LOCKED(udq));
844 ASSERT(XFS_DQ_IS_LOCKED(gdq));
845 }
846#endif
847 if (! locked)
848 xfs_dqlock(udq);
849
850 if ((tmp = udq->q_gdquot)) {
851 if (tmp == gdq) {
852 if (! locked)
853 xfs_dqunlock(udq);
854 return;
855 }
856
857 udq->q_gdquot = NULL;
858 /*
859 * We can't keep any dqlocks when calling dqrele,
860 * because the freelist lock comes before dqlocks.
861 */
862 xfs_dqunlock(udq);
863 if (locked)
864 xfs_dqunlock(gdq);
865 /*
866 * we took a hard reference once upon a time in dqget,
867 * so give it back when the udquot no longer points at it
868 * dqput() does the unlocking of the dquot.
869 */
870 xfs_qm_dqrele(tmp);
871
872 xfs_dqlock(udq);
873 xfs_dqlock(gdq);
874
875 } else {
876 ASSERT(XFS_DQ_IS_LOCKED(udq));
877 if (! locked) {
878 xfs_dqlock(gdq);
879 }
880 }
881
882 ASSERT(XFS_DQ_IS_LOCKED(udq));
883 ASSERT(XFS_DQ_IS_LOCKED(gdq));
884 /*
885 * Somebody could have attached a gdquot here,
886 * when we dropped the uqlock. If so, just do nothing.
887 */
888 if (udq->q_gdquot == NULL) {
889 XFS_DQHOLD(gdq);
890 udq->q_gdquot = gdq;
891 }
892 if (! locked) {
893 xfs_dqunlock(gdq);
894 xfs_dqunlock(udq);
895 }
896}
897
898
899/*
900 * Given a locked inode, attach dquot(s) to it, taking UQUOTAON / GQUOTAON
901 * in to account.
902 * If XFS_QMOPT_DQALLOC, the dquot(s) will be allocated if needed.
903 * If XFS_QMOPT_DQLOCK, the dquot(s) will be returned locked. This option pretty
904 * much made this code a complete mess, but it has been pretty useful.
905 * If XFS_QMOPT_ILOCKED, then inode sent is already locked EXCL.
906 * Inode may get unlocked and relocked in here, and the caller must deal with
907 * the consequences.
908 */
909int
910xfs_qm_dqattach(
911 xfs_inode_t *ip,
912 uint flags)
913{
914 xfs_mount_t *mp = ip->i_mount;
915 uint nquotas = 0;
916 int error = 0;
917
918 if ((! XFS_IS_QUOTA_ON(mp)) ||
919 (! XFS_NOT_DQATTACHED(mp, ip)) ||
920 (ip->i_ino == mp->m_sb.sb_uquotino) ||
921 (ip->i_ino == mp->m_sb.sb_gquotino))
922 return (0);
923
924 ASSERT((flags & XFS_QMOPT_ILOCKED) == 0 ||
925 XFS_ISLOCKED_INODE_EXCL(ip));
926
927 if (! (flags & XFS_QMOPT_ILOCKED))
928 xfs_ilock(ip, XFS_ILOCK_EXCL);
929
930 if (XFS_IS_UQUOTA_ON(mp)) {
931 error = xfs_qm_dqattach_one(ip, ip->i_d.di_uid, XFS_DQ_USER,
932 flags & XFS_QMOPT_DQALLOC,
933 flags & XFS_QMOPT_DQLOCK,
934 NULL, &ip->i_udquot);
935 if (error)
936 goto done;
937 nquotas++;
938 }
939 ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
940 if (XFS_IS_GQUOTA_ON(mp)) {
941 error = xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP,
942 flags & XFS_QMOPT_DQALLOC,
943 flags & XFS_QMOPT_DQLOCK,
944 ip->i_udquot, &ip->i_gdquot);
945 /*
946 * Don't worry about the udquot that we may have
947 * attached above. It'll get detached, if not already.
948 */
949 if (error)
950 goto done;
951 nquotas++;
952 }
953
954 /*
955 * Attach this group quota to the user quota as a hint.
956 * This WON'T, in general, result in a thrash.
957 */
958 if (nquotas == 2) {
959 ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
960 ASSERT(ip->i_udquot);
961 ASSERT(ip->i_gdquot);
962
963 /*
964 * We may or may not have the i_udquot locked at this point,
965 * but this check is OK since we don't depend on the i_gdquot to
966 * be accurate 100% all the time. It is just a hint, and this
967 * will succeed in general.
968 */
969 if (ip->i_udquot->q_gdquot == ip->i_gdquot)
970 goto done;
971 /*
972 * Attach i_gdquot to the gdquot hint inside the i_udquot.
973 */
974 xfs_qm_dqattach_grouphint(ip->i_udquot, ip->i_gdquot,
975 flags & XFS_QMOPT_DQLOCK);
976 }
977
978 done:
979
980#ifdef QUOTADEBUG
981 if (! error) {
982 if (ip->i_udquot) {
983 if (flags & XFS_QMOPT_DQLOCK)
984 ASSERT(XFS_DQ_IS_LOCKED(ip->i_udquot));
985 }
986 if (ip->i_gdquot) {
987 if (flags & XFS_QMOPT_DQLOCK)
988 ASSERT(XFS_DQ_IS_LOCKED(ip->i_gdquot));
989 }
990 if (XFS_IS_UQUOTA_ON(mp))
991 ASSERT(ip->i_udquot);
992 if (XFS_IS_GQUOTA_ON(mp))
993 ASSERT(ip->i_gdquot);
994 }
995#endif
996
997 if (! (flags & XFS_QMOPT_ILOCKED))
998 xfs_iunlock(ip, XFS_ILOCK_EXCL);
999
1000#ifdef QUOTADEBUG
1001 else
1002 ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
1003#endif
1004 return (error);
1005}
1006
1007/*
1008 * Release dquots (and their references) if any.
1009 * The inode should be locked EXCL except when this's called by
1010 * xfs_ireclaim.
1011 */
1012void
1013xfs_qm_dqdetach(
1014 xfs_inode_t *ip)
1015{
1016 if (!(ip->i_udquot || ip->i_gdquot))
1017 return;
1018
1019 ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_uquotino);
1020 ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_gquotino);
1021 if (ip->i_udquot)
1022 xfs_dqtrace_entry_ino(ip->i_udquot, "DQDETTACH", ip);
1023 if (ip->i_udquot) {
1024 xfs_qm_dqrele(ip->i_udquot);
1025 ip->i_udquot = NULL;
1026 }
1027 if (ip->i_gdquot) {
1028 xfs_qm_dqrele(ip->i_gdquot);
1029 ip->i_gdquot = NULL;
1030 }
1031}
1032
1033/*
1034 * This is called by VFS_SYNC and flags arg determines the caller,
1035 * and its motives, as done in xfs_sync.
1036 *
1037 * vfs_sync: SYNC_FSDATA|SYNC_ATTR|SYNC_BDFLUSH 0x31
1038 * syscall sync: SYNC_FSDATA|SYNC_ATTR|SYNC_DELWRI 0x25
1039 * umountroot : SYNC_WAIT | SYNC_CLOSE | SYNC_ATTR | SYNC_FSDATA
1040 */
1041
1042int
1043xfs_qm_sync(
1044 xfs_mount_t *mp,
1045 short flags)
1046{
1047 int recl, restarts;
1048 xfs_dquot_t *dqp;
1049 uint flush_flags;
1050 boolean_t nowait;
1051 int error;
1052
1053 restarts = 0;
1054 /*
1055 * We won't block unless we are asked to.
1056 */
1057 nowait = (boolean_t)(flags & SYNC_BDFLUSH || (flags & SYNC_WAIT) == 0);
1058
1059 again:
1060 xfs_qm_mplist_lock(mp);
1061 /*
1062 * dqpurge_all() also takes the mplist lock and iterate thru all dquots
1063 * in quotaoff. However, if the QUOTA_ACTIVE bits are not cleared
1064 * when we have the mplist lock, we know that dquots will be consistent
1065 * as long as we have it locked.
1066 */
1067 if (! XFS_IS_QUOTA_ON(mp)) {
1068 xfs_qm_mplist_unlock(mp);
1069 return (0);
1070 }
1071 FOREACH_DQUOT_IN_MP(dqp, mp) {
1072 /*
1073 * If this is vfs_sync calling, then skip the dquots that
1074 * don't 'seem' to be dirty. ie. don't acquire dqlock.
1075 * This is very similar to what xfs_sync does with inodes.
1076 */
1077 if (flags & SYNC_BDFLUSH) {
1078 if (! XFS_DQ_IS_DIRTY(dqp))
1079 continue;
1080 }
1081
1082 if (nowait) {
1083 /*
1084 * Try to acquire the dquot lock. We are NOT out of
1085 * lock order, but we just don't want to wait for this
1086 * lock, unless somebody wanted us to.
1087 */
1088 if (! xfs_qm_dqlock_nowait(dqp))
1089 continue;
1090 } else {
1091 xfs_dqlock(dqp);
1092 }
1093
1094 /*
1095 * Now, find out for sure if this dquot is dirty or not.
1096 */
1097 if (! XFS_DQ_IS_DIRTY(dqp)) {
1098 xfs_dqunlock(dqp);
1099 continue;
1100 }
1101
1102 /* XXX a sentinel would be better */
1103 recl = XFS_QI_MPLRECLAIMS(mp);
1104 if (! xfs_qm_dqflock_nowait(dqp)) {
1105 if (nowait) {
1106 xfs_dqunlock(dqp);
1107 continue;
1108 }
1109 /*
1110 * If we can't grab the flush lock then if the caller
1111 * really wanted us to give this our best shot,
1112 * see if we can give a push to the buffer before we wait
1113 * on the flush lock. At this point, we know that
1114 * eventhough the dquot is being flushed,
1115 * it has (new) dirty data.
1116 */
1117 xfs_qm_dqflock_pushbuf_wait(dqp);
1118 }
1119 /*
1120 * Let go of the mplist lock. We don't want to hold it
1121 * across a disk write
1122 */
1123 flush_flags = (nowait) ? XFS_QMOPT_DELWRI : XFS_QMOPT_SYNC;
1124 xfs_qm_mplist_unlock(mp);
1125 xfs_dqtrace_entry(dqp, "XQM_SYNC: DQFLUSH");
1126 error = xfs_qm_dqflush(dqp, flush_flags);
1127 xfs_dqunlock(dqp);
1128 if (error && XFS_FORCED_SHUTDOWN(mp))
1129 return(0); /* Need to prevent umount failure */
1130 else if (error)
1131 return (error);
1132
1133 xfs_qm_mplist_lock(mp);
1134 if (recl != XFS_QI_MPLRECLAIMS(mp)) {
1135 if (++restarts >= XFS_QM_SYNC_MAX_RESTARTS)
1136 break;
1137
1138 xfs_qm_mplist_unlock(mp);
1139 goto again;
1140 }
1141 }
1142
1143 xfs_qm_mplist_unlock(mp);
1144 return (0);
1145}
1146
1147
1148/*
1149 * This initializes all the quota information that's kept in the
1150 * mount structure
1151 */
1152int
1153xfs_qm_init_quotainfo(
1154 xfs_mount_t *mp)
1155{
1156 xfs_quotainfo_t *qinf;
1157 int error;
1158 xfs_dquot_t *dqp;
1159
1160 ASSERT(XFS_IS_QUOTA_RUNNING(mp));
1161
1162 /*
1163 * Tell XQM that we exist as soon as possible.
1164 */
1165 if ((error = xfs_qm_hold_quotafs_ref(mp))) {
1166 return (error);
1167 }
1168
1169 qinf = mp->m_quotainfo = kmem_zalloc(sizeof(xfs_quotainfo_t), KM_SLEEP);
1170
1171 /*
1172 * See if quotainodes are setup, and if not, allocate them,
1173 * and change the superblock accordingly.
1174 */
1175 if ((error = xfs_qm_init_quotainos(mp))) {
1176 kmem_free(qinf, sizeof(xfs_quotainfo_t));
1177 mp->m_quotainfo = NULL;
1178 return (error);
1179 }
1180
1181 spinlock_init(&qinf->qi_pinlock, "xfs_qinf_pin");
1182 xfs_qm_list_init(&qinf->qi_dqlist, "mpdqlist", 0);
1183 qinf->qi_dqreclaims = 0;
1184
1185 /* mutex used to serialize quotaoffs */
1186 mutex_init(&qinf->qi_quotaofflock, MUTEX_DEFAULT, "qoff");
1187
1188 /* Precalc some constants */
1189 qinf->qi_dqchunklen = XFS_FSB_TO_BB(mp, XFS_DQUOT_CLUSTER_SIZE_FSB);
1190 ASSERT(qinf->qi_dqchunklen);
1191 qinf->qi_dqperchunk = BBTOB(qinf->qi_dqchunklen);
1192 do_div(qinf->qi_dqperchunk, sizeof(xfs_dqblk_t));
1193
1194 mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD);
1195
1196 /*
1197 * We try to get the limits from the superuser's limits fields.
1198 * This is quite hacky, but it is standard quota practice.
1199 * We look at the USR dquot with id == 0 first, but if user quotas
1200 * are not enabled we goto the GRP dquot with id == 0.
1201 * We don't really care to keep separate default limits for user
1202 * and group quotas, at least not at this point.
1203 */
1204 error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)0,
1205 (XFS_IS_UQUOTA_RUNNING(mp)) ?
1206 XFS_DQ_USER : XFS_DQ_GROUP,
1207 XFS_QMOPT_DQSUSER|XFS_QMOPT_DOWARN,
1208 &dqp);
1209 if (! error) {
1210 xfs_disk_dquot_t *ddqp = &dqp->q_core;
1211
1212 /*
1213 * The warnings and timers set the grace period given to
1214 * a user or group before he or she can not perform any
1215 * more writing. If it is zero, a default is used.
1216 */
1217 qinf->qi_btimelimit =
1218 INT_GET(ddqp->d_btimer, ARCH_CONVERT) ?
1219 INT_GET(ddqp->d_btimer, ARCH_CONVERT) :
1220 XFS_QM_BTIMELIMIT;
1221 qinf->qi_itimelimit =
1222 INT_GET(ddqp->d_itimer, ARCH_CONVERT) ?
1223 INT_GET(ddqp->d_itimer, ARCH_CONVERT) :
1224 XFS_QM_ITIMELIMIT;
1225 qinf->qi_rtbtimelimit =
1226 INT_GET(ddqp->d_rtbtimer, ARCH_CONVERT) ?
1227 INT_GET(ddqp->d_rtbtimer, ARCH_CONVERT) :
1228 XFS_QM_RTBTIMELIMIT;
1229 qinf->qi_bwarnlimit =
1230 INT_GET(ddqp->d_bwarns, ARCH_CONVERT) ?
1231 INT_GET(ddqp->d_bwarns, ARCH_CONVERT) :
1232 XFS_QM_BWARNLIMIT;
1233 qinf->qi_iwarnlimit =
1234 INT_GET(ddqp->d_iwarns, ARCH_CONVERT) ?
1235 INT_GET(ddqp->d_iwarns, ARCH_CONVERT) :
1236 XFS_QM_IWARNLIMIT;
1237 qinf->qi_bhardlimit =
1238 INT_GET(ddqp->d_blk_hardlimit, ARCH_CONVERT);
1239 qinf->qi_bsoftlimit =
1240 INT_GET(ddqp->d_blk_softlimit, ARCH_CONVERT);
1241 qinf->qi_ihardlimit =
1242 INT_GET(ddqp->d_ino_hardlimit, ARCH_CONVERT);
1243 qinf->qi_isoftlimit =
1244 INT_GET(ddqp->d_ino_softlimit, ARCH_CONVERT);
1245 qinf->qi_rtbhardlimit =
1246 INT_GET(ddqp->d_rtb_hardlimit, ARCH_CONVERT);
1247 qinf->qi_rtbsoftlimit =
1248 INT_GET(ddqp->d_rtb_softlimit, ARCH_CONVERT);
1249
1250 /*
1251 * We sent the XFS_QMOPT_DQSUSER flag to dqget because
1252 * we don't want this dquot cached. We haven't done a
1253 * quotacheck yet, and quotacheck doesn't like incore dquots.
1254 */
1255 xfs_qm_dqdestroy(dqp);
1256 } else {
1257 qinf->qi_btimelimit = XFS_QM_BTIMELIMIT;
1258 qinf->qi_itimelimit = XFS_QM_ITIMELIMIT;
1259 qinf->qi_rtbtimelimit = XFS_QM_RTBTIMELIMIT;
1260 qinf->qi_bwarnlimit = XFS_QM_BWARNLIMIT;
1261 qinf->qi_iwarnlimit = XFS_QM_IWARNLIMIT;
1262 }
1263
1264 return (0);
1265}
1266
1267
1268/*
1269 * Gets called when unmounting a filesystem or when all quotas get
1270 * turned off.
1271 * This purges the quota inodes, destroys locks and frees itself.
1272 */
1273void
1274xfs_qm_destroy_quotainfo(
1275 xfs_mount_t *mp)
1276{
1277 xfs_quotainfo_t *qi;
1278
1279 qi = mp->m_quotainfo;
1280 ASSERT(qi != NULL);
1281 ASSERT(xfs_Gqm != NULL);
1282
1283 /*
1284 * Release the reference that XQM kept, so that we know
1285 * when the XQM structure should be freed. We cannot assume
1286 * that xfs_Gqm is non-null after this point.
1287 */
1288 xfs_qm_rele_quotafs_ref(mp);
1289
1290 spinlock_destroy(&qi->qi_pinlock);
1291 xfs_qm_list_destroy(&qi->qi_dqlist);
1292
1293 if (qi->qi_uquotaip) {
1294 XFS_PURGE_INODE(qi->qi_uquotaip);
1295 qi->qi_uquotaip = NULL; /* paranoia */
1296 }
1297 if (qi->qi_gquotaip) {
1298 XFS_PURGE_INODE(qi->qi_gquotaip);
1299 qi->qi_gquotaip = NULL;
1300 }
1301 mutex_destroy(&qi->qi_quotaofflock);
1302 kmem_free(qi, sizeof(xfs_quotainfo_t));
1303 mp->m_quotainfo = NULL;
1304}
1305
1306
1307
1308/* ------------------- PRIVATE STATIC FUNCTIONS ----------------------- */
1309
1310/* ARGSUSED */
1311STATIC void
1312xfs_qm_list_init(
1313 xfs_dqlist_t *list,
1314 char *str,
1315 int n)
1316{
1317 mutex_init(&list->qh_lock, MUTEX_DEFAULT, str);
1318 list->qh_next = NULL;
1319 list->qh_version = 0;
1320 list->qh_nelems = 0;
1321}
1322
1323STATIC void
1324xfs_qm_list_destroy(
1325 xfs_dqlist_t *list)
1326{
1327 mutex_destroy(&(list->qh_lock));
1328}
1329
1330
1331/*
1332 * Stripped down version of dqattach. This doesn't attach, or even look at the
1333 * dquots attached to the inode. The rationale is that there won't be any
1334 * attached at the time this is called from quotacheck.
1335 */
1336STATIC int
1337xfs_qm_dqget_noattach(
1338 xfs_inode_t *ip,
1339 xfs_dquot_t **O_udqpp,
1340 xfs_dquot_t **O_gdqpp)
1341{
1342 int error;
1343 xfs_mount_t *mp;
1344 xfs_dquot_t *udqp, *gdqp;
1345
1346 ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
1347 mp = ip->i_mount;
1348 udqp = NULL;
1349 gdqp = NULL;
1350
1351 if (XFS_IS_UQUOTA_ON(mp)) {
1352 ASSERT(ip->i_udquot == NULL);
1353 /*
1354 * We want the dquot allocated if it doesn't exist.
1355 */
1356 if ((error = xfs_qm_dqget(mp, ip, ip->i_d.di_uid, XFS_DQ_USER,
1357 XFS_QMOPT_DQALLOC | XFS_QMOPT_DOWARN,
1358 &udqp))) {
1359 /*
1360 * Shouldn't be able to turn off quotas here.
1361 */
1362 ASSERT(error != ESRCH);
1363 ASSERT(error != ENOENT);
1364 return (error);
1365 }
1366 ASSERT(udqp);
1367 }
1368
1369 if (XFS_IS_GQUOTA_ON(mp)) {
1370 ASSERT(ip->i_gdquot == NULL);
1371 if (udqp)
1372 xfs_dqunlock(udqp);
1373 if ((error = xfs_qm_dqget(mp, ip, ip->i_d.di_gid, XFS_DQ_GROUP,
1374 XFS_QMOPT_DQALLOC|XFS_QMOPT_DOWARN,
1375 &gdqp))) {
1376 if (udqp)
1377 xfs_qm_dqrele(udqp);
1378 ASSERT(error != ESRCH);
1379 ASSERT(error != ENOENT);
1380 return (error);
1381 }
1382 ASSERT(gdqp);
1383
1384 /* Reacquire the locks in the right order */
1385 if (udqp) {
1386 if (! xfs_qm_dqlock_nowait(udqp)) {
1387 xfs_dqunlock(gdqp);
1388 xfs_dqlock(udqp);
1389 xfs_dqlock(gdqp);
1390 }
1391 }
1392 }
1393
1394 *O_udqpp = udqp;
1395 *O_gdqpp = gdqp;
1396
1397#ifdef QUOTADEBUG
1398 if (udqp) ASSERT(XFS_DQ_IS_LOCKED(udqp));
1399 if (gdqp) ASSERT(XFS_DQ_IS_LOCKED(gdqp));
1400#endif
1401 return (0);
1402}
1403
1404/*
1405 * Create an inode and return with a reference already taken, but unlocked
1406 * This is how we create quota inodes
1407 */
1408STATIC int
1409xfs_qm_qino_alloc(
1410 xfs_mount_t *mp,
1411 xfs_inode_t **ip,
1412 __int64_t sbfields,
1413 uint flags)
1414{
1415 xfs_trans_t *tp;
1416 int error;
1417 unsigned long s;
1418 cred_t zerocr;
1419 int committed;
1420
1421 tp = xfs_trans_alloc(mp,XFS_TRANS_QM_QINOCREATE);
1422 if ((error = xfs_trans_reserve(tp,
1423 XFS_QM_QINOCREATE_SPACE_RES(mp),
1424 XFS_CREATE_LOG_RES(mp), 0,
1425 XFS_TRANS_PERM_LOG_RES,
1426 XFS_CREATE_LOG_COUNT))) {
1427 xfs_trans_cancel(tp, 0);
1428 return (error);
1429 }
1430 memset(&zerocr, 0, sizeof(zerocr));
1431
1432 if ((error = xfs_dir_ialloc(&tp, mp->m_rootip, S_IFREG, 1, 0,
1433 &zerocr, 0, 1, ip, &committed))) {
1434 xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES |
1435 XFS_TRANS_ABORT);
1436 return (error);
1437 }
1438
1439 /*
1440 * Keep an extra reference to this quota inode. This inode is
1441 * locked exclusively and joined to the transaction already.
1442 */
1443 ASSERT(XFS_ISLOCKED_INODE_EXCL(*ip));
1444 VN_HOLD(XFS_ITOV((*ip)));
1445
1446 /*
1447 * Make the changes in the superblock, and log those too.
1448 * sbfields arg may contain fields other than *QUOTINO;
1449 * VERSIONNUM for example.
1450 */
1451 s = XFS_SB_LOCK(mp);
1452 if (flags & XFS_QMOPT_SBVERSION) {
1453#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
1454 unsigned oldv = mp->m_sb.sb_versionnum;
1455#endif
1456 ASSERT(!XFS_SB_VERSION_HASQUOTA(&mp->m_sb));
1457 ASSERT((sbfields & (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
1458 XFS_SB_GQUOTINO | XFS_SB_QFLAGS)) ==
1459 (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
1460 XFS_SB_GQUOTINO | XFS_SB_QFLAGS));
1461
1462 XFS_SB_VERSION_ADDQUOTA(&mp->m_sb);
1463 mp->m_sb.sb_uquotino = NULLFSINO;
1464 mp->m_sb.sb_gquotino = NULLFSINO;
1465
1466 /* qflags will get updated _after_ quotacheck */
1467 mp->m_sb.sb_qflags = 0;
1468#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
1469 cmn_err(CE_NOTE,
1470 "Old superblock version %x, converting to %x.",
1471 oldv, mp->m_sb.sb_versionnum);
1472#endif
1473 }
1474 if (flags & XFS_QMOPT_UQUOTA)
1475 mp->m_sb.sb_uquotino = (*ip)->i_ino;
1476 else
1477 mp->m_sb.sb_gquotino = (*ip)->i_ino;
1478 XFS_SB_UNLOCK(mp, s);
1479 xfs_mod_sb(tp, sbfields);
1480
1481 if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES,
1482 NULL))) {
1483 xfs_fs_cmn_err(CE_ALERT, mp, "XFS qino_alloc failed!");
1484 return (error);
1485 }
1486 return (0);
1487}
1488
1489
1490STATIC int
1491xfs_qm_reset_dqcounts(
1492 xfs_mount_t *mp,
1493 xfs_buf_t *bp,
1494 xfs_dqid_t id,
1495 uint type)
1496{
1497 xfs_disk_dquot_t *ddq;
1498 int j;
1499
1500 xfs_buftrace("RESET DQUOTS", bp);
1501 /*
1502 * Reset all counters and timers. They'll be
1503 * started afresh by xfs_qm_quotacheck.
1504 */
1505#ifdef DEBUG
1506 j = XFS_FSB_TO_B(mp, XFS_DQUOT_CLUSTER_SIZE_FSB);
1507 do_div(j, sizeof(xfs_dqblk_t));
1508 ASSERT(XFS_QM_DQPERBLK(mp) == j);
1509#endif
1510 ddq = (xfs_disk_dquot_t *)XFS_BUF_PTR(bp);
1511 for (j = 0; j < XFS_QM_DQPERBLK(mp); j++) {
1512 /*
1513 * Do a sanity check, and if needed, repair the dqblk. Don't
1514 * output any warnings because it's perfectly possible to
1515 * find unitialized dquot blks. See comment in xfs_qm_dqcheck.
1516 */
1517 (void) xfs_qm_dqcheck(ddq, id+j, type, XFS_QMOPT_DQREPAIR,
1518 "xfs_quotacheck");
1519 INT_SET(ddq->d_bcount, ARCH_CONVERT, 0ULL);
1520 INT_SET(ddq->d_icount, ARCH_CONVERT, 0ULL);
1521 INT_SET(ddq->d_rtbcount, ARCH_CONVERT, 0ULL);
1522 INT_SET(ddq->d_btimer, ARCH_CONVERT, (time_t)0);
1523 INT_SET(ddq->d_itimer, ARCH_CONVERT, (time_t)0);
1524 INT_SET(ddq->d_bwarns, ARCH_CONVERT, 0UL);
1525 INT_SET(ddq->d_iwarns, ARCH_CONVERT, 0UL);
1526 ddq = (xfs_disk_dquot_t *) ((xfs_dqblk_t *)ddq + 1);
1527 }
1528
1529 return (0);
1530}
1531
1532STATIC int
1533xfs_qm_dqiter_bufs(
1534 xfs_mount_t *mp,
1535 xfs_dqid_t firstid,
1536 xfs_fsblock_t bno,
1537 xfs_filblks_t blkcnt,
1538 uint flags)
1539{
1540 xfs_buf_t *bp;
1541 int error;
1542 int notcommitted;
1543 int incr;
1544
1545 ASSERT(blkcnt > 0);
1546 notcommitted = 0;
1547 incr = (blkcnt > XFS_QM_MAX_DQCLUSTER_LOGSZ) ?
1548 XFS_QM_MAX_DQCLUSTER_LOGSZ : blkcnt;
1549 error = 0;
1550
1551 /*
1552 * Blkcnt arg can be a very big number, and might even be
1553 * larger than the log itself. So, we have to break it up into
1554 * manageable-sized transactions.
1555 * Note that we don't start a permanent transaction here; we might
1556 * not be able to get a log reservation for the whole thing up front,
1557 * and we don't really care to either, because we just discard
1558 * everything if we were to crash in the middle of this loop.
1559 */
1560 while (blkcnt--) {
1561 error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,
1562 XFS_FSB_TO_DADDR(mp, bno),
1563 (int)XFS_QI_DQCHUNKLEN(mp), 0, &bp);
1564 if (error)
1565 break;
1566
1567 (void) xfs_qm_reset_dqcounts(mp, bp, firstid,
1568 flags & XFS_QMOPT_UQUOTA ?
1569 XFS_DQ_USER : XFS_DQ_GROUP);
1570 xfs_bdwrite(mp, bp);
1571 /*
1572 * goto the next block.
1573 */
1574 bno++;
1575 firstid += XFS_QM_DQPERBLK(mp);
1576 }
1577 return (error);
1578}
1579
1580/*
1581 * Iterate over all allocated USR/GRP dquots in the system, calling a
1582 * caller supplied function for every chunk of dquots that we find.
1583 */
1584STATIC int
1585xfs_qm_dqiterate(
1586 xfs_mount_t *mp,
1587 xfs_inode_t *qip,
1588 uint flags)
1589{
1590 xfs_bmbt_irec_t *map;
1591 int i, nmaps; /* number of map entries */
1592 int error; /* return value */
1593 xfs_fileoff_t lblkno;
1594 xfs_filblks_t maxlblkcnt;
1595 xfs_dqid_t firstid;
1596 xfs_fsblock_t rablkno;
1597 xfs_filblks_t rablkcnt;
1598
1599 error = 0;
1600 /*
1601 * This looks racey, but we can't keep an inode lock across a
1602 * trans_reserve. But, this gets called during quotacheck, and that
1603 * happens only at mount time which is single threaded.
1604 */
1605 if (qip->i_d.di_nblocks == 0)
1606 return (0);
1607
1608 map = kmem_alloc(XFS_DQITER_MAP_SIZE * sizeof(*map), KM_SLEEP);
1609
1610 lblkno = 0;
1611 maxlblkcnt = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp));
1612 do {
1613 nmaps = XFS_DQITER_MAP_SIZE;
1614 /*
1615 * We aren't changing the inode itself. Just changing
1616 * some of its data. No new blocks are added here, and
1617 * the inode is never added to the transaction.
1618 */
1619 xfs_ilock(qip, XFS_ILOCK_SHARED);
1620 error = xfs_bmapi(NULL, qip, lblkno,
1621 maxlblkcnt - lblkno,
1622 XFS_BMAPI_METADATA,
1623 NULL,
1624 0, map, &nmaps, NULL);
1625 xfs_iunlock(qip, XFS_ILOCK_SHARED);
1626 if (error)
1627 break;
1628
1629 ASSERT(nmaps <= XFS_DQITER_MAP_SIZE);
1630 for (i = 0; i < nmaps; i++) {
1631 ASSERT(map[i].br_startblock != DELAYSTARTBLOCK);
1632 ASSERT(map[i].br_blockcount);
1633
1634
1635 lblkno += map[i].br_blockcount;
1636
1637 if (map[i].br_startblock == HOLESTARTBLOCK)
1638 continue;
1639
1640 firstid = (xfs_dqid_t) map[i].br_startoff *
1641 XFS_QM_DQPERBLK(mp);
1642 /*
1643 * Do a read-ahead on the next extent.
1644 */
1645 if ((i+1 < nmaps) &&
1646 (map[i+1].br_startblock != HOLESTARTBLOCK)) {
1647 rablkcnt = map[i+1].br_blockcount;
1648 rablkno = map[i+1].br_startblock;
1649 while (rablkcnt--) {
1650 xfs_baread(mp->m_ddev_targp,
1651 XFS_FSB_TO_DADDR(mp, rablkno),
1652 (int)XFS_QI_DQCHUNKLEN(mp));
1653 rablkno++;
1654 }
1655 }
1656 /*
1657 * Iterate thru all the blks in the extent and
1658 * reset the counters of all the dquots inside them.
1659 */
1660 if ((error = xfs_qm_dqiter_bufs(mp,
1661 firstid,
1662 map[i].br_startblock,
1663 map[i].br_blockcount,
1664 flags))) {
1665 break;
1666 }
1667 }
1668
1669 if (error)
1670 break;
1671 } while (nmaps > 0);
1672
1673 kmem_free(map, XFS_DQITER_MAP_SIZE * sizeof(*map));
1674
1675 return (error);
1676}
1677
1678/*
1679 * Called by dqusage_adjust in doing a quotacheck.
1680 * Given the inode, and a dquot (either USR or GRP, doesn't matter),
1681 * this updates its incore copy as well as the buffer copy. This is
1682 * so that once the quotacheck is done, we can just log all the buffers,
1683 * as opposed to logging numerous updates to individual dquots.
1684 */
1685STATIC void
1686xfs_qm_quotacheck_dqadjust(
1687 xfs_dquot_t *dqp,
1688 xfs_qcnt_t nblks,
1689 xfs_qcnt_t rtblks)
1690{
1691 ASSERT(XFS_DQ_IS_LOCKED(dqp));
1692 xfs_dqtrace_entry(dqp, "QCHECK DQADJUST");
1693 /*
1694 * Adjust the inode count and the block count to reflect this inode's
1695 * resource usage.
1696 */
1697 INT_MOD(dqp->q_core.d_icount, ARCH_CONVERT, +1);
1698 dqp->q_res_icount++;
1699 if (nblks) {
1700 INT_MOD(dqp->q_core.d_bcount, ARCH_CONVERT, nblks);
1701 dqp->q_res_bcount += nblks;
1702 }
1703 if (rtblks) {
1704 INT_MOD(dqp->q_core.d_rtbcount, ARCH_CONVERT, rtblks);
1705 dqp->q_res_rtbcount += rtblks;
1706 }
1707
1708 /*
1709 * Set default limits, adjust timers (since we changed usages)
1710 */
1711 if (! XFS_IS_SUSER_DQUOT(dqp)) {
1712 xfs_qm_adjust_dqlimits(dqp->q_mount, &dqp->q_core);
1713 xfs_qm_adjust_dqtimers(dqp->q_mount, &dqp->q_core);
1714 }
1715
1716 dqp->dq_flags |= XFS_DQ_DIRTY;
1717}
1718
1719STATIC int
1720xfs_qm_get_rtblks(
1721 xfs_inode_t *ip,
1722 xfs_qcnt_t *O_rtblks)
1723{
1724 xfs_filblks_t rtblks; /* total rt blks */
1725 xfs_ifork_t *ifp; /* inode fork pointer */
1726 xfs_extnum_t nextents; /* number of extent entries */
1727 xfs_bmbt_rec_t *base; /* base of extent array */
1728 xfs_bmbt_rec_t *ep; /* pointer to an extent entry */
1729 int error;
1730
1731 ASSERT(XFS_IS_REALTIME_INODE(ip));
1732 ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
1733 if (!(ifp->if_flags & XFS_IFEXTENTS)) {
1734 if ((error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK)))
1735 return (error);
1736 }
1737 rtblks = 0;
1738 nextents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t);
1739 base = &ifp->if_u1.if_extents[0];
1740 for (ep = base; ep < &base[nextents]; ep++)
1741 rtblks += xfs_bmbt_get_blockcount(ep);
1742 *O_rtblks = (xfs_qcnt_t)rtblks;
1743 return (0);
1744}
1745
1746/*
1747 * callback routine supplied to bulkstat(). Given an inumber, find its
1748 * dquots and update them to account for resources taken by that inode.
1749 */
1750/* ARGSUSED */
1751STATIC int
1752xfs_qm_dqusage_adjust(
1753 xfs_mount_t *mp, /* mount point for filesystem */
1754 xfs_ino_t ino, /* inode number to get data for */
1755 void __user *buffer, /* not used */
1756 int ubsize, /* not used */
1757 void *private_data, /* not used */
1758 xfs_daddr_t bno, /* starting block of inode cluster */
1759 int *ubused, /* not used */
1760 void *dip, /* on-disk inode pointer (not used) */
1761 int *res) /* result code value */
1762{
1763 xfs_inode_t *ip;
1764 xfs_dquot_t *udqp, *gdqp;
1765 xfs_qcnt_t nblks, rtblks;
1766 int error;
1767
1768 ASSERT(XFS_IS_QUOTA_RUNNING(mp));
1769
1770 /*
1771 * rootino must have its resources accounted for, not so with the quota
1772 * inodes.
1773 */
1774 if (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino) {
1775 *res = BULKSTAT_RV_NOTHING;
1776 return XFS_ERROR(EINVAL);
1777 }
1778
1779 /*
1780 * We don't _need_ to take the ilock EXCL. However, the xfs_qm_dqget
1781 * interface expects the inode to be exclusively locked because that's
1782 * the case in all other instances. It's OK that we do this because
1783 * quotacheck is done only at mount time.
1784 */
1785 if ((error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_EXCL, &ip, bno))) {
1786 *res = BULKSTAT_RV_NOTHING;
1787 return (error);
1788 }
1789
1790 if (ip->i_d.di_mode == 0) {
1791 xfs_iput_new(ip, XFS_ILOCK_EXCL);
1792 *res = BULKSTAT_RV_NOTHING;
1793 return XFS_ERROR(ENOENT);
1794 }
1795
1796 /*
1797 * Obtain the locked dquots. In case of an error (eg. allocation
1798 * fails for ENOSPC), we return the negative of the error number
1799 * to bulkstat, so that it can get propagated to quotacheck() and
1800 * making us disable quotas for the file system.
1801 */
1802 if ((error = xfs_qm_dqget_noattach(ip, &udqp, &gdqp))) {
1803 xfs_iput(ip, XFS_ILOCK_EXCL);
1804 *res = BULKSTAT_RV_GIVEUP;
1805 return (error);
1806 }
1807
1808 rtblks = 0;
1809 if (! XFS_IS_REALTIME_INODE(ip)) {
1810 nblks = (xfs_qcnt_t)ip->i_d.di_nblocks;
1811 } else {
1812 /*
1813 * Walk thru the extent list and count the realtime blocks.
1814 */
1815 if ((error = xfs_qm_get_rtblks(ip, &rtblks))) {
1816 xfs_iput(ip, XFS_ILOCK_EXCL);
1817 if (udqp)
1818 xfs_qm_dqput(udqp);
1819 if (gdqp)
1820 xfs_qm_dqput(gdqp);
1821 *res = BULKSTAT_RV_GIVEUP;
1822 return (error);
1823 }
1824 nblks = (xfs_qcnt_t)ip->i_d.di_nblocks - rtblks;
1825 }
1826 ASSERT(ip->i_delayed_blks == 0);
1827
1828 /*
1829 * We can't release the inode while holding its dquot locks.
1830 * The inode can go into inactive and might try to acquire the dquotlocks.
1831 * So, just unlock here and do a vn_rele at the end.
1832 */
1833 xfs_iunlock(ip, XFS_ILOCK_EXCL);
1834
1835 /*
1836 * Add the (disk blocks and inode) resources occupied by this
1837 * inode to its dquots. We do this adjustment in the incore dquot,
1838 * and also copy the changes to its buffer.
1839 * We don't care about putting these changes in a transaction
1840 * envelope because if we crash in the middle of a 'quotacheck'
1841 * we have to start from the beginning anyway.
1842 * Once we're done, we'll log all the dquot bufs.
1843 *
1844 * The *QUOTA_ON checks below may look pretty racey, but quotachecks
1845 * and quotaoffs don't race. (Quotachecks happen at mount time only).
1846 */
1847 if (XFS_IS_UQUOTA_ON(mp)) {
1848 ASSERT(udqp);
1849 xfs_qm_quotacheck_dqadjust(udqp, nblks, rtblks);
1850 xfs_qm_dqput(udqp);
1851 }
1852 if (XFS_IS_GQUOTA_ON(mp)) {
1853 ASSERT(gdqp);
1854 xfs_qm_quotacheck_dqadjust(gdqp, nblks, rtblks);
1855 xfs_qm_dqput(gdqp);
1856 }
1857 /*
1858 * Now release the inode. This will send it to 'inactive', and
1859 * possibly even free blocks.
1860 */
1861 VN_RELE(XFS_ITOV(ip));
1862
1863 /*
1864 * Goto next inode.
1865 */
1866 *res = BULKSTAT_RV_DIDONE;
1867 return (0);
1868}
1869
1870/*
1871 * Walk thru all the filesystem inodes and construct a consistent view
1872 * of the disk quota world. If the quotacheck fails, disable quotas.
1873 */
1874int
1875xfs_qm_quotacheck(
1876 xfs_mount_t *mp)
1877{
1878 int done, count, error;
1879 xfs_ino_t lastino;
1880 size_t structsz;
1881 xfs_inode_t *uip, *gip;
1882 uint flags;
1883
1884 count = INT_MAX;
1885 structsz = 1;
1886 lastino = 0;
1887 flags = 0;
1888
1889 ASSERT(XFS_QI_UQIP(mp) || XFS_QI_GQIP(mp));
1890 ASSERT(XFS_IS_QUOTA_RUNNING(mp));
1891
1892 /*
1893 * There should be no cached dquots. The (simplistic) quotacheck
1894 * algorithm doesn't like that.
1895 */
1896 ASSERT(XFS_QI_MPLNDQUOTS(mp) == 0);
1897
1898 cmn_err(CE_NOTE, "XFS quotacheck %s: Please wait.", mp->m_fsname);
1899
1900 /*
1901 * First we go thru all the dquots on disk, USR and GRP, and reset
1902 * their counters to zero. We need a clean slate.
1903 * We don't log our changes till later.
1904 */
1905 if ((uip = XFS_QI_UQIP(mp))) {
1906 if ((error = xfs_qm_dqiterate(mp, uip, XFS_QMOPT_UQUOTA)))
1907 goto error_return;
1908 flags |= XFS_UQUOTA_CHKD;
1909 }
1910
1911 if ((gip = XFS_QI_GQIP(mp))) {
1912 if ((error = xfs_qm_dqiterate(mp, gip, XFS_QMOPT_GQUOTA)))
1913 goto error_return;
1914 flags |= XFS_GQUOTA_CHKD;
1915 }
1916
1917 do {
1918 /*
1919 * Iterate thru all the inodes in the file system,
1920 * adjusting the corresponding dquot counters in core.
1921 */
1922 if ((error = xfs_bulkstat(mp, &lastino, &count,
1923 xfs_qm_dqusage_adjust, NULL,
1924 structsz, NULL,
1925 BULKSTAT_FG_IGET|BULKSTAT_FG_VFSLOCKED,
1926 &done)))
1927 break;
1928
1929 } while (! done);
1930
1931 /*
1932 * We can get this error if we couldn't do a dquot allocation inside
1933 * xfs_qm_dqusage_adjust (via bulkstat). We don't care about the
1934 * dirty dquots that might be cached, we just want to get rid of them
1935 * and turn quotaoff. The dquots won't be attached to any of the inodes
1936 * at this point (because we intentionally didn't in dqget_noattach).
1937 */
1938 if (error) {
1939 xfs_qm_dqpurge_all(mp,
1940 XFS_QMOPT_UQUOTA|XFS_QMOPT_GQUOTA|
1941 XFS_QMOPT_QUOTAOFF);
1942 goto error_return;
1943 }
1944 /*
1945 * We've made all the changes that we need to make incore.
1946 * Now flush_them down to disk buffers.
1947 */
1948 xfs_qm_dqflush_all(mp, XFS_QMOPT_DELWRI);
1949
1950 /*
1951 * We didn't log anything, because if we crashed, we'll have to
1952 * start the quotacheck from scratch anyway. However, we must make
1953 * sure that our dquot changes are secure before we put the
1954 * quotacheck'd stamp on the superblock. So, here we do a synchronous
1955 * flush.
1956 */
1957 XFS_bflush(mp->m_ddev_targp);
1958
1959 /*
1960 * If one type of quotas is off, then it will lose its
1961 * quotachecked status, since we won't be doing accounting for
1962 * that type anymore.
1963 */
1964 mp->m_qflags &= ~(XFS_GQUOTA_CHKD | XFS_UQUOTA_CHKD);
1965 mp->m_qflags |= flags;
1966
1967 XQM_LIST_PRINT(&(XFS_QI_MPL_LIST(mp)), MPL_NEXT, "++++ Mp list +++");
1968
1969 error_return:
1970 if (error) {
1971 cmn_err(CE_WARN, "XFS quotacheck %s: Unsuccessful (Error %d): "
1972 "Disabling quotas.",
1973 mp->m_fsname, error);
1974 /*
1975 * We must turn off quotas.
1976 */
1977 ASSERT(mp->m_quotainfo != NULL);
1978 ASSERT(xfs_Gqm != NULL);
1979 xfs_qm_destroy_quotainfo(mp);
1980 xfs_mount_reset_sbqflags(mp);
1981 } else {
1982 cmn_err(CE_NOTE, "XFS quotacheck %s: Done.", mp->m_fsname);
1983 }
1984 return (error);
1985}
1986
1987/*
1988 * This is called after the superblock has been read in and we're ready to
1989 * iget the quota inodes.
1990 */
1991STATIC int
1992xfs_qm_init_quotainos(
1993 xfs_mount_t *mp)
1994{
1995 xfs_inode_t *uip, *gip;
1996 int error;
1997 __int64_t sbflags;
1998 uint flags;
1999
2000 ASSERT(mp->m_quotainfo);
2001 uip = gip = NULL;
2002 sbflags = 0;
2003 flags = 0;
2004
2005 /*
2006 * Get the uquota and gquota inodes
2007 */
2008 if (XFS_SB_VERSION_HASQUOTA(&mp->m_sb)) {
2009 if (XFS_IS_UQUOTA_ON(mp) &&
2010 mp->m_sb.sb_uquotino != NULLFSINO) {
2011 ASSERT(mp->m_sb.sb_uquotino > 0);
2012 if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
2013 0, 0, &uip, 0)))
2014 return XFS_ERROR(error);
2015 }
2016 if (XFS_IS_GQUOTA_ON(mp) &&
2017 mp->m_sb.sb_gquotino != NULLFSINO) {
2018 ASSERT(mp->m_sb.sb_gquotino > 0);
2019 if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
2020 0, 0, &gip, 0))) {
2021 if (uip)
2022 VN_RELE(XFS_ITOV(uip));
2023 return XFS_ERROR(error);
2024 }
2025 }
2026 } else {
2027 flags |= XFS_QMOPT_SBVERSION;
2028 sbflags |= (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
2029 XFS_SB_GQUOTINO | XFS_SB_QFLAGS);
2030 }
2031
2032 /*
2033 * Create the two inodes, if they don't exist already. The changes
2034 * made above will get added to a transaction and logged in one of
2035 * the qino_alloc calls below. If the device is readonly,
2036 * temporarily switch to read-write to do this.
2037 */
2038 if (XFS_IS_UQUOTA_ON(mp) && uip == NULL) {
2039 if ((error = xfs_qm_qino_alloc(mp, &uip,
2040 sbflags | XFS_SB_UQUOTINO,
2041 flags | XFS_QMOPT_UQUOTA)))
2042 return XFS_ERROR(error);
2043
2044 flags &= ~XFS_QMOPT_SBVERSION;
2045 }
2046 if (XFS_IS_GQUOTA_ON(mp) && gip == NULL) {
2047 if ((error = xfs_qm_qino_alloc(mp, &gip,
2048 sbflags | XFS_SB_GQUOTINO,
2049 flags | XFS_QMOPT_GQUOTA))) {
2050 if (uip)
2051 VN_RELE(XFS_ITOV(uip));
2052
2053 return XFS_ERROR(error);
2054 }
2055 }
2056
2057 XFS_QI_UQIP(mp) = uip;
2058 XFS_QI_GQIP(mp) = gip;
2059
2060 return (0);
2061}
2062
2063
2064/*
2065 * Traverse the freelist of dquots and attempt to reclaim a maximum of
2066 * 'howmany' dquots. This operation races with dqlookup(), and attempts to
2067 * favor the lookup function ...
2068 * XXXsup merge this with qm_reclaim_one().
2069 */
2070STATIC int
2071xfs_qm_shake_freelist(
2072 int howmany)
2073{
2074 int nreclaimed;
2075 xfs_dqhash_t *hash;
2076 xfs_dquot_t *dqp, *nextdqp;
2077 int restarts;
2078 int nflushes;
2079
2080 if (howmany <= 0)
2081 return (0);
2082
2083 nreclaimed = 0;
2084 restarts = 0;
2085 nflushes = 0;
2086
2087#ifdef QUOTADEBUG
2088 cmn_err(CE_DEBUG, "Shake free 0x%x", howmany);
2089#endif
2090 /* lock order is : hashchainlock, freelistlock, mplistlock */
2091 tryagain:
2092 xfs_qm_freelist_lock(xfs_Gqm);
2093
2094 for (dqp = xfs_Gqm->qm_dqfreelist.qh_next;
2095 ((dqp != (xfs_dquot_t *) &xfs_Gqm->qm_dqfreelist) &&
2096 nreclaimed < howmany); ) {
2097 xfs_dqlock(dqp);
2098
2099 /*
2100 * We are racing with dqlookup here. Naturally we don't
2101 * want to reclaim a dquot that lookup wants.
2102 */
2103 if (dqp->dq_flags & XFS_DQ_WANT) {
2104 xfs_dqunlock(dqp);
2105 xfs_qm_freelist_unlock(xfs_Gqm);
2106 if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
2107 return (nreclaimed);
2108 XQM_STATS_INC(xqmstats.xs_qm_dqwants);
2109 goto tryagain;
2110 }
2111
2112 /*
2113 * If the dquot is inactive, we are assured that it is
2114 * not on the mplist or the hashlist, and that makes our
2115 * life easier.
2116 */
2117 if (dqp->dq_flags & XFS_DQ_INACTIVE) {
2118 ASSERT(dqp->q_mount == NULL);
2119 ASSERT(! XFS_DQ_IS_DIRTY(dqp));
2120 ASSERT(dqp->HL_PREVP == NULL);
2121 ASSERT(dqp->MPL_PREVP == NULL);
2122 XQM_STATS_INC(xqmstats.xs_qm_dqinact_reclaims);
2123 nextdqp = dqp->dq_flnext;
2124 goto off_freelist;
2125 }
2126
2127 ASSERT(dqp->MPL_PREVP);
2128 /*
2129 * Try to grab the flush lock. If this dquot is in the process of
2130 * getting flushed to disk, we don't want to reclaim it.
2131 */
2132 if (! xfs_qm_dqflock_nowait(dqp)) {
2133 xfs_dqunlock(dqp);
2134 dqp = dqp->dq_flnext;
2135 continue;
2136 }
2137
2138 /*
2139 * We have the flush lock so we know that this is not in the
2140 * process of being flushed. So, if this is dirty, flush it
2141 * DELWRI so that we don't get a freelist infested with
2142 * dirty dquots.
2143 */
2144 if (XFS_DQ_IS_DIRTY(dqp)) {
2145 xfs_dqtrace_entry(dqp, "DQSHAKE: DQDIRTY");
2146 /*
2147 * We flush it delayed write, so don't bother
2148 * releasing the mplock.
2149 */
2150 (void) xfs_qm_dqflush(dqp, XFS_QMOPT_DELWRI);
2151 xfs_dqunlock(dqp); /* dqflush unlocks dqflock */
2152 dqp = dqp->dq_flnext;
2153 continue;
2154 }
2155 /*
2156 * We're trying to get the hashlock out of order. This races
2157 * with dqlookup; so, we giveup and goto the next dquot if
2158 * we couldn't get the hashlock. This way, we won't starve
2159 * a dqlookup process that holds the hashlock that is
2160 * waiting for the freelist lock.
2161 */
2162 if (! xfs_qm_dqhashlock_nowait(dqp)) {
2163 xfs_dqfunlock(dqp);
2164 xfs_dqunlock(dqp);
2165 dqp = dqp->dq_flnext;
2166 continue;
2167 }
2168 /*
2169 * This races with dquot allocation code as well as dqflush_all
2170 * and reclaim code. So, if we failed to grab the mplist lock,
2171 * giveup everything and start over.
2172 */
2173 hash = dqp->q_hash;
2174 ASSERT(hash);
2175 if (! xfs_qm_mplist_nowait(dqp->q_mount)) {
2176 /* XXX put a sentinel so that we can come back here */
2177 xfs_dqfunlock(dqp);
2178 xfs_dqunlock(dqp);
2179 XFS_DQ_HASH_UNLOCK(hash);
2180 xfs_qm_freelist_unlock(xfs_Gqm);
2181 if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
2182 return (nreclaimed);
2183 goto tryagain;
2184 }
2185 xfs_dqtrace_entry(dqp, "DQSHAKE: UNLINKING");
2186#ifdef QUOTADEBUG
2187 cmn_err(CE_DEBUG, "Shake 0x%p, ID 0x%x\n",
2188 dqp, INT_GET(dqp->q_core.d_id, ARCH_CONVERT));
2189#endif
2190 ASSERT(dqp->q_nrefs == 0);
2191 nextdqp = dqp->dq_flnext;
2192 XQM_MPLIST_REMOVE(&(XFS_QI_MPL_LIST(dqp->q_mount)), dqp);
2193 XQM_HASHLIST_REMOVE(hash, dqp);
2194 xfs_dqfunlock(dqp);
2195 xfs_qm_mplist_unlock(dqp->q_mount);
2196 XFS_DQ_HASH_UNLOCK(hash);
2197
2198 off_freelist:
2199 XQM_FREELIST_REMOVE(dqp);
2200 xfs_dqunlock(dqp);
2201 nreclaimed++;
2202 XQM_STATS_INC(xqmstats.xs_qm_dqshake_reclaims);
2203 xfs_qm_dqdestroy(dqp);
2204 dqp = nextdqp;
2205 }
2206 xfs_qm_freelist_unlock(xfs_Gqm);
2207 return (nreclaimed);
2208}
2209
2210
2211/*
2212 * The kmem_shake interface is invoked when memory is running low.
2213 */
2214/* ARGSUSED */
2215STATIC int
2216xfs_qm_shake(int nr_to_scan, unsigned int gfp_mask)
2217{
2218 int ndqused, nfree, n;
2219
2220 if (!kmem_shake_allow(gfp_mask))
2221 return (0);
2222 if (!xfs_Gqm)
2223 return (0);
2224
2225 nfree = xfs_Gqm->qm_dqfreelist.qh_nelems; /* free dquots */
2226 /* incore dquots in all f/s's */
2227 ndqused = atomic_read(&xfs_Gqm->qm_totaldquots) - nfree;
2228
2229 ASSERT(ndqused >= 0);
2230
2231 if (nfree <= ndqused && nfree < ndquot)
2232 return (0);
2233
2234 ndqused *= xfs_Gqm->qm_dqfree_ratio; /* target # of free dquots */
2235 n = nfree - ndqused - ndquot; /* # over target */
2236
2237 return xfs_qm_shake_freelist(MAX(nfree, n));
2238}
2239
2240
2241/*
2242 * Just pop the least recently used dquot off the freelist and
2243 * recycle it. The returned dquot is locked.
2244 */
2245STATIC xfs_dquot_t *
2246xfs_qm_dqreclaim_one(void)
2247{
2248 xfs_dquot_t *dqpout;
2249 xfs_dquot_t *dqp;
2250 int restarts;
2251 int nflushes;
2252
2253 restarts = 0;
2254 dqpout = NULL;
2255 nflushes = 0;
2256
2257 /* lockorder: hashchainlock, freelistlock, mplistlock, dqlock, dqflock */
2258 startagain:
2259 xfs_qm_freelist_lock(xfs_Gqm);
2260
2261 FOREACH_DQUOT_IN_FREELIST(dqp, &(xfs_Gqm->qm_dqfreelist)) {
2262 xfs_dqlock(dqp);
2263
2264 /*
2265 * We are racing with dqlookup here. Naturally we don't
2266 * want to reclaim a dquot that lookup wants. We release the
2267 * freelist lock and start over, so that lookup will grab
2268 * both the dquot and the freelistlock.
2269 */
2270 if (dqp->dq_flags & XFS_DQ_WANT) {
2271 ASSERT(! (dqp->dq_flags & XFS_DQ_INACTIVE));
2272 xfs_dqtrace_entry(dqp, "DQRECLAIM: DQWANT");
2273 xfs_dqunlock(dqp);
2274 xfs_qm_freelist_unlock(xfs_Gqm);
2275 if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
2276 return (NULL);
2277 XQM_STATS_INC(xqmstats.xs_qm_dqwants);
2278 goto startagain;
2279 }
2280
2281 /*
2282 * If the dquot is inactive, we are assured that it is
2283 * not on the mplist or the hashlist, and that makes our
2284 * life easier.
2285 */
2286 if (dqp->dq_flags & XFS_DQ_INACTIVE) {
2287 ASSERT(dqp->q_mount == NULL);
2288 ASSERT(! XFS_DQ_IS_DIRTY(dqp));
2289 ASSERT(dqp->HL_PREVP == NULL);
2290 ASSERT(dqp->MPL_PREVP == NULL);
2291 XQM_FREELIST_REMOVE(dqp);
2292 xfs_dqunlock(dqp);
2293 dqpout = dqp;
2294 XQM_STATS_INC(xqmstats.xs_qm_dqinact_reclaims);
2295 break;
2296 }
2297
2298 ASSERT(dqp->q_hash);
2299 ASSERT(dqp->MPL_PREVP);
2300
2301 /*
2302 * Try to grab the flush lock. If this dquot is in the process of
2303 * getting flushed to disk, we don't want to reclaim it.
2304 */
2305 if (! xfs_qm_dqflock_nowait(dqp)) {
2306 xfs_dqunlock(dqp);
2307 continue;
2308 }
2309
2310 /*
2311 * We have the flush lock so we know that this is not in the
2312 * process of being flushed. So, if this is dirty, flush it
2313 * DELWRI so that we don't get a freelist infested with
2314 * dirty dquots.
2315 */
2316 if (XFS_DQ_IS_DIRTY(dqp)) {
2317 xfs_dqtrace_entry(dqp, "DQRECLAIM: DQDIRTY");
2318 /*
2319 * We flush it delayed write, so don't bother
2320 * releasing the freelist lock.
2321 */
2322 (void) xfs_qm_dqflush(dqp, XFS_QMOPT_DELWRI);
2323 xfs_dqunlock(dqp); /* dqflush unlocks dqflock */
2324 continue;
2325 }
2326
2327 if (! xfs_qm_mplist_nowait(dqp->q_mount)) {
2328 xfs_dqfunlock(dqp);
2329 xfs_dqunlock(dqp);
2330 continue;
2331 }
2332
2333 if (! xfs_qm_dqhashlock_nowait(dqp))
2334 goto mplistunlock;
2335
2336 ASSERT(dqp->q_nrefs == 0);
2337 xfs_dqtrace_entry(dqp, "DQRECLAIM: UNLINKING");
2338 XQM_MPLIST_REMOVE(&(XFS_QI_MPL_LIST(dqp->q_mount)), dqp);
2339 XQM_HASHLIST_REMOVE(dqp->q_hash, dqp);
2340 XQM_FREELIST_REMOVE(dqp);
2341 dqpout = dqp;
2342 XFS_DQ_HASH_UNLOCK(dqp->q_hash);
2343 mplistunlock:
2344 xfs_qm_mplist_unlock(dqp->q_mount);
2345 xfs_dqfunlock(dqp);
2346 xfs_dqunlock(dqp);
2347 if (dqpout)
2348 break;
2349 }
2350
2351 xfs_qm_freelist_unlock(xfs_Gqm);
2352 return (dqpout);
2353}
2354
2355
2356/*------------------------------------------------------------------*/
2357
2358/*
2359 * Return a new incore dquot. Depending on the number of
2360 * dquots in the system, we either allocate a new one on the kernel heap,
2361 * or reclaim a free one.
2362 * Return value is B_TRUE if we allocated a new dquot, B_FALSE if we managed
2363 * to reclaim an existing one from the freelist.
2364 */
2365boolean_t
2366xfs_qm_dqalloc_incore(
2367 xfs_dquot_t **O_dqpp)
2368{
2369 xfs_dquot_t *dqp;
2370
2371 /*
2372 * Check against high water mark to see if we want to pop
2373 * a nincompoop dquot off the freelist.
2374 */
2375 if (atomic_read(&xfs_Gqm->qm_totaldquots) >= ndquot) {
2376 /*
2377 * Try to recycle a dquot from the freelist.
2378 */
2379 if ((dqp = xfs_qm_dqreclaim_one())) {
2380 XQM_STATS_INC(xqmstats.xs_qm_dqreclaims);
2381 /*
2382 * Just zero the core here. The rest will get
2383 * reinitialized by caller. XXX we shouldn't even
2384 * do this zero ...
2385 */
2386 memset(&dqp->q_core, 0, sizeof(dqp->q_core));
2387 *O_dqpp = dqp;
2388 return (B_FALSE);
2389 }
2390 XQM_STATS_INC(xqmstats.xs_qm_dqreclaim_misses);
2391 }
2392
2393 /*
2394 * Allocate a brand new dquot on the kernel heap and return it
2395 * to the caller to initialize.
2396 */
2397 ASSERT(xfs_Gqm->qm_dqzone != NULL);
2398 *O_dqpp = kmem_zone_zalloc(xfs_Gqm->qm_dqzone, KM_SLEEP);
2399 atomic_inc(&xfs_Gqm->qm_totaldquots);
2400
2401 return (B_TRUE);
2402}
2403
2404
2405/*
2406 * Start a transaction and write the incore superblock changes to
2407 * disk. flags parameter indicates which fields have changed.
2408 */
2409int
2410xfs_qm_write_sb_changes(
2411 xfs_mount_t *mp,
2412 __int64_t flags)
2413{
2414 xfs_trans_t *tp;
2415 int error;
2416
2417#ifdef QUOTADEBUG
2418 cmn_err(CE_NOTE, "Writing superblock quota changes :%s", mp->m_fsname);
2419#endif
2420 tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE);
2421 if ((error = xfs_trans_reserve(tp, 0,
2422 mp->m_sb.sb_sectsize + 128, 0,
2423 0,
2424 XFS_DEFAULT_LOG_COUNT))) {
2425 xfs_trans_cancel(tp, 0);
2426 return (error);
2427 }
2428
2429 xfs_mod_sb(tp, flags);
2430 (void) xfs_trans_commit(tp, 0, NULL);
2431
2432 return (0);
2433}
2434
2435
2436/* --------------- utility functions for vnodeops ---------------- */
2437
2438
2439/*
2440 * Given an inode, a uid and gid (from cred_t) make sure that we have
2441 * allocated relevant dquot(s) on disk, and that we won't exceed inode
2442 * quotas by creating this file.
2443 * This also attaches dquot(s) to the given inode after locking it,
2444 * and returns the dquots corresponding to the uid and/or gid.
2445 *
2446 * in : inode (unlocked)
2447 * out : udquot, gdquot with references taken and unlocked
2448 */
2449int
2450xfs_qm_vop_dqalloc(
2451 xfs_mount_t *mp,
2452 xfs_inode_t *ip,
2453 uid_t uid,
2454 gid_t gid,
2455 uint flags,
2456 xfs_dquot_t **O_udqpp,
2457 xfs_dquot_t **O_gdqpp)
2458{
2459 int error;
2460 xfs_dquot_t *uq, *gq;
2461 uint lockflags;
2462
2463 if (!XFS_IS_QUOTA_ON(mp))
2464 return 0;
2465
2466 lockflags = XFS_ILOCK_EXCL;
2467 xfs_ilock(ip, lockflags);
2468
2469 if ((flags & XFS_QMOPT_INHERIT) &&
2470 XFS_INHERIT_GID(ip, XFS_MTOVFS(mp)))
2471 gid = ip->i_d.di_gid;
2472
2473 /*
2474 * Attach the dquot(s) to this inode, doing a dquot allocation
2475 * if necessary. The dquot(s) will not be locked.
2476 */
2477 if (XFS_NOT_DQATTACHED(mp, ip)) {
2478 if ((error = xfs_qm_dqattach(ip, XFS_QMOPT_DQALLOC |
2479 XFS_QMOPT_ILOCKED))) {
2480 xfs_iunlock(ip, lockflags);
2481 return (error);
2482 }
2483 }
2484
2485 uq = gq = NULL;
2486 if ((flags & XFS_QMOPT_UQUOTA) &&
2487 XFS_IS_UQUOTA_ON(mp)) {
2488 if (ip->i_d.di_uid != uid) {
2489 /*
2490 * What we need is the dquot that has this uid, and
2491 * if we send the inode to dqget, the uid of the inode
2492 * takes priority over what's sent in the uid argument.
2493 * We must unlock inode here before calling dqget if
2494 * we're not sending the inode, because otherwise
2495 * we'll deadlock by doing trans_reserve while
2496 * holding ilock.
2497 */
2498 xfs_iunlock(ip, lockflags);
2499 if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t) uid,
2500 XFS_DQ_USER,
2501 XFS_QMOPT_DQALLOC |
2502 XFS_QMOPT_DOWARN,
2503 &uq))) {
2504 ASSERT(error != ENOENT);
2505 return (error);
2506 }
2507 /*
2508 * Get the ilock in the right order.
2509 */
2510 xfs_dqunlock(uq);
2511 lockflags = XFS_ILOCK_SHARED;
2512 xfs_ilock(ip, lockflags);
2513 } else {
2514 /*
2515 * Take an extra reference, because we'll return
2516 * this to caller
2517 */
2518 ASSERT(ip->i_udquot);
2519 uq = ip->i_udquot;
2520 xfs_dqlock(uq);
2521 XFS_DQHOLD(uq);
2522 xfs_dqunlock(uq);
2523 }
2524 }
2525 if ((flags & XFS_QMOPT_GQUOTA) &&
2526 XFS_IS_GQUOTA_ON(mp)) {
2527 if (ip->i_d.di_gid != gid) {
2528 xfs_iunlock(ip, lockflags);
2529 if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)gid,
2530 XFS_DQ_GROUP,
2531 XFS_QMOPT_DQALLOC |
2532 XFS_QMOPT_DOWARN,
2533 &gq))) {
2534 if (uq)
2535 xfs_qm_dqrele(uq);
2536 ASSERT(error != ENOENT);
2537 return (error);
2538 }
2539 xfs_dqunlock(gq);
2540 lockflags = XFS_ILOCK_SHARED;
2541 xfs_ilock(ip, lockflags);
2542 } else {
2543 ASSERT(ip->i_gdquot);
2544 gq = ip->i_gdquot;
2545 xfs_dqlock(gq);
2546 XFS_DQHOLD(gq);
2547 xfs_dqunlock(gq);
2548 }
2549 }
2550 if (uq)
2551 xfs_dqtrace_entry_ino(uq, "DQALLOC", ip);
2552
2553 xfs_iunlock(ip, lockflags);
2554 if (O_udqpp)
2555 *O_udqpp = uq;
2556 else if (uq)
2557 xfs_qm_dqrele(uq);
2558 if (O_gdqpp)
2559 *O_gdqpp = gq;
2560 else if (gq)
2561 xfs_qm_dqrele(gq);
2562 return (0);
2563}
2564
2565/*
2566 * Actually transfer ownership, and do dquot modifications.
2567 * These were already reserved.
2568 */
2569xfs_dquot_t *
2570xfs_qm_vop_chown(
2571 xfs_trans_t *tp,
2572 xfs_inode_t *ip,
2573 xfs_dquot_t **IO_olddq,
2574 xfs_dquot_t *newdq)
2575{
2576 xfs_dquot_t *prevdq;
2577 ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
2578 ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount));
2579
2580 /* old dquot */
2581 prevdq = *IO_olddq;
2582 ASSERT(prevdq);
2583 ASSERT(prevdq != newdq);
2584
2585 xfs_trans_mod_dquot(tp, prevdq,
2586 XFS_TRANS_DQ_BCOUNT,
2587 -(ip->i_d.di_nblocks));
2588 xfs_trans_mod_dquot(tp, prevdq,
2589 XFS_TRANS_DQ_ICOUNT,
2590 -1);
2591
2592 /* the sparkling new dquot */
2593 xfs_trans_mod_dquot(tp, newdq,
2594 XFS_TRANS_DQ_BCOUNT,
2595 ip->i_d.di_nblocks);
2596 xfs_trans_mod_dquot(tp, newdq,
2597 XFS_TRANS_DQ_ICOUNT,
2598 1);
2599
2600 /*
2601 * Take an extra reference, because the inode
2602 * is going to keep this dquot pointer even
2603 * after the trans_commit.
2604 */
2605 xfs_dqlock(newdq);
2606 XFS_DQHOLD(newdq);
2607 xfs_dqunlock(newdq);
2608 *IO_olddq = newdq;
2609
2610 return (prevdq);
2611}
2612
2613/*
2614 * Quota reservations for setattr(AT_UID|AT_GID).
2615 */
2616int
2617xfs_qm_vop_chown_reserve(
2618 xfs_trans_t *tp,
2619 xfs_inode_t *ip,
2620 xfs_dquot_t *udqp,
2621 xfs_dquot_t *gdqp,
2622 uint flags)
2623{
2624 int error;
2625 xfs_mount_t *mp;
2626 uint delblks;
2627 xfs_dquot_t *unresudq, *unresgdq, *delblksudq, *delblksgdq;
2628
2629 ASSERT(XFS_ISLOCKED_INODE(ip));
2630 mp = ip->i_mount;
2631 ASSERT(XFS_IS_QUOTA_RUNNING(mp));
2632
2633 delblks = ip->i_delayed_blks;
2634 delblksudq = delblksgdq = unresudq = unresgdq = NULL;
2635
2636 if (XFS_IS_UQUOTA_ON(mp) && udqp &&
2637 ip->i_d.di_uid != (uid_t)INT_GET(udqp->q_core.d_id, ARCH_CONVERT)) {
2638 delblksudq = udqp;
2639 /*
2640 * If there are delayed allocation blocks, then we have to
2641 * unreserve those from the old dquot, and add them to the
2642 * new dquot.
2643 */
2644 if (delblks) {
2645 ASSERT(ip->i_udquot);
2646 unresudq = ip->i_udquot;
2647 }
2648 }
2649 if (XFS_IS_GQUOTA_ON(ip->i_mount) && gdqp &&
2650 ip->i_d.di_gid != INT_GET(gdqp->q_core.d_id, ARCH_CONVERT)) {
2651 delblksgdq = gdqp;
2652 if (delblks) {
2653 ASSERT(ip->i_gdquot);
2654 unresgdq = ip->i_gdquot;
2655 }
2656 }
2657
2658 if ((error = xfs_trans_reserve_quota_bydquots(tp, ip->i_mount,
2659 delblksudq, delblksgdq, ip->i_d.di_nblocks, 1,
2660 flags | XFS_QMOPT_RES_REGBLKS)))
2661 return (error);
2662
2663 /*
2664 * Do the delayed blks reservations/unreservations now. Since, these
2665 * are done without the help of a transaction, if a reservation fails
2666 * its previous reservations won't be automatically undone by trans
2667 * code. So, we have to do it manually here.
2668 */
2669 if (delblks) {
2670 /*
2671 * Do the reservations first. Unreservation can't fail.
2672 */
2673 ASSERT(delblksudq || delblksgdq);
2674 ASSERT(unresudq || unresgdq);
2675 if ((error = xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
2676 delblksudq, delblksgdq, (xfs_qcnt_t)delblks, 0,
2677 flags | XFS_QMOPT_RES_REGBLKS)))
2678 return (error);
2679 xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
2680 unresudq, unresgdq, -((xfs_qcnt_t)delblks), 0,
2681 XFS_QMOPT_RES_REGBLKS);
2682 }
2683
2684 return (0);
2685}
2686
2687int
2688xfs_qm_vop_rename_dqattach(
2689 xfs_inode_t **i_tab)
2690{
2691 xfs_inode_t *ip;
2692 int i;
2693 int error;
2694
2695 ip = i_tab[0];
2696
2697 if (! XFS_IS_QUOTA_ON(ip->i_mount))
2698 return (0);
2699
2700 if (XFS_NOT_DQATTACHED(ip->i_mount, ip)) {
2701 error = xfs_qm_dqattach(ip, 0);
2702 if (error)
2703 return (error);
2704 }
2705 for (i = 1; (i < 4 && i_tab[i]); i++) {
2706 /*
2707 * Watch out for duplicate entries in the table.
2708 */
2709 if ((ip = i_tab[i]) != i_tab[i-1]) {
2710 if (XFS_NOT_DQATTACHED(ip->i_mount, ip)) {
2711 error = xfs_qm_dqattach(ip, 0);
2712 if (error)
2713 return (error);
2714 }
2715 }
2716 }
2717 return (0);
2718}
2719
2720void
2721xfs_qm_vop_dqattach_and_dqmod_newinode(
2722 xfs_trans_t *tp,
2723 xfs_inode_t *ip,
2724 xfs_dquot_t *udqp,
2725 xfs_dquot_t *gdqp)
2726{
2727 if (!XFS_IS_QUOTA_ON(tp->t_mountp))
2728 return;
2729
2730 ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
2731 ASSERT(XFS_IS_QUOTA_RUNNING(tp->t_mountp));
2732
2733 if (udqp) {
2734 xfs_dqlock(udqp);
2735 XFS_DQHOLD(udqp);
2736 xfs_dqunlock(udqp);
2737 ASSERT(ip->i_udquot == NULL);
2738 ip->i_udquot = udqp;
2739 ASSERT(ip->i_d.di_uid == INT_GET(udqp->q_core.d_id, ARCH_CONVERT));
2740 xfs_trans_mod_dquot(tp, udqp, XFS_TRANS_DQ_ICOUNT, 1);
2741 }
2742 if (gdqp) {
2743 xfs_dqlock(gdqp);
2744 XFS_DQHOLD(gdqp);
2745 xfs_dqunlock(gdqp);
2746 ASSERT(ip->i_gdquot == NULL);
2747 ip->i_gdquot = gdqp;
2748 ASSERT(ip->i_d.di_gid == INT_GET(gdqp->q_core.d_id, ARCH_CONVERT));
2749 xfs_trans_mod_dquot(tp, gdqp, XFS_TRANS_DQ_ICOUNT, 1);
2750 }
2751}
2752
2753/* ------------- list stuff -----------------*/
2754void
2755xfs_qm_freelist_init(xfs_frlist_t *ql)
2756{
2757 ql->qh_next = ql->qh_prev = (xfs_dquot_t *) ql;
2758 mutex_init(&ql->qh_lock, MUTEX_DEFAULT, "dqf");
2759 ql->qh_version = 0;
2760 ql->qh_nelems = 0;
2761}
2762
2763void
2764xfs_qm_freelist_destroy(xfs_frlist_t *ql)
2765{
2766 xfs_dquot_t *dqp, *nextdqp;
2767
2768 mutex_lock(&ql->qh_lock, PINOD);
2769 for (dqp = ql->qh_next;
2770 dqp != (xfs_dquot_t *)ql; ) {
2771 xfs_dqlock(dqp);
2772 nextdqp = dqp->dq_flnext;
2773#ifdef QUOTADEBUG
2774 cmn_err(CE_DEBUG, "FREELIST destroy 0x%p", dqp);
2775#endif
2776 XQM_FREELIST_REMOVE(dqp);
2777 xfs_dqunlock(dqp);
2778 xfs_qm_dqdestroy(dqp);
2779 dqp = nextdqp;
2780 }
2781 /*
2782 * Don't bother about unlocking.
2783 */
2784 mutex_destroy(&ql->qh_lock);
2785
2786 ASSERT(ql->qh_nelems == 0);
2787}
2788
2789void
2790xfs_qm_freelist_insert(xfs_frlist_t *ql, xfs_dquot_t *dq)
2791{
2792 dq->dq_flnext = ql->qh_next;
2793 dq->dq_flprev = (xfs_dquot_t *)ql;
2794 ql->qh_next = dq;
2795 dq->dq_flnext->dq_flprev = dq;
2796 xfs_Gqm->qm_dqfreelist.qh_nelems++;
2797 xfs_Gqm->qm_dqfreelist.qh_version++;
2798}
2799
2800void
2801xfs_qm_freelist_unlink(xfs_dquot_t *dq)
2802{
2803 xfs_dquot_t *next = dq->dq_flnext;
2804 xfs_dquot_t *prev = dq->dq_flprev;
2805
2806 next->dq_flprev = prev;
2807 prev->dq_flnext = next;
2808 dq->dq_flnext = dq->dq_flprev = dq;
2809 xfs_Gqm->qm_dqfreelist.qh_nelems--;
2810 xfs_Gqm->qm_dqfreelist.qh_version++;
2811}
2812
2813void
2814xfs_qm_freelist_append(xfs_frlist_t *ql, xfs_dquot_t *dq)
2815{
2816 xfs_qm_freelist_insert((xfs_frlist_t *)ql->qh_prev, dq);
2817}
2818
2819int
2820xfs_qm_dqhashlock_nowait(
2821 xfs_dquot_t *dqp)
2822{
2823 int locked;
2824
2825 locked = mutex_trylock(&((dqp)->q_hash->qh_lock));
2826 return (locked);
2827}
2828
2829int
2830xfs_qm_freelist_lock_nowait(
2831 xfs_qm_t *xqm)
2832{
2833 int locked;
2834
2835 locked = mutex_trylock(&(xqm->qm_dqfreelist.qh_lock));
2836 return (locked);
2837}
2838
2839int
2840xfs_qm_mplist_nowait(
2841 xfs_mount_t *mp)
2842{
2843 int locked;
2844
2845 ASSERT(mp->m_quotainfo);
2846 locked = mutex_trylock(&(XFS_QI_MPLLOCK(mp)));
2847 return (locked);
2848}
diff --git a/fs/xfs/quota/xfs_qm.h b/fs/xfs/quota/xfs_qm.h
new file mode 100644
index 000000000000..dcf1a7a831d8
--- /dev/null
+++ b/fs/xfs/quota/xfs_qm.h
@@ -0,0 +1,236 @@
1/*
2 * Copyright (c) 2000-2004 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#ifndef __XFS_QM_H__
33#define __XFS_QM_H__
34
35#include "xfs_dquot_item.h"
36#include "xfs_dquot.h"
37#include "xfs_quota_priv.h"
38#include "xfs_qm_stats.h"
39
40struct xfs_qm;
41struct xfs_inode;
42
43extern mutex_t xfs_Gqm_lock;
44extern struct xfs_qm *xfs_Gqm;
45extern kmem_zone_t *qm_dqzone;
46extern kmem_zone_t *qm_dqtrxzone;
47
48/*
49 * Used in xfs_qm_sync called by xfs_sync to count the max times that it can
50 * iterate over the mountpt's dquot list in one call.
51 */
52#define XFS_QM_SYNC_MAX_RESTARTS 7
53
54/*
55 * Ditto, for xfs_qm_dqreclaim_one.
56 */
57#define XFS_QM_RECLAIM_MAX_RESTARTS 4
58
59/*
60 * Ideal ratio of free to in use dquots. Quota manager makes an attempt
61 * to keep this balance.
62 */
63#define XFS_QM_DQFREE_RATIO 2
64
65/*
66 * Dquot hashtable constants/threshold values.
67 */
68#define XFS_QM_NCSIZE_THRESHOLD 5000
69#define XFS_QM_HASHSIZE_LOW 32
70#define XFS_QM_HASHSIZE_HIGH 64
71
72/*
73 * We output a cmn_err when quotachecking a quota file with more than
74 * this many fsbs.
75 */
76#define XFS_QM_BIG_QCHECK_NBLKS 500
77
78/*
79 * This defines the unit of allocation of dquots.
80 * Currently, it is just one file system block, and a 4K blk contains 30
81 * (136 * 30 = 4080) dquots. It's probably not worth trying to make
82 * this more dynamic.
83 * XXXsup However, if this number is changed, we have to make sure that we don't
84 * implicitly assume that we do allocations in chunks of a single filesystem
85 * block in the dquot/xqm code.
86 */
87#define XFS_DQUOT_CLUSTER_SIZE_FSB (xfs_filblks_t)1
88/*
89 * When doing a quotacheck, we log dquot clusters of this many FSBs at most
90 * in a single transaction. We don't want to ask for too huge a log reservation.
91 */
92#define XFS_QM_MAX_DQCLUSTER_LOGSZ 3
93
94typedef xfs_dqhash_t xfs_dqlist_t;
95/*
96 * The freelist head. The first two fields match the first two in the
97 * xfs_dquot_t structure (in xfs_dqmarker_t)
98 */
99typedef struct xfs_frlist {
100 struct xfs_dquot *qh_next;
101 struct xfs_dquot *qh_prev;
102 mutex_t qh_lock;
103 uint qh_version;
104 uint qh_nelems;
105} xfs_frlist_t;
106
107/*
108 * Quota Manager (global) structure. Lives only in core.
109 */
110typedef struct xfs_qm {
111 xfs_dqlist_t *qm_usr_dqhtable;/* udquot hash table */
112 xfs_dqlist_t *qm_grp_dqhtable;/* gdquot hash table */
113 uint qm_dqhashmask; /* # buckets in dq hashtab - 1 */
114 xfs_frlist_t qm_dqfreelist; /* freelist of dquots */
115 atomic_t qm_totaldquots; /* total incore dquots */
116 uint qm_nrefs; /* file systems with quota on */
117 int qm_dqfree_ratio;/* ratio of free to inuse dquots */
118 kmem_zone_t *qm_dqzone; /* dquot mem-alloc zone */
119 kmem_zone_t *qm_dqtrxzone; /* t_dqinfo of transactions */
120} xfs_qm_t;
121
122/*
123 * Various quota information for individual filesystems.
124 * The mount structure keeps a pointer to this.
125 */
126typedef struct xfs_quotainfo {
127 xfs_inode_t *qi_uquotaip; /* user quota inode */
128 xfs_inode_t *qi_gquotaip; /* group quota inode */
129 lock_t qi_pinlock; /* dquot pinning mutex */
130 xfs_dqlist_t qi_dqlist; /* all dquots in filesys */
131 int qi_dqreclaims; /* a change here indicates
132 a removal in the dqlist */
133 time_t qi_btimelimit; /* limit for blks timer */
134 time_t qi_itimelimit; /* limit for inodes timer */
135 time_t qi_rtbtimelimit;/* limit for rt blks timer */
136 xfs_qwarncnt_t qi_bwarnlimit; /* limit for num warnings */
137 xfs_qwarncnt_t qi_iwarnlimit; /* limit for num warnings */
138 mutex_t qi_quotaofflock;/* to serialize quotaoff */
139 xfs_filblks_t qi_dqchunklen; /* # BBs in a chunk of dqs */
140 uint qi_dqperchunk; /* # ondisk dqs in above chunk */
141 xfs_qcnt_t qi_bhardlimit; /* default data blk hard limit */
142 xfs_qcnt_t qi_bsoftlimit; /* default data blk soft limit */
143 xfs_qcnt_t qi_ihardlimit; /* default inode count hard limit */
144 xfs_qcnt_t qi_isoftlimit; /* default inode count soft limit */
145 xfs_qcnt_t qi_rtbhardlimit;/* default realtime blk hard limit */
146 xfs_qcnt_t qi_rtbsoftlimit;/* default realtime blk soft limit */
147} xfs_quotainfo_t;
148
149
150extern xfs_dqtrxops_t xfs_trans_dquot_ops;
151
152extern void xfs_trans_mod_dquot(xfs_trans_t *, xfs_dquot_t *, uint, long);
153extern int xfs_trans_reserve_quota_bydquots(xfs_trans_t *, xfs_mount_t *,
154 xfs_dquot_t *, xfs_dquot_t *, long, long, uint);
155extern void xfs_trans_dqjoin(xfs_trans_t *, xfs_dquot_t *);
156extern void xfs_trans_log_dquot(xfs_trans_t *, xfs_dquot_t *);
157
158/*
159 * We keep the usr and grp dquots separately so that locking will be easier
160 * to do at commit time. All transactions that we know of at this point
161 * affect no more than two dquots of one type. Hence, the TRANS_MAXDQS value.
162 */
163#define XFS_QM_TRANS_MAXDQS 2
164typedef struct xfs_dquot_acct {
165 xfs_dqtrx_t dqa_usrdquots[XFS_QM_TRANS_MAXDQS];
166 xfs_dqtrx_t dqa_grpdquots[XFS_QM_TRANS_MAXDQS];
167} xfs_dquot_acct_t;
168
169/*
170 * Users are allowed to have a usage exceeding their softlimit for
171 * a period this long.
172 */
173#define XFS_QM_BTIMELIMIT (7 * 24*60*60) /* 1 week */
174#define XFS_QM_RTBTIMELIMIT (7 * 24*60*60) /* 1 week */
175#define XFS_QM_ITIMELIMIT (7 * 24*60*60) /* 1 week */
176
177#define XFS_QM_BWARNLIMIT 5
178#define XFS_QM_IWARNLIMIT 5
179
180#define XFS_QM_LOCK(xqm) (mutex_lock(&xqm##_lock, PINOD))
181#define XFS_QM_UNLOCK(xqm) (mutex_unlock(&xqm##_lock))
182#define XFS_QM_HOLD(xqm) ((xqm)->qm_nrefs++)
183#define XFS_QM_RELE(xqm) ((xqm)->qm_nrefs--)
184
185extern void xfs_mount_reset_sbqflags(xfs_mount_t *);
186
187extern int xfs_qm_init_quotainfo(xfs_mount_t *);
188extern void xfs_qm_destroy_quotainfo(xfs_mount_t *);
189extern int xfs_qm_mount_quotas(xfs_mount_t *, int);
190extern void xfs_qm_mount_quotainit(xfs_mount_t *, uint);
191extern int xfs_qm_quotacheck(xfs_mount_t *);
192extern void xfs_qm_unmount_quotadestroy(xfs_mount_t *);
193extern int xfs_qm_unmount_quotas(xfs_mount_t *);
194extern int xfs_qm_write_sb_changes(xfs_mount_t *, __int64_t);
195extern int xfs_qm_sync(xfs_mount_t *, short);
196
197/* dquot stuff */
198extern boolean_t xfs_qm_dqalloc_incore(xfs_dquot_t **);
199extern int xfs_qm_dqattach(xfs_inode_t *, uint);
200extern void xfs_qm_dqdetach(xfs_inode_t *);
201extern int xfs_qm_dqpurge_all(xfs_mount_t *, uint);
202extern void xfs_qm_dqrele_all_inodes(xfs_mount_t *, uint);
203
204/* vop stuff */
205extern int xfs_qm_vop_dqalloc(xfs_mount_t *, xfs_inode_t *,
206 uid_t, gid_t, uint,
207 xfs_dquot_t **, xfs_dquot_t **);
208extern void xfs_qm_vop_dqattach_and_dqmod_newinode(
209 xfs_trans_t *, xfs_inode_t *,
210 xfs_dquot_t *, xfs_dquot_t *);
211extern int xfs_qm_vop_rename_dqattach(xfs_inode_t **);
212extern xfs_dquot_t * xfs_qm_vop_chown(xfs_trans_t *, xfs_inode_t *,
213 xfs_dquot_t **, xfs_dquot_t *);
214extern int xfs_qm_vop_chown_reserve(xfs_trans_t *, xfs_inode_t *,
215 xfs_dquot_t *, xfs_dquot_t *, uint);
216
217/* list stuff */
218extern void xfs_qm_freelist_init(xfs_frlist_t *);
219extern void xfs_qm_freelist_destroy(xfs_frlist_t *);
220extern void xfs_qm_freelist_insert(xfs_frlist_t *, xfs_dquot_t *);
221extern void xfs_qm_freelist_append(xfs_frlist_t *, xfs_dquot_t *);
222extern void xfs_qm_freelist_unlink(xfs_dquot_t *);
223extern int xfs_qm_freelist_lock_nowait(xfs_qm_t *);
224extern int xfs_qm_mplist_nowait(xfs_mount_t *);
225extern int xfs_qm_dqhashlock_nowait(xfs_dquot_t *);
226
227/* system call interface */
228extern int xfs_qm_quotactl(bhv_desc_t *, int, int, xfs_caddr_t);
229
230#ifdef DEBUG
231extern int xfs_qm_internalqcheck(xfs_mount_t *);
232#else
233#define xfs_qm_internalqcheck(mp) (0)
234#endif
235
236#endif /* __XFS_QM_H__ */
diff --git a/fs/xfs/quota/xfs_qm_bhv.c b/fs/xfs/quota/xfs_qm_bhv.c
new file mode 100644
index 000000000000..be67d9c265f8
--- /dev/null
+++ b/fs/xfs/quota/xfs_qm_bhv.c
@@ -0,0 +1,410 @@
1/*
2 * Copyright (c) 2000-2004 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_clnt.h"
38#include "xfs_trans.h"
39#include "xfs_sb.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
68#include "xfs_qm.h"
69
70#define MNTOPT_QUOTA "quota" /* disk quotas (user) */
71#define MNTOPT_NOQUOTA "noquota" /* no quotas */
72#define MNTOPT_USRQUOTA "usrquota" /* user quota enabled */
73#define MNTOPT_GRPQUOTA "grpquota" /* group quota enabled */
74#define MNTOPT_UQUOTA "uquota" /* user quota (IRIX variant) */
75#define MNTOPT_GQUOTA "gquota" /* group quota (IRIX variant) */
76#define MNTOPT_UQUOTANOENF "uqnoenforce"/* user quota limit enforcement */
77#define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */
78#define MNTOPT_QUOTANOENF "qnoenforce" /* same as uqnoenforce */
79
80STATIC int
81xfs_qm_parseargs(
82 struct bhv_desc *bhv,
83 char *options,
84 struct xfs_mount_args *args,
85 int update)
86{
87 size_t length;
88 char *local_options = options;
89 char *this_char;
90 int error;
91 int referenced = update;
92
93 while ((this_char = strsep(&local_options, ",")) != NULL) {
94 length = strlen(this_char);
95 if (local_options)
96 length++;
97
98 if (!strcmp(this_char, MNTOPT_NOQUOTA)) {
99 args->flags &= ~(XFSMNT_UQUOTAENF|XFSMNT_UQUOTA);
100 args->flags &= ~(XFSMNT_GQUOTAENF|XFSMNT_GQUOTA);
101 referenced = update;
102 } else if (!strcmp(this_char, MNTOPT_QUOTA) ||
103 !strcmp(this_char, MNTOPT_UQUOTA) ||
104 !strcmp(this_char, MNTOPT_USRQUOTA)) {
105 args->flags |= XFSMNT_UQUOTA | XFSMNT_UQUOTAENF;
106 referenced = 1;
107 } else if (!strcmp(this_char, MNTOPT_QUOTANOENF) ||
108 !strcmp(this_char, MNTOPT_UQUOTANOENF)) {
109 args->flags |= XFSMNT_UQUOTA;
110 args->flags &= ~XFSMNT_UQUOTAENF;
111 referenced = 1;
112 } else if (!strcmp(this_char, MNTOPT_GQUOTA) ||
113 !strcmp(this_char, MNTOPT_GRPQUOTA)) {
114 args->flags |= XFSMNT_GQUOTA | XFSMNT_GQUOTAENF;
115 referenced = 1;
116 } else if (!strcmp(this_char, MNTOPT_GQUOTANOENF)) {
117 args->flags |= XFSMNT_GQUOTA;
118 args->flags &= ~XFSMNT_GQUOTAENF;
119 referenced = 1;
120 } else {
121 if (local_options)
122 *(local_options-1) = ',';
123 continue;
124 }
125
126 while (length--)
127 *this_char++ = ',';
128 }
129
130 PVFS_PARSEARGS(BHV_NEXT(bhv), options, args, update, error);
131 if (!error && !referenced)
132 bhv_remove_vfsops(bhvtovfs(bhv), VFS_POSITION_QM);
133 return error;
134}
135
136STATIC int
137xfs_qm_showargs(
138 struct bhv_desc *bhv,
139 struct seq_file *m)
140{
141 struct vfs *vfsp = bhvtovfs(bhv);
142 struct xfs_mount *mp = XFS_VFSTOM(vfsp);
143 int error;
144
145 if (mp->m_qflags & XFS_UQUOTA_ACCT) {
146 (mp->m_qflags & XFS_UQUOTA_ENFD) ?
147 seq_puts(m, "," MNTOPT_USRQUOTA) :
148 seq_puts(m, "," MNTOPT_UQUOTANOENF);
149 }
150
151 if (mp->m_qflags & XFS_GQUOTA_ACCT) {
152 (mp->m_qflags & XFS_GQUOTA_ENFD) ?
153 seq_puts(m, "," MNTOPT_GRPQUOTA) :
154 seq_puts(m, "," MNTOPT_GQUOTANOENF);
155 }
156
157 if (!(mp->m_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT)))
158 seq_puts(m, "," MNTOPT_NOQUOTA);
159
160 PVFS_SHOWARGS(BHV_NEXT(bhv), m, error);
161 return error;
162}
163
164STATIC int
165xfs_qm_mount(
166 struct bhv_desc *bhv,
167 struct xfs_mount_args *args,
168 struct cred *cr)
169{
170 struct vfs *vfsp = bhvtovfs(bhv);
171 struct xfs_mount *mp = XFS_VFSTOM(vfsp);
172 int error;
173
174 if (args->flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA))
175 xfs_qm_mount_quotainit(mp, args->flags);
176 PVFS_MOUNT(BHV_NEXT(bhv), args, cr, error);
177 return error;
178}
179
180STATIC int
181xfs_qm_syncall(
182 struct bhv_desc *bhv,
183 int flags,
184 cred_t *credp)
185{
186 struct vfs *vfsp = bhvtovfs(bhv);
187 struct xfs_mount *mp = XFS_VFSTOM(vfsp);
188 int error;
189
190 /*
191 * Get the Quota Manager to flush the dquots.
192 */
193 if (XFS_IS_QUOTA_ON(mp)) {
194 if ((error = xfs_qm_sync(mp, flags))) {
195 /*
196 * If we got an IO error, we will be shutting down.
197 * So, there's nothing more for us to do here.
198 */
199 ASSERT(error != EIO || XFS_FORCED_SHUTDOWN(mp));
200 if (XFS_FORCED_SHUTDOWN(mp)) {
201 return XFS_ERROR(error);
202 }
203 }
204 }
205 PVFS_SYNC(BHV_NEXT(bhv), flags, credp, error);
206 return error;
207}
208
209/*
210 * Clear the quotaflags in memory and in the superblock.
211 */
212void
213xfs_mount_reset_sbqflags(
214 xfs_mount_t *mp)
215{
216 xfs_trans_t *tp;
217 unsigned long s;
218
219 mp->m_qflags = 0;
220 /*
221 * It is OK to look at sb_qflags here in mount path,
222 * without SB_LOCK.
223 */
224 if (mp->m_sb.sb_qflags == 0)
225 return;
226 s = XFS_SB_LOCK(mp);
227 mp->m_sb.sb_qflags = 0;
228 XFS_SB_UNLOCK(mp, s);
229
230 /*
231 * if the fs is readonly, let the incore superblock run
232 * with quotas off but don't flush the update out to disk
233 */
234 if (XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY)
235 return;
236#ifdef QUOTADEBUG
237 xfs_fs_cmn_err(CE_NOTE, mp, "Writing superblock quota changes");
238#endif
239 tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE);
240 if (xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
241 XFS_DEFAULT_LOG_COUNT)) {
242 xfs_trans_cancel(tp, 0);
243 xfs_fs_cmn_err(CE_ALERT, mp,
244 "xfs_mount_reset_sbqflags: Superblock update failed!");
245 return;
246 }
247 xfs_mod_sb(tp, XFS_SB_QFLAGS);
248 xfs_trans_commit(tp, 0, NULL);
249}
250
251STATIC int
252xfs_qm_newmount(
253 xfs_mount_t *mp,
254 uint *needquotamount,
255 uint *quotaflags)
256{
257 uint quotaondisk;
258 uint uquotaondisk = 0, gquotaondisk = 0;
259
260 *quotaflags = 0;
261 *needquotamount = B_FALSE;
262
263 quotaondisk = XFS_SB_VERSION_HASQUOTA(&mp->m_sb) &&
264 mp->m_sb.sb_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT);
265
266 if (quotaondisk) {
267 uquotaondisk = mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT;
268 gquotaondisk = mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT;
269 }
270
271 /*
272 * If the device itself is read-only, we can't allow
273 * the user to change the state of quota on the mount -
274 * this would generate a transaction on the ro device,
275 * which would lead to an I/O error and shutdown
276 */
277
278 if (((uquotaondisk && !XFS_IS_UQUOTA_ON(mp)) ||
279 (!uquotaondisk && XFS_IS_UQUOTA_ON(mp)) ||
280 (gquotaondisk && !XFS_IS_GQUOTA_ON(mp)) ||
281 (!gquotaondisk && XFS_IS_GQUOTA_ON(mp))) &&
282 xfs_dev_is_read_only(mp, "changing quota state")) {
283 cmn_err(CE_WARN,
284 "XFS: please mount with%s%s%s.",
285 (!quotaondisk ? "out quota" : ""),
286 (uquotaondisk ? " usrquota" : ""),
287 (gquotaondisk ? " grpquota" : ""));
288 return XFS_ERROR(EPERM);
289 }
290
291 if (XFS_IS_QUOTA_ON(mp) || quotaondisk) {
292 /*
293 * Call mount_quotas at this point only if we won't have to do
294 * a quotacheck.
295 */
296 if (quotaondisk && !XFS_QM_NEED_QUOTACHECK(mp)) {
297 /*
298 * If an error occured, qm_mount_quotas code
299 * has already disabled quotas. So, just finish
300 * mounting, and get on with the boring life
301 * without disk quotas.
302 */
303 xfs_qm_mount_quotas(mp, 0);
304 } else {
305 /*
306 * Clear the quota flags, but remember them. This
307 * is so that the quota code doesn't get invoked
308 * before we're ready. This can happen when an
309 * inode goes inactive and wants to free blocks,
310 * or via xfs_log_mount_finish.
311 */
312 *needquotamount = B_TRUE;
313 *quotaflags = mp->m_qflags;
314 mp->m_qflags = 0;
315 }
316 }
317
318 return 0;
319}
320
321STATIC int
322xfs_qm_endmount(
323 xfs_mount_t *mp,
324 uint needquotamount,
325 uint quotaflags,
326 int mfsi_flags)
327{
328 if (needquotamount) {
329 ASSERT(mp->m_qflags == 0);
330 mp->m_qflags = quotaflags;
331 xfs_qm_mount_quotas(mp, mfsi_flags);
332 }
333
334#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
335 if (! (XFS_IS_QUOTA_ON(mp)))
336 xfs_fs_cmn_err(CE_NOTE, mp, "Disk quotas not turned on");
337 else
338 xfs_fs_cmn_err(CE_NOTE, mp, "Disk quotas turned on");
339#endif
340
341#ifdef QUOTADEBUG
342 if (XFS_IS_QUOTA_ON(mp) && xfs_qm_internalqcheck(mp))
343 cmn_err(CE_WARN, "XFS: mount internalqcheck failed");
344#endif
345
346 return 0;
347}
348
349STATIC void
350xfs_qm_dqrele_null(
351 xfs_dquot_t *dq)
352{
353 /*
354 * Called from XFS, where we always check first for a NULL dquot.
355 */
356 if (!dq)
357 return;
358 xfs_qm_dqrele(dq);
359}
360
361
362struct xfs_qmops xfs_qmcore_xfs = {
363 .xfs_qminit = xfs_qm_newmount,
364 .xfs_qmdone = xfs_qm_unmount_quotadestroy,
365 .xfs_qmmount = xfs_qm_endmount,
366 .xfs_qmunmount = xfs_qm_unmount_quotas,
367 .xfs_dqrele = xfs_qm_dqrele_null,
368 .xfs_dqattach = xfs_qm_dqattach,
369 .xfs_dqdetach = xfs_qm_dqdetach,
370 .xfs_dqpurgeall = xfs_qm_dqpurge_all,
371 .xfs_dqvopalloc = xfs_qm_vop_dqalloc,
372 .xfs_dqvopcreate = xfs_qm_vop_dqattach_and_dqmod_newinode,
373 .xfs_dqvoprename = xfs_qm_vop_rename_dqattach,
374 .xfs_dqvopchown = xfs_qm_vop_chown,
375 .xfs_dqvopchownresv = xfs_qm_vop_chown_reserve,
376 .xfs_dqtrxops = &xfs_trans_dquot_ops,
377};
378
379struct bhv_vfsops xfs_qmops = { {
380 BHV_IDENTITY_INIT(VFS_BHV_QM, VFS_POSITION_QM),
381 .vfs_parseargs = xfs_qm_parseargs,
382 .vfs_showargs = xfs_qm_showargs,
383 .vfs_mount = xfs_qm_mount,
384 .vfs_sync = xfs_qm_syncall,
385 .vfs_quotactl = xfs_qm_quotactl, },
386};
387
388
389void __init
390xfs_qm_init(void)
391{
392 static char message[] __initdata =
393 KERN_INFO "SGI XFS Quota Management subsystem\n";
394
395 printk(message);
396 mutex_init(&xfs_Gqm_lock, MUTEX_DEFAULT, "xfs_qmlock");
397 vfs_bhv_set_custom(&xfs_qmops, &xfs_qmcore_xfs);
398 xfs_qm_init_procfs();
399}
400
401void __exit
402xfs_qm_exit(void)
403{
404 vfs_bhv_clr_custom(&xfs_qmops);
405 xfs_qm_cleanup_procfs();
406 if (qm_dqzone)
407 kmem_cache_destroy(qm_dqzone);
408 if (qm_dqtrxzone)
409 kmem_cache_destroy(qm_dqtrxzone);
410}
diff --git a/fs/xfs/quota/xfs_qm_stats.c b/fs/xfs/quota/xfs_qm_stats.c
new file mode 100644
index 000000000000..29978e037fee
--- /dev/null
+++ b/fs/xfs/quota/xfs_qm_stats.c
@@ -0,0 +1,149 @@
1/*
2 * Copyright (c) 2000-2003 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_dir.h"
40#include "xfs_dir2.h"
41#include "xfs_alloc.h"
42#include "xfs_dmapi.h"
43#include "xfs_quota.h"
44#include "xfs_mount.h"
45#include "xfs_alloc_btree.h"
46#include "xfs_bmap_btree.h"
47#include "xfs_ialloc_btree.h"
48#include "xfs_btree.h"
49#include "xfs_ialloc.h"
50#include "xfs_attr_sf.h"
51#include "xfs_dir_sf.h"
52#include "xfs_dir2_sf.h"
53#include "xfs_dinode.h"
54#include "xfs_inode.h"
55#include "xfs_bmap.h"
56#include "xfs_bit.h"
57#include "xfs_rtalloc.h"
58#include "xfs_error.h"
59#include "xfs_itable.h"
60#include "xfs_rw.h"
61#include "xfs_acl.h"
62#include "xfs_cap.h"
63#include "xfs_mac.h"
64#include "xfs_attr.h"
65#include "xfs_buf_item.h"
66
67#include "xfs_qm.h"
68
69struct xqmstats xqmstats;
70
71STATIC int
72xfs_qm_read_xfsquota(
73 char *buffer,
74 char **start,
75 off_t offset,
76 int count,
77 int *eof,
78 void *data)
79{
80 int len;
81
82 /* maximum; incore; ratio free to inuse; freelist */
83 len = sprintf(buffer, "%d\t%d\t%d\t%u\n",
84 ndquot,
85 xfs_Gqm? atomic_read(&xfs_Gqm->qm_totaldquots) : 0,
86 xfs_Gqm? xfs_Gqm->qm_dqfree_ratio : 0,
87 xfs_Gqm? xfs_Gqm->qm_dqfreelist.qh_nelems : 0);
88
89 if (offset >= len) {
90 *start = buffer;
91 *eof = 1;
92 return 0;
93 }
94 *start = buffer + offset;
95 if ((len -= offset) > count)
96 return count;
97 *eof = 1;
98
99 return len;
100}
101
102STATIC int
103xfs_qm_read_stats(
104 char *buffer,
105 char **start,
106 off_t offset,
107 int count,
108 int *eof,
109 void *data)
110{
111 int len;
112
113 /* quota performance statistics */
114 len = sprintf(buffer, "qm %u %u %u %u %u %u %u %u\n",
115 xqmstats.xs_qm_dqreclaims,
116 xqmstats.xs_qm_dqreclaim_misses,
117 xqmstats.xs_qm_dquot_dups,
118 xqmstats.xs_qm_dqcachemisses,
119 xqmstats.xs_qm_dqcachehits,
120 xqmstats.xs_qm_dqwants,
121 xqmstats.xs_qm_dqshake_reclaims,
122 xqmstats.xs_qm_dqinact_reclaims);
123
124 if (offset >= len) {
125 *start = buffer;
126 *eof = 1;
127 return 0;
128 }
129 *start = buffer + offset;
130 if ((len -= offset) > count)
131 return count;
132 *eof = 1;
133
134 return len;
135}
136
137void
138xfs_qm_init_procfs(void)
139{
140 create_proc_read_entry("fs/xfs/xqmstat", 0, NULL, xfs_qm_read_stats, NULL);
141 create_proc_read_entry("fs/xfs/xqm", 0, NULL, xfs_qm_read_xfsquota, NULL);
142}
143
144void
145xfs_qm_cleanup_procfs(void)
146{
147 remove_proc_entry("fs/xfs/xqm", NULL);
148 remove_proc_entry("fs/xfs/xqmstat", NULL);
149}
diff --git a/fs/xfs/quota/xfs_qm_stats.h b/fs/xfs/quota/xfs_qm_stats.h
new file mode 100644
index 000000000000..8093c5c284ec
--- /dev/null
+++ b/fs/xfs/quota/xfs_qm_stats.h
@@ -0,0 +1,68 @@
1/*
2 * Copyright (c) 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#ifndef __XFS_QM_STATS_H__
33#define __XFS_QM_STATS_H__
34
35
36#if defined(CONFIG_PROC_FS) && !defined(XFS_STATS_OFF)
37
38/*
39 * XQM global statistics
40 */
41struct xqmstats {
42 __uint32_t xs_qm_dqreclaims;
43 __uint32_t xs_qm_dqreclaim_misses;
44 __uint32_t xs_qm_dquot_dups;
45 __uint32_t xs_qm_dqcachemisses;
46 __uint32_t xs_qm_dqcachehits;
47 __uint32_t xs_qm_dqwants;
48 __uint32_t xs_qm_dqshake_reclaims;
49 __uint32_t xs_qm_dqinact_reclaims;
50};
51
52extern struct xqmstats xqmstats;
53
54# define XQM_STATS_INC(count) ( (count)++ )
55
56extern void xfs_qm_init_procfs(void);
57extern void xfs_qm_cleanup_procfs(void);
58
59#else
60
61# define XQM_STATS_INC(count) do { } while (0)
62
63static __inline void xfs_qm_init_procfs(void) { };
64static __inline void xfs_qm_cleanup_procfs(void) { };
65
66#endif
67
68#endif /* __XFS_QM_STATS_H__ */
diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c
new file mode 100644
index 000000000000..229f5b5a2d25
--- /dev/null
+++ b/fs/xfs/quota/xfs_qm_syscalls.c
@@ -0,0 +1,1458 @@
1/*
2 * Copyright (c) 2000-2003 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_dir.h"
40#include "xfs_dir2.h"
41#include "xfs_alloc.h"
42#include "xfs_dmapi.h"
43#include "xfs_quota.h"
44#include "xfs_mount.h"
45#include "xfs_alloc_btree.h"
46#include "xfs_bmap_btree.h"
47#include "xfs_ialloc_btree.h"
48#include "xfs_btree.h"
49#include "xfs_ialloc.h"
50#include "xfs_attr_sf.h"
51#include "xfs_dir_sf.h"
52#include "xfs_dir2_sf.h"
53#include "xfs_dinode.h"
54#include "xfs_inode.h"
55#include "xfs_bmap.h"
56#include "xfs_bit.h"
57#include "xfs_rtalloc.h"
58#include "xfs_error.h"
59#include "xfs_itable.h"
60#include "xfs_rw.h"
61#include "xfs_acl.h"
62#include "xfs_cap.h"
63#include "xfs_mac.h"
64#include "xfs_attr.h"
65#include "xfs_buf_item.h"
66#include "xfs_utils.h"
67
68#include "xfs_qm.h"
69
70#ifdef DEBUG
71# define qdprintk(s, args...) cmn_err(CE_DEBUG, s, ## args)
72#else
73# define qdprintk(s, args...) do { } while (0)
74#endif
75
76STATIC int xfs_qm_scall_trunc_qfiles(xfs_mount_t *, uint);
77STATIC int xfs_qm_scall_getquota(xfs_mount_t *, xfs_dqid_t, uint,
78 fs_disk_quota_t *);
79STATIC int xfs_qm_scall_getqstat(xfs_mount_t *, fs_quota_stat_t *);
80STATIC int xfs_qm_scall_setqlim(xfs_mount_t *, xfs_dqid_t, uint,
81 fs_disk_quota_t *);
82STATIC int xfs_qm_scall_quotaon(xfs_mount_t *, uint);
83STATIC int xfs_qm_scall_quotaoff(xfs_mount_t *, uint, boolean_t);
84STATIC int xfs_qm_log_quotaoff(xfs_mount_t *, xfs_qoff_logitem_t **, uint);
85STATIC int xfs_qm_log_quotaoff_end(xfs_mount_t *, xfs_qoff_logitem_t *,
86 uint);
87STATIC uint xfs_qm_import_flags(uint);
88STATIC uint xfs_qm_export_flags(uint);
89STATIC uint xfs_qm_import_qtype_flags(uint);
90STATIC uint xfs_qm_export_qtype_flags(uint);
91STATIC void xfs_qm_export_dquot(xfs_mount_t *, xfs_disk_dquot_t *,
92 fs_disk_quota_t *);
93
94
95/*
96 * The main distribution switch of all XFS quotactl system calls.
97 */
98int
99xfs_qm_quotactl(
100 struct bhv_desc *bdp,
101 int cmd,
102 int id,
103 xfs_caddr_t addr)
104{
105 xfs_mount_t *mp;
106 int error;
107 struct vfs *vfsp;
108
109 vfsp = bhvtovfs(bdp);
110 mp = XFS_VFSTOM(vfsp);
111
112 if (addr == NULL && cmd != Q_SYNC)
113 return XFS_ERROR(EINVAL);
114 if (id < 0 && cmd != Q_SYNC)
115 return XFS_ERROR(EINVAL);
116
117 /*
118 * The following commands are valid even when quotaoff.
119 */
120 switch (cmd) {
121 /*
122 * truncate quota files. quota must be off.
123 */
124 case Q_XQUOTARM:
125 if (XFS_IS_QUOTA_ON(mp) || addr == NULL)
126 return XFS_ERROR(EINVAL);
127 if (vfsp->vfs_flag & VFS_RDONLY)
128 return XFS_ERROR(EROFS);
129 return (xfs_qm_scall_trunc_qfiles(mp,
130 xfs_qm_import_qtype_flags(*(uint *)addr)));
131 /*
132 * Get quota status information.
133 */
134 case Q_XGETQSTAT:
135 return (xfs_qm_scall_getqstat(mp, (fs_quota_stat_t *)addr));
136
137 /*
138 * QUOTAON for root f/s and quota enforcement on others..
139 * Quota accounting for non-root f/s's must be turned on
140 * at mount time.
141 */
142 case Q_XQUOTAON:
143 if (addr == NULL)
144 return XFS_ERROR(EINVAL);
145 if (vfsp->vfs_flag & VFS_RDONLY)
146 return XFS_ERROR(EROFS);
147 return (xfs_qm_scall_quotaon(mp,
148 xfs_qm_import_flags(*(uint *)addr)));
149 case Q_XQUOTAOFF:
150 if (vfsp->vfs_flag & VFS_RDONLY)
151 return XFS_ERROR(EROFS);
152 break;
153
154 default:
155 break;
156 }
157
158 if (! XFS_IS_QUOTA_ON(mp))
159 return XFS_ERROR(ESRCH);
160
161 switch (cmd) {
162 case Q_XQUOTAOFF:
163 if (vfsp->vfs_flag & VFS_RDONLY)
164 return XFS_ERROR(EROFS);
165 error = xfs_qm_scall_quotaoff(mp,
166 xfs_qm_import_flags(*(uint *)addr),
167 B_FALSE);
168 break;
169
170 /*
171 * Defaults to XFS_GETUQUOTA.
172 */
173 case Q_XGETQUOTA:
174 error = xfs_qm_scall_getquota(mp, (xfs_dqid_t)id, XFS_DQ_USER,
175 (fs_disk_quota_t *)addr);
176 break;
177 /*
178 * Set limits, both hard and soft. Defaults to Q_SETUQLIM.
179 */
180 case Q_XSETQLIM:
181 if (vfsp->vfs_flag & VFS_RDONLY)
182 return XFS_ERROR(EROFS);
183 error = xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, XFS_DQ_USER,
184 (fs_disk_quota_t *)addr);
185 break;
186
187 case Q_XSETGQLIM:
188 if (vfsp->vfs_flag & VFS_RDONLY)
189 return XFS_ERROR(EROFS);
190 error = xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, XFS_DQ_GROUP,
191 (fs_disk_quota_t *)addr);
192 break;
193
194
195 case Q_XGETGQUOTA:
196 error = xfs_qm_scall_getquota(mp, (xfs_dqid_t)id, XFS_DQ_GROUP,
197 (fs_disk_quota_t *)addr);
198 break;
199
200 /*
201 * Quotas are entirely undefined after quotaoff in XFS quotas.
202 * For instance, there's no way to set limits when quotaoff.
203 */
204
205 default:
206 error = XFS_ERROR(EINVAL);
207 break;
208 }
209
210 return (error);
211}
212
213/*
214 * Turn off quota accounting and/or enforcement for all udquots and/or
215 * gdquots. Called only at unmount time.
216 *
217 * This assumes that there are no dquots of this file system cached
218 * incore, and modifies the ondisk dquot directly. Therefore, for example,
219 * it is an error to call this twice, without purging the cache.
220 */
221STATIC int
222xfs_qm_scall_quotaoff(
223 xfs_mount_t *mp,
224 uint flags,
225 boolean_t force)
226{
227 uint dqtype;
228 unsigned long s;
229 int error;
230 uint inactivate_flags;
231 xfs_qoff_logitem_t *qoffstart;
232 int nculprits;
233
234 if (!force && !capable(CAP_SYS_ADMIN))
235 return XFS_ERROR(EPERM);
236 /*
237 * No file system can have quotas enabled on disk but not in core.
238 * Note that quota utilities (like quotaoff) _expect_
239 * errno == EEXIST here.
240 */
241 if ((mp->m_qflags & flags) == 0)
242 return XFS_ERROR(EEXIST);
243 error = 0;
244
245 flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD);
246
247 /*
248 * We don't want to deal with two quotaoffs messing up each other,
249 * so we're going to serialize it. quotaoff isn't exactly a performance
250 * critical thing.
251 * If quotaoff, then we must be dealing with the root filesystem.
252 */
253 ASSERT(mp->m_quotainfo);
254 if (mp->m_quotainfo)
255 mutex_lock(&(XFS_QI_QOFFLOCK(mp)), PINOD);
256
257 ASSERT(mp->m_quotainfo);
258
259 /*
260 * If we're just turning off quota enforcement, change mp and go.
261 */
262 if ((flags & XFS_ALL_QUOTA_ACCT) == 0) {
263 mp->m_qflags &= ~(flags);
264
265 s = XFS_SB_LOCK(mp);
266 mp->m_sb.sb_qflags = mp->m_qflags;
267 XFS_SB_UNLOCK(mp, s);
268 mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
269
270 /* XXX what to do if error ? Revert back to old vals incore ? */
271 error = xfs_qm_write_sb_changes(mp, XFS_SB_QFLAGS);
272 return (error);
273 }
274
275 dqtype = 0;
276 inactivate_flags = 0;
277 /*
278 * If accounting is off, we must turn enforcement off, clear the
279 * quota 'CHKD' certificate to make it known that we have to
280 * do a quotacheck the next time this quota is turned on.
281 */
282 if (flags & XFS_UQUOTA_ACCT) {
283 dqtype |= XFS_QMOPT_UQUOTA;
284 flags |= (XFS_UQUOTA_CHKD | XFS_UQUOTA_ENFD);
285 inactivate_flags |= XFS_UQUOTA_ACTIVE;
286 }
287 if (flags & XFS_GQUOTA_ACCT) {
288 dqtype |= XFS_QMOPT_GQUOTA;
289 flags |= (XFS_GQUOTA_CHKD | XFS_GQUOTA_ENFD);
290 inactivate_flags |= XFS_GQUOTA_ACTIVE;
291 }
292
293 /*
294 * Nothing to do? Don't complain. This happens when we're just
295 * turning off quota enforcement.
296 */
297 if ((mp->m_qflags & flags) == 0) {
298 mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
299 return (0);
300 }
301
302 /*
303 * Write the LI_QUOTAOFF log record, and do SB changes atomically,
304 * and synchronously.
305 */
306 xfs_qm_log_quotaoff(mp, &qoffstart, flags);
307
308 /*
309 * Next we clear the XFS_MOUNT_*DQ_ACTIVE bit(s) in the mount struct
310 * to take care of the race between dqget and quotaoff. We don't take
311 * any special locks to reset these bits. All processes need to check
312 * these bits *after* taking inode lock(s) to see if the particular
313 * quota type is in the process of being turned off. If *ACTIVE, it is
314 * guaranteed that all dquot structures and all quotainode ptrs will all
315 * stay valid as long as that inode is kept locked.
316 *
317 * There is no turning back after this.
318 */
319 mp->m_qflags &= ~inactivate_flags;
320
321 /*
322 * Give back all the dquot reference(s) held by inodes.
323 * Here we go thru every single incore inode in this file system, and
324 * do a dqrele on the i_udquot/i_gdquot that it may have.
325 * Essentially, as long as somebody has an inode locked, this guarantees
326 * that quotas will not be turned off. This is handy because in a
327 * transaction once we lock the inode(s) and check for quotaon, we can
328 * depend on the quota inodes (and other things) being valid as long as
329 * we keep the lock(s).
330 */
331 xfs_qm_dqrele_all_inodes(mp, flags);
332
333 /*
334 * Next we make the changes in the quota flag in the mount struct.
335 * This isn't protected by a particular lock directly, because we
336 * don't want to take a mrlock everytime we depend on quotas being on.
337 */
338 mp->m_qflags &= ~(flags);
339
340 /*
341 * Go through all the dquots of this file system and purge them,
342 * according to what was turned off. We may not be able to get rid
343 * of all dquots, because dquots can have temporary references that
344 * are not attached to inodes. eg. xfs_setattr, xfs_create.
345 * So, if we couldn't purge all the dquots from the filesystem,
346 * we can't get rid of the incore data structures.
347 */
348 while ((nculprits = xfs_qm_dqpurge_all(mp, dqtype|XFS_QMOPT_QUOTAOFF)))
349 delay(10 * nculprits);
350
351 /*
352 * Transactions that had started before ACTIVE state bit was cleared
353 * could have logged many dquots, so they'd have higher LSNs than
354 * the first QUOTAOFF log record does. If we happen to crash when
355 * the tail of the log has gone past the QUOTAOFF record, but
356 * before the last dquot modification, those dquots __will__
357 * recover, and that's not good.
358 *
359 * So, we have QUOTAOFF start and end logitems; the start
360 * logitem won't get overwritten until the end logitem appears...
361 */
362 xfs_qm_log_quotaoff_end(mp, qoffstart, flags);
363
364 /*
365 * If quotas is completely disabled, close shop.
366 */
367 if ((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_ALL) {
368 mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
369 xfs_qm_destroy_quotainfo(mp);
370 return (0);
371 }
372
373 /*
374 * Release our quotainode references, and vn_purge them,
375 * if we don't need them anymore.
376 */
377 if ((dqtype & XFS_QMOPT_UQUOTA) && XFS_QI_UQIP(mp)) {
378 XFS_PURGE_INODE(XFS_QI_UQIP(mp));
379 XFS_QI_UQIP(mp) = NULL;
380 }
381 if ((dqtype & XFS_QMOPT_GQUOTA) && XFS_QI_GQIP(mp)) {
382 XFS_PURGE_INODE(XFS_QI_GQIP(mp));
383 XFS_QI_GQIP(mp) = NULL;
384 }
385 mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
386
387 return (error);
388}
389
390STATIC int
391xfs_qm_scall_trunc_qfiles(
392 xfs_mount_t *mp,
393 uint flags)
394{
395 int error;
396 xfs_inode_t *qip;
397
398 if (!capable(CAP_SYS_ADMIN))
399 return XFS_ERROR(EPERM);
400 error = 0;
401 if (!XFS_SB_VERSION_HASQUOTA(&mp->m_sb) || flags == 0) {
402 qdprintk("qtrunc flags=%x m_qflags=%x\n", flags, mp->m_qflags);
403 return XFS_ERROR(EINVAL);
404 }
405
406 if ((flags & XFS_DQ_USER) && mp->m_sb.sb_uquotino != NULLFSINO) {
407 error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, 0, &qip, 0);
408 if (! error) {
409 (void) xfs_truncate_file(mp, qip);
410 VN_RELE(XFS_ITOV(qip));
411 }
412 }
413
414 if ((flags & XFS_DQ_GROUP) && mp->m_sb.sb_gquotino != NULLFSINO) {
415 error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, 0, &qip, 0);
416 if (! error) {
417 (void) xfs_truncate_file(mp, qip);
418 VN_RELE(XFS_ITOV(qip));
419 }
420 }
421
422 return (error);
423}
424
425
426/*
427 * Switch on (a given) quota enforcement for a filesystem. This takes
428 * effect immediately.
429 * (Switching on quota accounting must be done at mount time.)
430 */
431STATIC int
432xfs_qm_scall_quotaon(
433 xfs_mount_t *mp,
434 uint flags)
435{
436 int error;
437 unsigned long s;
438 uint qf;
439 uint accflags;
440 __int64_t sbflags;
441
442 if (!capable(CAP_SYS_ADMIN))
443 return XFS_ERROR(EPERM);
444
445 flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD);
446 /*
447 * Switching on quota accounting must be done at mount time.
448 */
449 accflags = flags & XFS_ALL_QUOTA_ACCT;
450 flags &= ~(XFS_ALL_QUOTA_ACCT);
451
452 sbflags = 0;
453
454 if (flags == 0) {
455 qdprintk("quotaon: zero flags, m_qflags=%x\n", mp->m_qflags);
456 return XFS_ERROR(EINVAL);
457 }
458
459 /* No fs can turn on quotas with a delayed effect */
460 ASSERT((flags & XFS_ALL_QUOTA_ACCT) == 0);
461
462 /*
463 * Can't enforce without accounting. We check the superblock
464 * qflags here instead of m_qflags because rootfs can have
465 * quota acct on ondisk without m_qflags' knowing.
466 */
467 if (((flags & XFS_UQUOTA_ACCT) == 0 &&
468 (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) == 0 &&
469 (flags & XFS_UQUOTA_ENFD))
470 ||
471 ((flags & XFS_GQUOTA_ACCT) == 0 &&
472 (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 &&
473 (flags & XFS_GQUOTA_ENFD))) {
474 qdprintk("Can't enforce without acct, flags=%x sbflags=%x\n",
475 flags, mp->m_sb.sb_qflags);
476 return XFS_ERROR(EINVAL);
477 }
478 /*
479 * If everything's upto-date incore, then don't waste time.
480 */
481 if ((mp->m_qflags & flags) == flags)
482 return XFS_ERROR(EEXIST);
483
484 /*
485 * Change sb_qflags on disk but not incore mp->qflags
486 * if this is the root filesystem.
487 */
488 s = XFS_SB_LOCK(mp);
489 qf = mp->m_sb.sb_qflags;
490 mp->m_sb.sb_qflags = qf | flags;
491 XFS_SB_UNLOCK(mp, s);
492
493 /*
494 * There's nothing to change if it's the same.
495 */
496 if ((qf & flags) == flags && sbflags == 0)
497 return XFS_ERROR(EEXIST);
498 sbflags |= XFS_SB_QFLAGS;
499
500 if ((error = xfs_qm_write_sb_changes(mp, sbflags)))
501 return (error);
502 /*
503 * If we aren't trying to switch on quota enforcement, we are done.
504 */
505 if (((mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) !=
506 (mp->m_qflags & XFS_UQUOTA_ACCT)) ||
507 (flags & XFS_ALL_QUOTA_ENFD) == 0)
508 return (0);
509
510 if (! XFS_IS_QUOTA_RUNNING(mp))
511 return XFS_ERROR(ESRCH);
512
513 /*
514 * Switch on quota enforcement in core.
515 */
516 mutex_lock(&(XFS_QI_QOFFLOCK(mp)), PINOD);
517 mp->m_qflags |= (flags & XFS_ALL_QUOTA_ENFD);
518 mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
519
520 return (0);
521}
522
523
524
525/*
526 * Return quota status information, such as uquota-off, enforcements, etc.
527 */
528STATIC int
529xfs_qm_scall_getqstat(
530 xfs_mount_t *mp,
531 fs_quota_stat_t *out)
532{
533 xfs_inode_t *uip, *gip;
534 boolean_t tempuqip, tempgqip;
535
536 uip = gip = NULL;
537 tempuqip = tempgqip = B_FALSE;
538 memset(out, 0, sizeof(fs_quota_stat_t));
539
540 out->qs_version = FS_QSTAT_VERSION;
541 if (! XFS_SB_VERSION_HASQUOTA(&mp->m_sb)) {
542 out->qs_uquota.qfs_ino = NULLFSINO;
543 out->qs_gquota.qfs_ino = NULLFSINO;
544 return (0);
545 }
546 out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags &
547 (XFS_ALL_QUOTA_ACCT|
548 XFS_ALL_QUOTA_ENFD));
549 out->qs_pad = 0;
550 out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino;
551 out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;
552
553 if (mp->m_quotainfo) {
554 uip = mp->m_quotainfo->qi_uquotaip;
555 gip = mp->m_quotainfo->qi_gquotaip;
556 }
557 if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) {
558 if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
559 0, 0, &uip, 0) == 0)
560 tempuqip = B_TRUE;
561 }
562 if (!gip && mp->m_sb.sb_gquotino != NULLFSINO) {
563 if (xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
564 0, 0, &gip, 0) == 0)
565 tempgqip = B_TRUE;
566 }
567 if (uip) {
568 out->qs_uquota.qfs_nblks = uip->i_d.di_nblocks;
569 out->qs_uquota.qfs_nextents = uip->i_d.di_nextents;
570 if (tempuqip)
571 VN_RELE(XFS_ITOV(uip));
572 }
573 if (gip) {
574 out->qs_gquota.qfs_nblks = gip->i_d.di_nblocks;
575 out->qs_gquota.qfs_nextents = gip->i_d.di_nextents;
576 if (tempgqip)
577 VN_RELE(XFS_ITOV(gip));
578 }
579 if (mp->m_quotainfo) {
580 out->qs_incoredqs = XFS_QI_MPLNDQUOTS(mp);
581 out->qs_btimelimit = XFS_QI_BTIMELIMIT(mp);
582 out->qs_itimelimit = XFS_QI_ITIMELIMIT(mp);
583 out->qs_rtbtimelimit = XFS_QI_RTBTIMELIMIT(mp);
584 out->qs_bwarnlimit = XFS_QI_BWARNLIMIT(mp);
585 out->qs_iwarnlimit = XFS_QI_IWARNLIMIT(mp);
586 }
587 return (0);
588}
589
590/*
591 * Adjust quota limits, and start/stop timers accordingly.
592 */
593STATIC int
594xfs_qm_scall_setqlim(
595 xfs_mount_t *mp,
596 xfs_dqid_t id,
597 uint type,
598 fs_disk_quota_t *newlim)
599{
600 xfs_disk_dquot_t *ddq;
601 xfs_dquot_t *dqp;
602 xfs_trans_t *tp;
603 int error;
604 xfs_qcnt_t hard, soft;
605
606 if (!capable(CAP_SYS_ADMIN))
607 return XFS_ERROR(EPERM);
608
609 if ((newlim->d_fieldmask & (FS_DQ_LIMIT_MASK|FS_DQ_TIMER_MASK)) == 0)
610 return (0);
611
612 tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SETQLIM);
613 if ((error = xfs_trans_reserve(tp, 0, sizeof(xfs_disk_dquot_t) + 128,
614 0, 0, XFS_DEFAULT_LOG_COUNT))) {
615 xfs_trans_cancel(tp, 0);
616 return (error);
617 }
618
619 /*
620 * We don't want to race with a quotaoff so take the quotaoff lock.
621 * (We don't hold an inode lock, so there's nothing else to stop
622 * a quotaoff from happening). (XXXThis doesn't currently happen
623 * because we take the vfslock before calling xfs_qm_sysent).
624 */
625 mutex_lock(&(XFS_QI_QOFFLOCK(mp)), PINOD);
626
627 /*
628 * Get the dquot (locked), and join it to the transaction.
629 * Allocate the dquot if this doesn't exist.
630 */
631 if ((error = xfs_qm_dqget(mp, NULL, id, type, XFS_QMOPT_DQALLOC, &dqp))) {
632 xfs_trans_cancel(tp, XFS_TRANS_ABORT);
633 mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
634 ASSERT(error != ENOENT);
635 return (error);
636 }
637 xfs_dqtrace_entry(dqp, "Q_SETQLIM: AFT DQGET");
638 xfs_trans_dqjoin(tp, dqp);
639 ddq = &dqp->q_core;
640
641 /*
642 * Make sure that hardlimits are >= soft limits before changing.
643 */
644 hard = (newlim->d_fieldmask & FS_DQ_BHARD) ?
645 (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_blk_hardlimit) :
646 INT_GET(ddq->d_blk_hardlimit, ARCH_CONVERT);
647 soft = (newlim->d_fieldmask & FS_DQ_BSOFT) ?
648 (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_blk_softlimit) :
649 INT_GET(ddq->d_blk_softlimit, ARCH_CONVERT);
650 if (hard == 0 || hard >= soft) {
651 INT_SET(ddq->d_blk_hardlimit, ARCH_CONVERT, hard);
652 INT_SET(ddq->d_blk_softlimit, ARCH_CONVERT, soft);
653 if (id == 0) {
654 mp->m_quotainfo->qi_bhardlimit = hard;
655 mp->m_quotainfo->qi_bsoftlimit = soft;
656 }
657 } else {
658 qdprintk("blkhard %Ld < blksoft %Ld\n", hard, soft);
659 }
660 hard = (newlim->d_fieldmask & FS_DQ_RTBHARD) ?
661 (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_rtb_hardlimit) :
662 INT_GET(ddq->d_rtb_hardlimit, ARCH_CONVERT);
663 soft = (newlim->d_fieldmask & FS_DQ_RTBSOFT) ?
664 (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_rtb_softlimit) :
665 INT_GET(ddq->d_rtb_softlimit, ARCH_CONVERT);
666 if (hard == 0 || hard >= soft) {
667 INT_SET(ddq->d_rtb_hardlimit, ARCH_CONVERT, hard);
668 INT_SET(ddq->d_rtb_softlimit, ARCH_CONVERT, soft);
669 if (id == 0) {
670 mp->m_quotainfo->qi_rtbhardlimit = hard;
671 mp->m_quotainfo->qi_rtbsoftlimit = soft;
672 }
673 } else {
674 qdprintk("rtbhard %Ld < rtbsoft %Ld\n", hard, soft);
675 }
676
677 hard = (newlim->d_fieldmask & FS_DQ_IHARD) ?
678 (xfs_qcnt_t) newlim->d_ino_hardlimit :
679 INT_GET(ddq->d_ino_hardlimit, ARCH_CONVERT);
680 soft = (newlim->d_fieldmask & FS_DQ_ISOFT) ?
681 (xfs_qcnt_t) newlim->d_ino_softlimit :
682 INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT);
683 if (hard == 0 || hard >= soft) {
684 INT_SET(ddq->d_ino_hardlimit, ARCH_CONVERT, hard);
685 INT_SET(ddq->d_ino_softlimit, ARCH_CONVERT, soft);
686 if (id == 0) {
687 mp->m_quotainfo->qi_ihardlimit = hard;
688 mp->m_quotainfo->qi_isoftlimit = soft;
689 }
690 } else {
691 qdprintk("ihard %Ld < isoft %Ld\n", hard, soft);
692 }
693
694 if (id == 0) {
695 /*
696 * Timelimits for the super user set the relative time
697 * the other users can be over quota for this file system.
698 * If it is zero a default is used. Ditto for the default
699 * soft and hard limit values (already done, above).
700 */
701 if (newlim->d_fieldmask & FS_DQ_BTIMER) {
702 mp->m_quotainfo->qi_btimelimit = newlim->d_btimer;
703 INT_SET(ddq->d_btimer, ARCH_CONVERT, newlim->d_btimer);
704 }
705 if (newlim->d_fieldmask & FS_DQ_ITIMER) {
706 mp->m_quotainfo->qi_itimelimit = newlim->d_itimer;
707 INT_SET(ddq->d_itimer, ARCH_CONVERT, newlim->d_itimer);
708 }
709 if (newlim->d_fieldmask & FS_DQ_RTBTIMER) {
710 mp->m_quotainfo->qi_rtbtimelimit = newlim->d_rtbtimer;
711 INT_SET(ddq->d_rtbtimer, ARCH_CONVERT, newlim->d_rtbtimer);
712 }
713 } else /* if (XFS_IS_QUOTA_ENFORCED(mp)) */ {
714 /*
715 * If the user is now over quota, start the timelimit.
716 * The user will not be 'warned'.
717 * Note that we keep the timers ticking, whether enforcement
718 * is on or off. We don't really want to bother with iterating
719 * over all ondisk dquots and turning the timers on/off.
720 */
721 xfs_qm_adjust_dqtimers(mp, ddq);
722 }
723 dqp->dq_flags |= XFS_DQ_DIRTY;
724 xfs_trans_log_dquot(tp, dqp);
725
726 xfs_dqtrace_entry(dqp, "Q_SETQLIM: COMMIT");
727 xfs_trans_commit(tp, 0, NULL);
728 xfs_qm_dqprint(dqp);
729 xfs_qm_dqrele(dqp);
730 mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
731
732 return (0);
733}
734
735STATIC int
736xfs_qm_scall_getquota(
737 xfs_mount_t *mp,
738 xfs_dqid_t id,
739 uint type,
740 fs_disk_quota_t *out)
741{
742 xfs_dquot_t *dqp;
743 int error;
744
745 /*
746 * Try to get the dquot. We don't want it allocated on disk, so
747 * we aren't passing the XFS_QMOPT_DOALLOC flag. If it doesn't
748 * exist, we'll get ENOENT back.
749 */
750 if ((error = xfs_qm_dqget(mp, NULL, id, type, 0, &dqp))) {
751 return (error);
752 }
753
754 xfs_dqtrace_entry(dqp, "Q_GETQUOTA SUCCESS");
755 /*
756 * If everything's NULL, this dquot doesn't quite exist as far as
757 * our utility programs are concerned.
758 */
759 if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) {
760 xfs_qm_dqput(dqp);
761 return XFS_ERROR(ENOENT);
762 }
763 /* xfs_qm_dqprint(dqp); */
764 /*
765 * Convert the disk dquot to the exportable format
766 */
767 xfs_qm_export_dquot(mp, &dqp->q_core, out);
768 xfs_qm_dqput(dqp);
769 return (error ? XFS_ERROR(EFAULT) : 0);
770}
771
772
773STATIC int
774xfs_qm_log_quotaoff_end(
775 xfs_mount_t *mp,
776 xfs_qoff_logitem_t *startqoff,
777 uint flags)
778{
779 xfs_trans_t *tp;
780 int error;
781 xfs_qoff_logitem_t *qoffi;
782
783 tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF_END);
784
785 if ((error = xfs_trans_reserve(tp, 0, sizeof(xfs_qoff_logitem_t) * 2,
786 0, 0, XFS_DEFAULT_LOG_COUNT))) {
787 xfs_trans_cancel(tp, 0);
788 return (error);
789 }
790
791 qoffi = xfs_trans_get_qoff_item(tp, startqoff,
792 flags & XFS_ALL_QUOTA_ACCT);
793 xfs_trans_log_quotaoff_item(tp, qoffi);
794
795 /*
796 * We have to make sure that the transaction is secure on disk before we
797 * return and actually stop quota accounting. So, make it synchronous.
798 * We don't care about quotoff's performance.
799 */
800 xfs_trans_set_sync(tp);
801 error = xfs_trans_commit(tp, 0, NULL);
802 return (error);
803}
804
805
806STATIC int
807xfs_qm_log_quotaoff(
808 xfs_mount_t *mp,
809 xfs_qoff_logitem_t **qoffstartp,
810 uint flags)
811{
812 xfs_trans_t *tp;
813 int error;
814 unsigned long s;
815 xfs_qoff_logitem_t *qoffi=NULL;
816 uint oldsbqflag=0;
817
818 tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF);
819 if ((error = xfs_trans_reserve(tp, 0,
820 sizeof(xfs_qoff_logitem_t) * 2 +
821 mp->m_sb.sb_sectsize + 128,
822 0,
823 0,
824 XFS_DEFAULT_LOG_COUNT))) {
825 goto error0;
826 }
827
828 qoffi = xfs_trans_get_qoff_item(tp, NULL, flags & XFS_ALL_QUOTA_ACCT);
829 xfs_trans_log_quotaoff_item(tp, qoffi);
830
831 s = XFS_SB_LOCK(mp);
832 oldsbqflag = mp->m_sb.sb_qflags;
833 mp->m_sb.sb_qflags = (mp->m_qflags & ~(flags)) & XFS_MOUNT_QUOTA_ALL;
834 XFS_SB_UNLOCK(mp, s);
835
836 xfs_mod_sb(tp, XFS_SB_QFLAGS);
837
838 /*
839 * We have to make sure that the transaction is secure on disk before we
840 * return and actually stop quota accounting. So, make it synchronous.
841 * We don't care about quotoff's performance.
842 */
843 xfs_trans_set_sync(tp);
844 error = xfs_trans_commit(tp, 0, NULL);
845
846error0:
847 if (error) {
848 xfs_trans_cancel(tp, 0);
849 /*
850 * No one else is modifying sb_qflags, so this is OK.
851 * We still hold the quotaofflock.
852 */
853 s = XFS_SB_LOCK(mp);
854 mp->m_sb.sb_qflags = oldsbqflag;
855 XFS_SB_UNLOCK(mp, s);
856 }
857 *qoffstartp = qoffi;
858 return (error);
859}
860
861
862/*
863 * Translate an internal style on-disk-dquot to the exportable format.
864 * The main differences are that the counters/limits are all in Basic
865 * Blocks (BBs) instead of the internal FSBs, and all on-disk data has
866 * to be converted to the native endianness.
867 */
868STATIC void
869xfs_qm_export_dquot(
870 xfs_mount_t *mp,
871 xfs_disk_dquot_t *src,
872 struct fs_disk_quota *dst)
873{
874 memset(dst, 0, sizeof(*dst));
875 dst->d_version = FS_DQUOT_VERSION; /* different from src->d_version */
876 dst->d_flags =
877 xfs_qm_export_qtype_flags(INT_GET(src->d_flags, ARCH_CONVERT));
878 dst->d_id = INT_GET(src->d_id, ARCH_CONVERT);
879 dst->d_blk_hardlimit = (__uint64_t)
880 XFS_FSB_TO_BB(mp, INT_GET(src->d_blk_hardlimit, ARCH_CONVERT));
881 dst->d_blk_softlimit = (__uint64_t)
882 XFS_FSB_TO_BB(mp, INT_GET(src->d_blk_softlimit, ARCH_CONVERT));
883 dst->d_ino_hardlimit = (__uint64_t)
884 INT_GET(src->d_ino_hardlimit, ARCH_CONVERT);
885 dst->d_ino_softlimit = (__uint64_t)
886 INT_GET(src->d_ino_softlimit, ARCH_CONVERT);
887 dst->d_bcount = (__uint64_t)
888 XFS_FSB_TO_BB(mp, INT_GET(src->d_bcount, ARCH_CONVERT));
889 dst->d_icount = (__uint64_t) INT_GET(src->d_icount, ARCH_CONVERT);
890 dst->d_btimer = (__uint32_t) INT_GET(src->d_btimer, ARCH_CONVERT);
891 dst->d_itimer = (__uint32_t) INT_GET(src->d_itimer, ARCH_CONVERT);
892 dst->d_iwarns = INT_GET(src->d_iwarns, ARCH_CONVERT);
893 dst->d_bwarns = INT_GET(src->d_bwarns, ARCH_CONVERT);
894
895 dst->d_rtb_hardlimit = (__uint64_t)
896 XFS_FSB_TO_BB(mp, INT_GET(src->d_rtb_hardlimit, ARCH_CONVERT));
897 dst->d_rtb_softlimit = (__uint64_t)
898 XFS_FSB_TO_BB(mp, INT_GET(src->d_rtb_softlimit, ARCH_CONVERT));
899 dst->d_rtbcount = (__uint64_t)
900 XFS_FSB_TO_BB(mp, INT_GET(src->d_rtbcount, ARCH_CONVERT));
901 dst->d_rtbtimer = (__uint32_t) INT_GET(src->d_rtbtimer, ARCH_CONVERT);
902 dst->d_rtbwarns = INT_GET(src->d_rtbwarns, ARCH_CONVERT);
903
904 /*
905 * Internally, we don't reset all the timers when quota enforcement
906 * gets turned off. No need to confuse the userlevel code,
907 * so return zeroes in that case.
908 */
909 if (! XFS_IS_QUOTA_ENFORCED(mp)) {
910 dst->d_btimer = 0;
911 dst->d_itimer = 0;
912 dst->d_rtbtimer = 0;
913 }
914
915#ifdef DEBUG
916 if (XFS_IS_QUOTA_ENFORCED(mp) && dst->d_id != 0) {
917 if (((int) dst->d_bcount >= (int) dst->d_blk_softlimit) &&
918 (dst->d_blk_softlimit > 0)) {
919 ASSERT(dst->d_btimer != 0);
920 }
921 if (((int) dst->d_icount >= (int) dst->d_ino_softlimit) &&
922 (dst->d_ino_softlimit > 0)) {
923 ASSERT(dst->d_itimer != 0);
924 }
925 }
926#endif
927}
928
929STATIC uint
930xfs_qm_import_qtype_flags(
931 uint uflags)
932{
933 /*
934 * Can't be both at the same time.
935 */
936 if (((uflags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) ==
937 (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) ||
938 ((uflags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) == 0))
939 return (0);
940
941 return (uflags & XFS_USER_QUOTA) ?
942 XFS_DQ_USER : XFS_DQ_GROUP;
943}
944
945STATIC uint
946xfs_qm_export_qtype_flags(
947 uint flags)
948{
949 /*
950 * Can't be both at the same time.
951 */
952 ASSERT((flags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) !=
953 (XFS_GROUP_QUOTA | XFS_USER_QUOTA));
954 ASSERT((flags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) != 0);
955
956 return (flags & XFS_DQ_USER) ?
957 XFS_USER_QUOTA : XFS_GROUP_QUOTA;
958}
959
960STATIC uint
961xfs_qm_import_flags(
962 uint uflags)
963{
964 uint flags = 0;
965
966 if (uflags & XFS_QUOTA_UDQ_ACCT)
967 flags |= XFS_UQUOTA_ACCT;
968 if (uflags & XFS_QUOTA_GDQ_ACCT)
969 flags |= XFS_GQUOTA_ACCT;
970 if (uflags & XFS_QUOTA_UDQ_ENFD)
971 flags |= XFS_UQUOTA_ENFD;
972 if (uflags & XFS_QUOTA_GDQ_ENFD)
973 flags |= XFS_GQUOTA_ENFD;
974 return (flags);
975}
976
977
978STATIC uint
979xfs_qm_export_flags(
980 uint flags)
981{
982 uint uflags;
983
984 uflags = 0;
985 if (flags & XFS_UQUOTA_ACCT)
986 uflags |= XFS_QUOTA_UDQ_ACCT;
987 if (flags & XFS_GQUOTA_ACCT)
988 uflags |= XFS_QUOTA_GDQ_ACCT;
989 if (flags & XFS_UQUOTA_ENFD)
990 uflags |= XFS_QUOTA_UDQ_ENFD;
991 if (flags & XFS_GQUOTA_ENFD)
992 uflags |= XFS_QUOTA_GDQ_ENFD;
993 return (uflags);
994}
995
996
997/*
998 * Go thru all the inodes in the file system, releasing their dquots.
999 * Note that the mount structure gets modified to indicate that quotas are off
1000 * AFTER this, in the case of quotaoff. This also gets called from
1001 * xfs_rootumount.
1002 */
1003void
1004xfs_qm_dqrele_all_inodes(
1005 struct xfs_mount *mp,
1006 uint flags)
1007{
1008 vmap_t vmap;
1009 xfs_inode_t *ip, *topino;
1010 uint ireclaims;
1011 vnode_t *vp;
1012 boolean_t vnode_refd;
1013
1014 ASSERT(mp->m_quotainfo);
1015
1016again:
1017 XFS_MOUNT_ILOCK(mp);
1018 ip = mp->m_inodes;
1019 if (ip == NULL) {
1020 XFS_MOUNT_IUNLOCK(mp);
1021 return;
1022 }
1023 do {
1024 /* Skip markers inserted by xfs_sync */
1025 if (ip->i_mount == NULL) {
1026 ip = ip->i_mnext;
1027 continue;
1028 }
1029 /* Root inode, rbmip and rsumip have associated blocks */
1030 if (ip == XFS_QI_UQIP(mp) || ip == XFS_QI_GQIP(mp)) {
1031 ASSERT(ip->i_udquot == NULL);
1032 ASSERT(ip->i_gdquot == NULL);
1033 ip = ip->i_mnext;
1034 continue;
1035 }
1036 vp = XFS_ITOV_NULL(ip);
1037 if (!vp) {
1038 ASSERT(ip->i_udquot == NULL);
1039 ASSERT(ip->i_gdquot == NULL);
1040 ip = ip->i_mnext;
1041 continue;
1042 }
1043 vnode_refd = B_FALSE;
1044 if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL) == 0) {
1045 /*
1046 * Sample vp mapping while holding the mplock, lest
1047 * we come across a non-existent vnode.
1048 */
1049 VMAP(vp, vmap);
1050 ireclaims = mp->m_ireclaims;
1051 topino = mp->m_inodes;
1052 XFS_MOUNT_IUNLOCK(mp);
1053
1054 /* XXX restart limit ? */
1055 if ( ! (vp = vn_get(vp, &vmap)))
1056 goto again;
1057 xfs_ilock(ip, XFS_ILOCK_EXCL);
1058 vnode_refd = B_TRUE;
1059 } else {
1060 ireclaims = mp->m_ireclaims;
1061 topino = mp->m_inodes;
1062 XFS_MOUNT_IUNLOCK(mp);
1063 }
1064
1065 /*
1066 * We don't keep the mountlock across the dqrele() call,
1067 * since it can take a while..
1068 */
1069 if ((flags & XFS_UQUOTA_ACCT) && ip->i_udquot) {
1070 xfs_qm_dqrele(ip->i_udquot);
1071 ip->i_udquot = NULL;
1072 }
1073 if ((flags & XFS_GQUOTA_ACCT) && ip->i_gdquot) {
1074 xfs_qm_dqrele(ip->i_gdquot);
1075 ip->i_gdquot = NULL;
1076 }
1077 xfs_iunlock(ip, XFS_ILOCK_EXCL);
1078 /*
1079 * Wait until we've dropped the ilock and mountlock to
1080 * do the vn_rele. Or be condemned to an eternity in the
1081 * inactive code in hell.
1082 */
1083 if (vnode_refd)
1084 VN_RELE(vp);
1085 XFS_MOUNT_ILOCK(mp);
1086 /*
1087 * If an inode was inserted or removed, we gotta
1088 * start over again.
1089 */
1090 if (topino != mp->m_inodes || mp->m_ireclaims != ireclaims) {
1091 /* XXX use a sentinel */
1092 XFS_MOUNT_IUNLOCK(mp);
1093 goto again;
1094 }
1095 ip = ip->i_mnext;
1096 } while (ip != mp->m_inodes);
1097
1098 XFS_MOUNT_IUNLOCK(mp);
1099}
1100
1101/*------------------------------------------------------------------------*/
1102#ifdef DEBUG
1103/*
1104 * This contains all the test functions for XFS disk quotas.
1105 * Currently it does a quota accounting check. ie. it walks through
1106 * all inodes in the file system, calculating the dquot accounting fields,
1107 * and prints out any inconsistencies.
1108 */
1109xfs_dqhash_t *qmtest_udqtab;
1110xfs_dqhash_t *qmtest_gdqtab;
1111int qmtest_hashmask;
1112int qmtest_nfails;
1113mutex_t qcheck_lock;
1114
1115#define DQTEST_HASHVAL(mp, id) (((__psunsigned_t)(mp) + \
1116 (__psunsigned_t)(id)) & \
1117 (qmtest_hashmask - 1))
1118
1119#define DQTEST_HASH(mp, id, type) ((type & XFS_DQ_USER) ? \
1120 (qmtest_udqtab + \
1121 DQTEST_HASHVAL(mp, id)) : \
1122 (qmtest_gdqtab + \
1123 DQTEST_HASHVAL(mp, id)))
1124
1125#define DQTEST_LIST_PRINT(l, NXT, title) \
1126{ \
1127 xfs_dqtest_t *dqp; int i = 0;\
1128 cmn_err(CE_DEBUG, "%s (#%d)", title, (int) (l)->qh_nelems); \
1129 for (dqp = (xfs_dqtest_t *)(l)->qh_next; dqp != NULL; \
1130 dqp = (xfs_dqtest_t *)dqp->NXT) { \
1131 cmn_err(CE_DEBUG, " %d. \"%d (%s)\" bcnt = %d, icnt = %d", \
1132 ++i, dqp->d_id, DQFLAGTO_TYPESTR(dqp), \
1133 dqp->d_bcount, dqp->d_icount); } \
1134}
1135
1136typedef struct dqtest {
1137 xfs_dqmarker_t q_lists;
1138 xfs_dqhash_t *q_hash; /* the hashchain header */
1139 xfs_mount_t *q_mount; /* filesystem this relates to */
1140 xfs_dqid_t d_id; /* user id or group id */
1141 xfs_qcnt_t d_bcount; /* # disk blocks owned by the user */
1142 xfs_qcnt_t d_icount; /* # inodes owned by the user */
1143} xfs_dqtest_t;
1144
1145STATIC void
1146xfs_qm_hashinsert(xfs_dqhash_t *h, xfs_dqtest_t *dqp)
1147{
1148 xfs_dquot_t *d;
1149 if (((d) = (h)->qh_next))
1150 (d)->HL_PREVP = &((dqp)->HL_NEXT);
1151 (dqp)->HL_NEXT = d;
1152 (dqp)->HL_PREVP = &((h)->qh_next);
1153 (h)->qh_next = (xfs_dquot_t *)dqp;
1154 (h)->qh_version++;
1155 (h)->qh_nelems++;
1156}
1157STATIC void
1158xfs_qm_dqtest_print(
1159 xfs_dqtest_t *d)
1160{
1161 cmn_err(CE_DEBUG, "-----------DQTEST DQUOT----------------");
1162 cmn_err(CE_DEBUG, "---- dquot ID = %d", d->d_id);
1163 cmn_err(CE_DEBUG, "---- type = %s", XFS_QM_ISUDQ(d)? "USR" : "GRP");
1164 cmn_err(CE_DEBUG, "---- fs = 0x%p", d->q_mount);
1165 cmn_err(CE_DEBUG, "---- bcount = %Lu (0x%x)",
1166 d->d_bcount, (int)d->d_bcount);
1167 cmn_err(CE_DEBUG, "---- icount = %Lu (0x%x)",
1168 d->d_icount, (int)d->d_icount);
1169 cmn_err(CE_DEBUG, "---------------------------");
1170}
1171
1172STATIC void
1173xfs_qm_dqtest_failed(
1174 xfs_dqtest_t *d,
1175 xfs_dquot_t *dqp,
1176 char *reason,
1177 xfs_qcnt_t a,
1178 xfs_qcnt_t b,
1179 int error)
1180{
1181 qmtest_nfails++;
1182 if (error)
1183 cmn_err(CE_DEBUG, "quotacheck failed id=%d, err=%d\nreason: %s",
1184 INT_GET(d->d_id, ARCH_CONVERT), error, reason);
1185 else
1186 cmn_err(CE_DEBUG, "quotacheck failed id=%d (%s) [%d != %d]",
1187 INT_GET(d->d_id, ARCH_CONVERT), reason, (int)a, (int)b);
1188 xfs_qm_dqtest_print(d);
1189 if (dqp)
1190 xfs_qm_dqprint(dqp);
1191}
1192
1193STATIC int
1194xfs_dqtest_cmp2(
1195 xfs_dqtest_t *d,
1196 xfs_dquot_t *dqp)
1197{
1198 int err = 0;
1199 if (INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) != d->d_icount) {
1200 xfs_qm_dqtest_failed(d, dqp, "icount mismatch",
1201 INT_GET(dqp->q_core.d_icount, ARCH_CONVERT),
1202 d->d_icount, 0);
1203 err++;
1204 }
1205 if (INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT) != d->d_bcount) {
1206 xfs_qm_dqtest_failed(d, dqp, "bcount mismatch",
1207 INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT),
1208 d->d_bcount, 0);
1209 err++;
1210 }
1211 if (INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT) &&
1212 INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT) >=
1213 INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT)) {
1214 if (!dqp->q_core.d_btimer && dqp->q_core.d_id) {
1215 cmn_err(CE_DEBUG,
1216 "%d [%s] [0x%p] BLK TIMER NOT STARTED",
1217 d->d_id, DQFLAGTO_TYPESTR(d), d->q_mount);
1218 err++;
1219 }
1220 }
1221 if (INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT) &&
1222 INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >=
1223 INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT)) {
1224 if (!dqp->q_core.d_itimer && dqp->q_core.d_id) {
1225 cmn_err(CE_DEBUG,
1226 "%d [%s] [0x%p] INO TIMER NOT STARTED",
1227 d->d_id, DQFLAGTO_TYPESTR(d), d->q_mount);
1228 err++;
1229 }
1230 }
1231#ifdef QUOTADEBUG
1232 if (!err) {
1233 cmn_err(CE_DEBUG, "%d [%s] [0x%p] qchecked",
1234 d->d_id, XFS_QM_ISUDQ(d) ? "USR" : "GRP", d->q_mount);
1235 }
1236#endif
1237 return (err);
1238}
1239
1240STATIC void
1241xfs_dqtest_cmp(
1242 xfs_dqtest_t *d)
1243{
1244 xfs_dquot_t *dqp;
1245 int error;
1246
1247 /* xfs_qm_dqtest_print(d); */
1248 if ((error = xfs_qm_dqget(d->q_mount, NULL, d->d_id, d->dq_flags, 0,
1249 &dqp))) {
1250 xfs_qm_dqtest_failed(d, NULL, "dqget failed", 0, 0, error);
1251 return;
1252 }
1253 xfs_dqtest_cmp2(d, dqp);
1254 xfs_qm_dqput(dqp);
1255}
1256
1257STATIC int
1258xfs_qm_internalqcheck_dqget(
1259 xfs_mount_t *mp,
1260 xfs_dqid_t id,
1261 uint type,
1262 xfs_dqtest_t **O_dq)
1263{
1264 xfs_dqtest_t *d;
1265 xfs_dqhash_t *h;
1266
1267 h = DQTEST_HASH(mp, id, type);
1268 for (d = (xfs_dqtest_t *) h->qh_next; d != NULL;
1269 d = (xfs_dqtest_t *) d->HL_NEXT) {
1270 /* DQTEST_LIST_PRINT(h, HL_NEXT, "@@@@@ dqtestlist @@@@@"); */
1271 if (d->d_id == id && mp == d->q_mount) {
1272 *O_dq = d;
1273 return (0);
1274 }
1275 }
1276 d = kmem_zalloc(sizeof(xfs_dqtest_t), KM_SLEEP);
1277 d->dq_flags = type;
1278 d->d_id = id;
1279 d->q_mount = mp;
1280 d->q_hash = h;
1281 xfs_qm_hashinsert(h, d);
1282 *O_dq = d;
1283 return (0);
1284}
1285
1286STATIC void
1287xfs_qm_internalqcheck_get_dquots(
1288 xfs_mount_t *mp,
1289 xfs_dqid_t uid,
1290 xfs_dqid_t gid,
1291 xfs_dqtest_t **ud,
1292 xfs_dqtest_t **gd)
1293{
1294 if (XFS_IS_UQUOTA_ON(mp))
1295 xfs_qm_internalqcheck_dqget(mp, uid, XFS_DQ_USER, ud);
1296 if (XFS_IS_GQUOTA_ON(mp))
1297 xfs_qm_internalqcheck_dqget(mp, gid, XFS_DQ_GROUP, gd);
1298}
1299
1300
1301STATIC void
1302xfs_qm_internalqcheck_dqadjust(
1303 xfs_inode_t *ip,
1304 xfs_dqtest_t *d)
1305{
1306 d->d_icount++;
1307 d->d_bcount += (xfs_qcnt_t)ip->i_d.di_nblocks;
1308}
1309
1310STATIC int
1311xfs_qm_internalqcheck_adjust(
1312 xfs_mount_t *mp, /* mount point for filesystem */
1313 xfs_ino_t ino, /* inode number to get data for */
1314 void __user *buffer, /* not used */
1315 int ubsize, /* not used */
1316 void *private_data, /* not used */
1317 xfs_daddr_t bno, /* starting block of inode cluster */
1318 int *ubused, /* not used */
1319 void *dip, /* not used */
1320 int *res) /* bulkstat result code */
1321{
1322 xfs_inode_t *ip;
1323 xfs_dqtest_t *ud, *gd;
1324 uint lock_flags;
1325 boolean_t ipreleased;
1326 int error;
1327
1328 ASSERT(XFS_IS_QUOTA_RUNNING(mp));
1329
1330 if (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino) {
1331 *res = BULKSTAT_RV_NOTHING;
1332 qdprintk("internalqcheck: ino=%llu, uqino=%llu, gqino=%llu\n",
1333 (unsigned long long) ino,
1334 (unsigned long long) mp->m_sb.sb_uquotino,
1335 (unsigned long long) mp->m_sb.sb_gquotino);
1336 return XFS_ERROR(EINVAL);
1337 }
1338 ipreleased = B_FALSE;
1339 again:
1340 lock_flags = XFS_ILOCK_SHARED;
1341 if ((error = xfs_iget(mp, NULL, ino, 0, lock_flags, &ip, bno))) {
1342 *res = BULKSTAT_RV_NOTHING;
1343 return (error);
1344 }
1345
1346 if (ip->i_d.di_mode == 0) {
1347 xfs_iput_new(ip, lock_flags);
1348 *res = BULKSTAT_RV_NOTHING;
1349 return XFS_ERROR(ENOENT);
1350 }
1351
1352 /*
1353 * This inode can have blocks after eof which can get released
1354 * when we send it to inactive. Since we don't check the dquot
1355 * until the after all our calculations are done, we must get rid
1356 * of those now.
1357 */
1358 if (! ipreleased) {
1359 xfs_iput(ip, lock_flags);
1360 ipreleased = B_TRUE;
1361 goto again;
1362 }
1363 xfs_qm_internalqcheck_get_dquots(mp,
1364 (xfs_dqid_t) ip->i_d.di_uid,
1365 (xfs_dqid_t) ip->i_d.di_gid,
1366 &ud, &gd);
1367 if (XFS_IS_UQUOTA_ON(mp)) {
1368 ASSERT(ud);
1369 xfs_qm_internalqcheck_dqadjust(ip, ud);
1370 }
1371 if (XFS_IS_GQUOTA_ON(mp)) {
1372 ASSERT(gd);
1373 xfs_qm_internalqcheck_dqadjust(ip, gd);
1374 }
1375 xfs_iput(ip, lock_flags);
1376 *res = BULKSTAT_RV_DIDONE;
1377 return (0);
1378}
1379
1380
1381/* PRIVATE, debugging */
1382int
1383xfs_qm_internalqcheck(
1384 xfs_mount_t *mp)
1385{
1386 xfs_ino_t lastino;
1387 int done, count;
1388 int i;
1389 xfs_dqtest_t *d, *e;
1390 xfs_dqhash_t *h1;
1391 int error;
1392
1393 lastino = 0;
1394 qmtest_hashmask = 32;
1395 count = 5;
1396 done = 0;
1397 qmtest_nfails = 0;
1398
1399 if (! XFS_IS_QUOTA_ON(mp))
1400 return XFS_ERROR(ESRCH);
1401
1402 xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC);
1403 XFS_bflush(mp->m_ddev_targp);
1404 xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC);
1405 XFS_bflush(mp->m_ddev_targp);
1406
1407 mutex_lock(&qcheck_lock, PINOD);
1408 /* There should be absolutely no quota activity while this
1409 is going on. */
1410 qmtest_udqtab = kmem_zalloc(qmtest_hashmask *
1411 sizeof(xfs_dqhash_t), KM_SLEEP);
1412 qmtest_gdqtab = kmem_zalloc(qmtest_hashmask *
1413 sizeof(xfs_dqhash_t), KM_SLEEP);
1414 do {
1415 /*
1416 * Iterate thru all the inodes in the file system,
1417 * adjusting the corresponding dquot counters
1418 */
1419 if ((error = xfs_bulkstat(mp, &lastino, &count,
1420 xfs_qm_internalqcheck_adjust, NULL,
1421 0, NULL, BULKSTAT_FG_IGET, &done))) {
1422 break;
1423 }
1424 } while (! done);
1425 if (error) {
1426 cmn_err(CE_DEBUG, "Bulkstat returned error 0x%x", error);
1427 }
1428 cmn_err(CE_DEBUG, "Checking results against system dquots");
1429 for (i = 0; i < qmtest_hashmask; i++) {
1430 h1 = &qmtest_udqtab[i];
1431 for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) {
1432 xfs_dqtest_cmp(d);
1433 e = (xfs_dqtest_t *) d->HL_NEXT;
1434 kmem_free(d, sizeof(xfs_dqtest_t));
1435 d = e;
1436 }
1437 h1 = &qmtest_gdqtab[i];
1438 for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) {
1439 xfs_dqtest_cmp(d);
1440 e = (xfs_dqtest_t *) d->HL_NEXT;
1441 kmem_free(d, sizeof(xfs_dqtest_t));
1442 d = e;
1443 }
1444 }
1445
1446 if (qmtest_nfails) {
1447 cmn_err(CE_DEBUG, "******** quotacheck failed ********");
1448 cmn_err(CE_DEBUG, "failures = %d", qmtest_nfails);
1449 } else {
1450 cmn_err(CE_DEBUG, "******** quotacheck successful! ********");
1451 }
1452 kmem_free(qmtest_udqtab, qmtest_hashmask * sizeof(xfs_dqhash_t));
1453 kmem_free(qmtest_gdqtab, qmtest_hashmask * sizeof(xfs_dqhash_t));
1454 mutex_unlock(&qcheck_lock);
1455 return (qmtest_nfails);
1456}
1457
1458#endif /* DEBUG */
diff --git a/fs/xfs/quota/xfs_quota_priv.h b/fs/xfs/quota/xfs_quota_priv.h
new file mode 100644
index 000000000000..414b6004af21
--- /dev/null
+++ b/fs/xfs/quota/xfs_quota_priv.h
@@ -0,0 +1,192 @@
1/*
2 * Copyright (c) 2000-2003 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#ifndef __XFS_QUOTA_PRIV_H__
33#define __XFS_QUOTA_PRIV_H__
34
35/*
36 * Number of bmaps that we ask from bmapi when doing a quotacheck.
37 * We make this restriction to keep the memory usage to a minimum.
38 */
39#define XFS_DQITER_MAP_SIZE 10
40
41/* Number of dquots that fit in to a dquot block */
42#define XFS_QM_DQPERBLK(mp) ((mp)->m_quotainfo->qi_dqperchunk)
43
44#define XFS_ISLOCKED_INODE(ip) (ismrlocked(&(ip)->i_lock, \
45 MR_UPDATE | MR_ACCESS) != 0)
46#define XFS_ISLOCKED_INODE_EXCL(ip) (ismrlocked(&(ip)->i_lock, \
47 MR_UPDATE) != 0)
48
49#define XFS_DQ_IS_ADDEDTO_TRX(t, d) ((d)->q_transp == (t))
50
51#define XFS_QI_MPLRECLAIMS(mp) ((mp)->m_quotainfo->qi_dqreclaims)
52#define XFS_QI_UQIP(mp) ((mp)->m_quotainfo->qi_uquotaip)
53#define XFS_QI_GQIP(mp) ((mp)->m_quotainfo->qi_gquotaip)
54#define XFS_QI_DQCHUNKLEN(mp) ((mp)->m_quotainfo->qi_dqchunklen)
55#define XFS_QI_BTIMELIMIT(mp) ((mp)->m_quotainfo->qi_btimelimit)
56#define XFS_QI_RTBTIMELIMIT(mp) ((mp)->m_quotainfo->qi_rtbtimelimit)
57#define XFS_QI_ITIMELIMIT(mp) ((mp)->m_quotainfo->qi_itimelimit)
58#define XFS_QI_BWARNLIMIT(mp) ((mp)->m_quotainfo->qi_bwarnlimit)
59#define XFS_QI_IWARNLIMIT(mp) ((mp)->m_quotainfo->qi_iwarnlimit)
60#define XFS_QI_QOFFLOCK(mp) ((mp)->m_quotainfo->qi_quotaofflock)
61
62#define XFS_QI_MPL_LIST(mp) ((mp)->m_quotainfo->qi_dqlist)
63#define XFS_QI_MPLLOCK(mp) ((mp)->m_quotainfo->qi_dqlist.qh_lock)
64#define XFS_QI_MPLNEXT(mp) ((mp)->m_quotainfo->qi_dqlist.qh_next)
65#define XFS_QI_MPLNDQUOTS(mp) ((mp)->m_quotainfo->qi_dqlist.qh_nelems)
66
67#define XQMLCK(h) (mutex_lock(&((h)->qh_lock), PINOD))
68#define XQMUNLCK(h) (mutex_unlock(&((h)->qh_lock)))
69#ifdef DEBUG
70struct xfs_dqhash;
71static inline int XQMISLCKD(struct xfs_dqhash *h)
72{
73 if (mutex_trylock(&h->qh_lock)) {
74 mutex_unlock(&h->qh_lock);
75 return 0;
76 }
77 return 1;
78}
79#endif
80
81#define XFS_DQ_HASH_LOCK(h) XQMLCK(h)
82#define XFS_DQ_HASH_UNLOCK(h) XQMUNLCK(h)
83#define XFS_DQ_IS_HASH_LOCKED(h) XQMISLCKD(h)
84
85#define xfs_qm_mplist_lock(mp) XQMLCK(&(XFS_QI_MPL_LIST(mp)))
86#define xfs_qm_mplist_unlock(mp) XQMUNLCK(&(XFS_QI_MPL_LIST(mp)))
87#define XFS_QM_IS_MPLIST_LOCKED(mp) XQMISLCKD(&(XFS_QI_MPL_LIST(mp)))
88
89#define xfs_qm_freelist_lock(qm) XQMLCK(&((qm)->qm_dqfreelist))
90#define xfs_qm_freelist_unlock(qm) XQMUNLCK(&((qm)->qm_dqfreelist))
91#define XFS_QM_IS_FREELIST_LOCKED(qm) XQMISLCKD(&((qm)->qm_dqfreelist))
92
93/*
94 * Hash into a bucket in the dquot hash table, based on <mp, id>.
95 */
96#define XFS_DQ_HASHVAL(mp, id) (((__psunsigned_t)(mp) + \
97 (__psunsigned_t)(id)) & \
98 (xfs_Gqm->qm_dqhashmask - 1))
99#define XFS_DQ_HASH(mp, id, type) (type == XFS_DQ_USER ? \
100 (xfs_Gqm->qm_usr_dqhtable + \
101 XFS_DQ_HASHVAL(mp, id)) : \
102 (xfs_Gqm->qm_grp_dqhtable + \
103 XFS_DQ_HASHVAL(mp, id)))
104#define XFS_IS_DQTYPE_ON(mp, type) (type == XFS_DQ_USER ? \
105 XFS_IS_UQUOTA_ON(mp):XFS_IS_GQUOTA_ON(mp))
106#define XFS_IS_DQUOT_UNINITIALIZED(dqp) ( \
107 !dqp->q_core.d_blk_hardlimit && \
108 !dqp->q_core.d_blk_softlimit && \
109 !dqp->q_core.d_rtb_hardlimit && \
110 !dqp->q_core.d_rtb_softlimit && \
111 !dqp->q_core.d_ino_hardlimit && \
112 !dqp->q_core.d_ino_softlimit && \
113 !dqp->q_core.d_bcount && \
114 !dqp->q_core.d_rtbcount && \
115 !dqp->q_core.d_icount)
116
117#define HL_PREVP dq_hashlist.ql_prevp
118#define HL_NEXT dq_hashlist.ql_next
119#define MPL_PREVP dq_mplist.ql_prevp
120#define MPL_NEXT dq_mplist.ql_next
121
122
123#define _LIST_REMOVE(h, dqp, PVP, NXT) \
124 { \
125 xfs_dquot_t *d; \
126 if (((d) = (dqp)->NXT)) \
127 (d)->PVP = (dqp)->PVP; \
128 *((dqp)->PVP) = d; \
129 (dqp)->NXT = NULL; \
130 (dqp)->PVP = NULL; \
131 (h)->qh_version++; \
132 (h)->qh_nelems--; \
133 }
134
135#define _LIST_INSERT(h, dqp, PVP, NXT) \
136 { \
137 xfs_dquot_t *d; \
138 if (((d) = (h)->qh_next)) \
139 (d)->PVP = &((dqp)->NXT); \
140 (dqp)->NXT = d; \
141 (dqp)->PVP = &((h)->qh_next); \
142 (h)->qh_next = dqp; \
143 (h)->qh_version++; \
144 (h)->qh_nelems++; \
145 }
146
147#define FOREACH_DQUOT_IN_MP(dqp, mp) \
148 for ((dqp) = XFS_QI_MPLNEXT(mp); (dqp) != NULL; (dqp) = (dqp)->MPL_NEXT)
149
150#define FOREACH_DQUOT_IN_FREELIST(dqp, qlist) \
151for ((dqp) = (qlist)->qh_next; (dqp) != (xfs_dquot_t *)(qlist); \
152 (dqp) = (dqp)->dq_flnext)
153
154#define XQM_HASHLIST_INSERT(h, dqp) \
155 _LIST_INSERT(h, dqp, HL_PREVP, HL_NEXT)
156
157#define XQM_FREELIST_INSERT(h, dqp) \
158 xfs_qm_freelist_append(h, dqp)
159
160#define XQM_MPLIST_INSERT(h, dqp) \
161 _LIST_INSERT(h, dqp, MPL_PREVP, MPL_NEXT)
162
163#define XQM_HASHLIST_REMOVE(h, dqp) \
164 _LIST_REMOVE(h, dqp, HL_PREVP, HL_NEXT)
165#define XQM_FREELIST_REMOVE(dqp) \
166 xfs_qm_freelist_unlink(dqp)
167#define XQM_MPLIST_REMOVE(h, dqp) \
168 { _LIST_REMOVE(h, dqp, MPL_PREVP, MPL_NEXT); \
169 XFS_QI_MPLRECLAIMS((dqp)->q_mount)++; }
170
171#define XFS_DQ_IS_LOGITEM_INITD(dqp) ((dqp)->q_logitem.qli_dquot == (dqp))
172
173#define XFS_QM_DQP_TO_DQACCT(tp, dqp) (XFS_QM_ISUDQ(dqp) ? \
174 (tp)->t_dqinfo->dqa_usrdquots : \
175 (tp)->t_dqinfo->dqa_grpdquots)
176#define XFS_IS_SUSER_DQUOT(dqp) \
177 (!((dqp)->q_core.d_id))
178
179#define XFS_PURGE_INODE(ip) \
180 { \
181 vmap_t dqvmap; \
182 vnode_t *dqvp; \
183 dqvp = XFS_ITOV(ip); \
184 VMAP(dqvp, dqvmap); \
185 VN_RELE(dqvp); \
186 }
187
188#define DQFLAGTO_TYPESTR(d) (((d)->dq_flags & XFS_DQ_USER) ? "USR" : \
189 (((d)->dq_flags & XFS_DQ_GROUP) ? "GRP" : "???"))
190#define DQFLAGTO_DIRTYSTR(d) (XFS_DQ_IS_DIRTY(d) ? "DIRTY" : "NOTDIRTY")
191
192#endif /* __XFS_QUOTA_PRIV_H__ */
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};