ufs_quota.c revision 1.84 1 /* $NetBSD: ufs_quota.c,v 1.84 2012/01/29 06:48:50 dholland Exp $ */
2
3 /*
4 * Copyright (c) 1982, 1986, 1990, 1993, 1995
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Robert Elz at The University of Melbourne.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95
35 */
36
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: ufs_quota.c,v 1.84 2012/01/29 06:48:50 dholland Exp $");
39
40 #if defined(_KERNEL_OPT)
41 #include "opt_quota.h"
42 #endif
43 #include <sys/param.h>
44 #include <sys/kernel.h>
45 #include <sys/systm.h>
46 #include <sys/namei.h>
47 #include <sys/file.h>
48 #include <sys/proc.h>
49 #include <sys/vnode.h>
50 #include <sys/mount.h>
51 #include <sys/kauth.h>
52
53 #include <sys/quotactl.h>
54 #include <ufs/ufs/quota.h>
55 #include <ufs/ufs/inode.h>
56 #include <ufs/ufs/ufsmount.h>
57 #include <ufs/ufs/ufs_extern.h>
58 #include <ufs/ufs/ufs_quota.h>
59 #include <quota/quotaprop.h>
60
61 kmutex_t dqlock;
62 kcondvar_t dqcv;
63
64 /*
65 * Code pertaining to management of the in-core dquot data structures.
66 */
67 #define DQHASH(dqvp, id) \
68 (((((long)(dqvp)) >> 8) + id) & dqhash)
69 static LIST_HEAD(dqhashhead, dquot) *dqhashtbl;
70 static u_long dqhash;
71 static pool_cache_t dquot_cache;
72
73
74 static int quota_handle_cmd_get_version(struct mount *, struct lwp *,
75 struct vfs_quotactl_args *args);
76 static int quota_handle_cmd_get(struct mount *, struct lwp *,
77 struct vfs_quotactl_args *args);
78 static int quota_handle_cmd_set(struct mount *, struct lwp *,
79 struct vfs_quotactl_args *args);
80 static int quota_handle_cmd_getall(struct mount *, struct lwp *,
81 struct vfs_quotactl_args *args);
82 static int quota_handle_cmd_clear(struct mount *, struct lwp *,
83 struct vfs_quotactl_args *args);
84 static int quota_handle_cmd_quotaon(struct mount *, struct lwp *,
85 struct vfs_quotactl_args *args);
86 static int quota_handle_cmd_quotaoff(struct mount *, struct lwp *,
87 struct vfs_quotactl_args *args);
88
89 /*
90 * Initialize the quota fields of an inode.
91 */
92 void
93 ufsquota_init(struct inode *ip)
94 {
95 int i;
96
97 for (i = 0; i < MAXQUOTAS; i++)
98 ip->i_dquot[i] = NODQUOT;
99 }
100
101 /*
102 * Release the quota fields from an inode.
103 */
104 void
105 ufsquota_free(struct inode *ip)
106 {
107 int i;
108
109 for (i = 0; i < MAXQUOTAS; i++) {
110 dqrele(ITOV(ip), ip->i_dquot[i]);
111 ip->i_dquot[i] = NODQUOT;
112 }
113 }
114
115 /*
116 * Update disk usage, and take corrective action.
117 */
118 int
119 chkdq(struct inode *ip, int64_t change, kauth_cred_t cred, int flags)
120 {
121 /* do not track snapshot usage, or we will deadlock */
122 if ((ip->i_flags & SF_SNAPSHOT) != 0)
123 return 0;
124
125 #ifdef QUOTA
126 if (ip->i_ump->um_flags & UFS_QUOTA)
127 return chkdq1(ip, change, cred, flags);
128 #endif
129 #ifdef QUOTA2
130 if (ip->i_ump->um_flags & UFS_QUOTA2)
131 return chkdq2(ip, change, cred, flags);
132 #endif
133 return 0;
134 }
135
136 /*
137 * Check the inode limit, applying corrective action.
138 */
139 int
140 chkiq(struct inode *ip, int32_t change, kauth_cred_t cred, int flags)
141 {
142 /* do not track snapshot usage, or we will deadlock */
143 if ((ip->i_flags & SF_SNAPSHOT) != 0)
144 return 0;
145 #ifdef QUOTA
146 if (ip->i_ump->um_flags & UFS_QUOTA)
147 return chkiq1(ip, change, cred, flags);
148 #endif
149 #ifdef QUOTA2
150 if (ip->i_ump->um_flags & UFS_QUOTA2)
151 return chkiq2(ip, change, cred, flags);
152 #endif
153 return 0;
154 }
155
156 int
157 quota_handle_cmd(struct mount *mp, struct lwp *l, int op,
158 struct vfs_quotactl_args *args)
159 {
160 int error = 0;
161
162 switch (op) {
163 case QUOTACTL_GETVERSION:
164 error = quota_handle_cmd_get_version(mp, l, args);
165 break;
166 case QUOTACTL_QUOTAON:
167 error = quota_handle_cmd_quotaon(mp, l, args);
168 break;
169 case QUOTACTL_QUOTAOFF:
170 error = quota_handle_cmd_quotaoff(mp, l, args);
171 break;
172 case QUOTACTL_GET:
173 error = quota_handle_cmd_get(mp, l, args);
174 break;
175 case QUOTACTL_SET:
176 error = quota_handle_cmd_set(mp, l, args);
177 break;
178 case QUOTACTL_GETALL:
179 error = quota_handle_cmd_getall(mp, l, args);
180 break;
181 case QUOTACTL_CLEAR:
182 error = quota_handle_cmd_clear(mp, l, args);
183 break;
184 default:
185 panic("Invalid quotactl operation %d\n", op);
186 }
187
188 return error;
189 }
190
191 static int
192 quota_handle_cmd_get_version(struct mount *mp, struct lwp *l,
193 struct vfs_quotactl_args *args)
194 {
195 struct ufsmount *ump = VFSTOUFS(mp);
196 int *version_ret;
197
198 KASSERT(args->qc_type == QCT_GETVERSION);
199 version_ret = args->u.getversion.qc_version_ret;
200
201 if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0)
202 return EOPNOTSUPP;
203
204 #ifdef QUOTA
205 if (ump->um_flags & UFS_QUOTA) {
206 *version_ret = 1;
207 } else
208 #endif
209 #ifdef QUOTA2
210 if (ump->um_flags & UFS_QUOTA2) {
211 *version_ret = 2;
212 } else
213 #endif
214 return EOPNOTSUPP;
215
216 return 0;
217 }
218
219 /* XXX shouldn't all this be in kauth ? */
220 static int
221 quota_get_auth(struct mount *mp, struct lwp *l, uid_t id) {
222 /* The user can always query about his own quota. */
223 if (id == kauth_cred_getuid(l->l_cred))
224 return 0;
225 return kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
226 KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, KAUTH_ARG(id), NULL);
227 }
228
229 static int
230 quota_handle_cmd_get(struct mount *mp, struct lwp *l,
231 struct vfs_quotactl_args *args)
232 {
233 struct ufsmount *ump = VFSTOUFS(mp);
234 int error;
235 const struct quotakey *qk;
236 struct quotaval *ret;
237
238 KASSERT(args->qc_type == QCT_GET);
239 qk = args->u.get.qc_key;
240 ret = args->u.get.qc_ret;
241
242 if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0)
243 return EOPNOTSUPP;
244
245 error = quota_get_auth(mp, l, qk->qk_id);
246 if (error != 0)
247 return error;
248 #ifdef QUOTA
249 if (ump->um_flags & UFS_QUOTA) {
250 error = quota1_handle_cmd_get(ump, qk, ret);
251 } else
252 #endif
253 #ifdef QUOTA2
254 if (ump->um_flags & UFS_QUOTA2) {
255 error = quota2_handle_cmd_get(ump, qk, ret);
256 } else
257 #endif
258 panic("quota_handle_cmd_get: no support ?");
259
260 if (error != 0)
261 return error;
262
263 return error;
264 }
265
266 static int
267 quota_handle_cmd_set(struct mount *mp, struct lwp *l,
268 struct vfs_quotactl_args *args)
269 {
270 struct ufsmount *ump = VFSTOUFS(mp);
271 const struct quotakey *qk;
272 const struct quotaval *qv;
273 id_t kauth_id;
274 int error;
275
276 KASSERT(args->qc_type == QCT_SET);
277 qk = args->u.set.qc_key;
278 qv = args->u.set.qc_val;
279
280 if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0)
281 return EOPNOTSUPP;
282
283 kauth_id = qk->qk_id;
284 if (kauth_id == QUOTA_DEFAULTID) {
285 kauth_id = 0;
286 }
287
288 /* avoid whitespace changes */
289 {
290 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
291 KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(kauth_id),
292 NULL);
293 if (error != 0)
294 goto err;
295 #ifdef QUOTA
296 if (ump->um_flags & UFS_QUOTA)
297 error = quota1_handle_cmd_set(ump, qk, qv);
298 else
299 #endif
300 #ifdef QUOTA2
301 if (ump->um_flags & UFS_QUOTA2) {
302 error = quota2_handle_cmd_set(ump, qk, qv);
303 } else
304 #endif
305 panic("quota_handle_cmd_get: no support ?");
306
307 if (error && error != ENOENT)
308 goto err;
309 }
310
311 return 0;
312 err:
313 return error;
314 }
315
316 static int
317 quota_handle_cmd_clear(struct mount *mp, struct lwp *l,
318 struct vfs_quotactl_args *args)
319 {
320 prop_array_t replies;
321 prop_object_iterator_t iter;
322 prop_dictionary_t data;
323 uint32_t id;
324 struct ufsmount *ump = VFSTOUFS(mp);
325 int error, defaultq = 0;
326 const char *idstr;
327 prop_dictionary_t cmddict;
328 int q2type;
329 prop_array_t datas;
330
331 KASSERT(args->qc_type == QCT_PROPLIB);
332 cmddict = args->u.proplib.qc_cmddict;
333 q2type = args->u.proplib.qc_q2type;
334 datas = args->u.proplib.qc_datas;
335
336 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
337 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
338
339 if ((ump->um_flags & UFS_QUOTA2) == 0)
340 return EOPNOTSUPP;
341
342 replies = prop_array_create();
343 if (replies == NULL)
344 return ENOMEM;
345
346 iter = prop_array_iterator(datas);
347 if (iter == NULL) {
348 prop_object_release(replies);
349 return ENOMEM;
350 }
351 while ((data = prop_object_iterator_next(iter)) != NULL) {
352 if (!prop_dictionary_get_uint32(data, "id", &id)) {
353 if (!prop_dictionary_get_cstring_nocopy(data, "id",
354 &idstr))
355 continue;
356 if (strcmp(idstr, "default"))
357 continue;
358 id = 0;
359 defaultq = 1;
360 } else {
361 defaultq = 0;
362 }
363 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
364 KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(id), NULL);
365 if (error != 0)
366 goto err;
367 #ifdef QUOTA2
368 if (ump->um_flags & UFS_QUOTA2) {
369 error = quota2_handle_cmd_clear(ump, q2type, id, defaultq,
370 data);
371 } else
372 #endif
373 panic("quota_handle_cmd_get: no support ?");
374
375 if (error && error != ENOENT)
376 goto err;
377 }
378 prop_object_iterator_release(iter);
379 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
380 error = ENOMEM;
381 } else {
382 error = 0;
383 }
384 return error;
385 err:
386 prop_object_iterator_release(iter);
387 prop_object_release(replies);
388 return error;
389 }
390
391 static int
392 quota_handle_cmd_getall(struct mount *mp, struct lwp *l,
393 struct vfs_quotactl_args *args)
394 {
395 prop_array_t replies;
396 struct ufsmount *ump = VFSTOUFS(mp);
397 int error;
398 prop_dictionary_t cmddict;
399 int q2type;
400 prop_array_t datas;
401
402 KASSERT(args->qc_type == QCT_PROPLIB);
403 cmddict = args->u.proplib.qc_cmddict;
404 q2type = args->u.proplib.qc_q2type;
405 datas = args->u.proplib.qc_datas;
406
407 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
408 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
409
410 if ((ump->um_flags & UFS_QUOTA2) == 0)
411 return EOPNOTSUPP;
412
413 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
414 KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL);
415 if (error)
416 return error;
417
418 replies = prop_array_create();
419 if (replies == NULL)
420 return ENOMEM;
421
422 #ifdef QUOTA2
423 if (ump->um_flags & UFS_QUOTA2) {
424 error = quota2_handle_cmd_getall(ump, q2type, replies);
425 } else
426 #endif
427 panic("quota_handle_cmd_getall: no support ?");
428 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
429 error = ENOMEM;
430 } else {
431 error = 0;
432 }
433 return error;
434 }
435
436 static int
437 quota_handle_cmd_quotaon(struct mount *mp, struct lwp *l,
438 struct vfs_quotactl_args *args)
439 {
440 prop_dictionary_t data;
441 struct ufsmount *ump = VFSTOUFS(mp);
442 int error;
443 const char *qfile;
444 prop_dictionary_t cmddict;
445 int q2type;
446 prop_array_t datas;
447
448 KASSERT(args->qc_type == QCT_PROPLIB);
449 cmddict = args->u.proplib.qc_cmddict;
450 q2type = args->u.proplib.qc_q2type;
451 datas = args->u.proplib.qc_datas;
452
453 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
454 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
455
456 if ((ump->um_flags & UFS_QUOTA2) != 0)
457 return EBUSY;
458
459 if (prop_array_count(datas) != 1)
460 return EINVAL;
461
462 data = prop_array_get(datas, 0);
463 if (data == NULL)
464 return ENOMEM;
465 if (!prop_dictionary_get_cstring_nocopy(data, "quotafile",
466 &qfile))
467 return EINVAL;
468
469 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
470 KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL);
471 if (error != 0) {
472 return error;
473 }
474 #ifdef QUOTA
475 error = quota1_handle_cmd_quotaon(l, ump, q2type, qfile);
476 #else
477 error = EOPNOTSUPP;
478 #endif
479
480 return error;
481 }
482
483 static int
484 quota_handle_cmd_quotaoff(struct mount *mp, struct lwp *l,
485 struct vfs_quotactl_args *args)
486 {
487 struct ufsmount *ump = VFSTOUFS(mp);
488 int error;
489 prop_dictionary_t cmddict;
490 int q2type;
491 prop_array_t datas;
492
493 KASSERT(args->qc_type == QCT_PROPLIB);
494 cmddict = args->u.proplib.qc_cmddict;
495 q2type = args->u.proplib.qc_q2type;
496 datas = args->u.proplib.qc_datas;
497
498 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
499 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
500
501 if ((ump->um_flags & UFS_QUOTA2) != 0)
502 return EOPNOTSUPP;
503
504 if (prop_array_count(datas) != 0)
505 return EINVAL;
506
507 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
508 KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL);
509 if (error != 0) {
510 return error;
511 }
512 #ifdef QUOTA
513 error = quota1_handle_cmd_quotaoff(l, ump, q2type);
514 #else
515 error = EOPNOTSUPP;
516 #endif
517
518 return error;
519 }
520
521 /*
522 * Initialize the quota system.
523 */
524 void
525 dqinit(void)
526 {
527
528 mutex_init(&dqlock, MUTEX_DEFAULT, IPL_NONE);
529 cv_init(&dqcv, "quota");
530 dqhashtbl = hashinit(desiredvnodes, HASH_LIST, true, &dqhash);
531 dquot_cache = pool_cache_init(sizeof(struct dquot), 0, 0, 0, "ufsdq",
532 NULL, IPL_NONE, NULL, NULL, NULL);
533 }
534
535 void
536 dqreinit(void)
537 {
538 struct dquot *dq;
539 struct dqhashhead *oldhash, *hash;
540 struct vnode *dqvp;
541 u_long oldmask, mask, hashval;
542 int i;
543
544 hash = hashinit(desiredvnodes, HASH_LIST, true, &mask);
545 mutex_enter(&dqlock);
546 oldhash = dqhashtbl;
547 oldmask = dqhash;
548 dqhashtbl = hash;
549 dqhash = mask;
550 for (i = 0; i <= oldmask; i++) {
551 while ((dq = LIST_FIRST(&oldhash[i])) != NULL) {
552 dqvp = dq->dq_ump->um_quotas[dq->dq_type];
553 LIST_REMOVE(dq, dq_hash);
554 hashval = DQHASH(dqvp, dq->dq_id);
555 LIST_INSERT_HEAD(&dqhashtbl[hashval], dq, dq_hash);
556 }
557 }
558 mutex_exit(&dqlock);
559 hashdone(oldhash, HASH_LIST, oldmask);
560 }
561
562 /*
563 * Free resources held by quota system.
564 */
565 void
566 dqdone(void)
567 {
568
569 pool_cache_destroy(dquot_cache);
570 hashdone(dqhashtbl, HASH_LIST, dqhash);
571 cv_destroy(&dqcv);
572 mutex_destroy(&dqlock);
573 }
574
575 /*
576 * Set up the quotas for an inode.
577 *
578 * This routine completely defines the semantics of quotas.
579 * If other criterion want to be used to establish quotas, the
580 * MAXQUOTAS value in quotas.h should be increased, and the
581 * additional dquots set up here.
582 */
583 int
584 getinoquota(struct inode *ip)
585 {
586 struct ufsmount *ump = ip->i_ump;
587 struct vnode *vp = ITOV(ip);
588 int i, error;
589 u_int32_t ino_ids[MAXQUOTAS];
590
591 /*
592 * To avoid deadlocks never update quotas for quota files
593 * on the same file system
594 */
595 for (i = 0; i < MAXQUOTAS; i++)
596 if (vp == ump->um_quotas[i])
597 return 0;
598
599 ino_ids[USRQUOTA] = ip->i_uid;
600 ino_ids[GRPQUOTA] = ip->i_gid;
601 for (i = 0; i < MAXQUOTAS; i++) {
602 /*
603 * If the file id changed the quota needs update.
604 */
605 if (ip->i_dquot[i] != NODQUOT &&
606 ip->i_dquot[i]->dq_id != ino_ids[i]) {
607 dqrele(ITOV(ip), ip->i_dquot[i]);
608 ip->i_dquot[i] = NODQUOT;
609 }
610 /*
611 * Set up the quota based on file id.
612 * ENODEV means that quotas are not enabled.
613 */
614 if (ip->i_dquot[i] == NODQUOT &&
615 (error = dqget(vp, ino_ids[i], ump, i, &ip->i_dquot[i])) &&
616 error != ENODEV)
617 return (error);
618 }
619 return 0;
620 }
621
622 /*
623 * Obtain a dquot structure for the specified identifier and quota file
624 * reading the information from the file if necessary.
625 */
626 int
627 dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type,
628 struct dquot **dqp)
629 {
630 struct dquot *dq, *ndq;
631 struct dqhashhead *dqh;
632 struct vnode *dqvp;
633 int error = 0; /* XXX gcc */
634
635 /* Lock to see an up to date value for QTF_CLOSING. */
636 mutex_enter(&dqlock);
637 if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) {
638 mutex_exit(&dqlock);
639 *dqp = NODQUOT;
640 return (ENODEV);
641 }
642 dqvp = ump->um_quotas[type];
643 #ifdef QUOTA
644 if (ump->um_flags & UFS_QUOTA) {
645 if (dqvp == NULLVP || (ump->umq1_qflags[type] & QTF_CLOSING)) {
646 mutex_exit(&dqlock);
647 *dqp = NODQUOT;
648 return (ENODEV);
649 }
650 }
651 #endif
652 #ifdef QUOTA2
653 if (ump->um_flags & UFS_QUOTA2) {
654 if (dqvp == NULLVP) {
655 mutex_exit(&dqlock);
656 *dqp = NODQUOT;
657 return (ENODEV);
658 }
659 }
660 #endif
661 KASSERT(dqvp != vp);
662 /*
663 * Check the cache first.
664 */
665 dqh = &dqhashtbl[DQHASH(dqvp, id)];
666 LIST_FOREACH(dq, dqh, dq_hash) {
667 if (dq->dq_id != id ||
668 dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
669 continue;
670 KASSERT(dq->dq_cnt > 0);
671 dqref(dq);
672 mutex_exit(&dqlock);
673 *dqp = dq;
674 return (0);
675 }
676 /*
677 * Not in cache, allocate a new one.
678 */
679 mutex_exit(&dqlock);
680 ndq = pool_cache_get(dquot_cache, PR_WAITOK);
681 /*
682 * Initialize the contents of the dquot structure.
683 */
684 memset((char *)ndq, 0, sizeof *ndq);
685 ndq->dq_flags = 0;
686 ndq->dq_id = id;
687 ndq->dq_ump = ump;
688 ndq->dq_type = type;
689 mutex_init(&ndq->dq_interlock, MUTEX_DEFAULT, IPL_NONE);
690 mutex_enter(&dqlock);
691 dqh = &dqhashtbl[DQHASH(dqvp, id)];
692 LIST_FOREACH(dq, dqh, dq_hash) {
693 if (dq->dq_id != id ||
694 dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
695 continue;
696 /*
697 * Another thread beat us allocating this dquot.
698 */
699 KASSERT(dq->dq_cnt > 0);
700 dqref(dq);
701 mutex_exit(&dqlock);
702 mutex_destroy(&ndq->dq_interlock);
703 pool_cache_put(dquot_cache, ndq);
704 *dqp = dq;
705 return 0;
706 }
707 dq = ndq;
708 LIST_INSERT_HEAD(dqh, dq, dq_hash);
709 dqref(dq);
710 mutex_enter(&dq->dq_interlock);
711 mutex_exit(&dqlock);
712 #ifdef QUOTA
713 if (ump->um_flags & UFS_QUOTA)
714 error = dq1get(dqvp, id, ump, type, dq);
715 #endif
716 #ifdef QUOTA2
717 if (ump->um_flags & UFS_QUOTA2)
718 error = dq2get(dqvp, id, ump, type, dq);
719 #endif
720 /*
721 * I/O error in reading quota file, release
722 * quota structure and reflect problem to caller.
723 */
724 if (error) {
725 mutex_enter(&dqlock);
726 LIST_REMOVE(dq, dq_hash);
727 mutex_exit(&dqlock);
728 mutex_exit(&dq->dq_interlock);
729 dqrele(vp, dq);
730 *dqp = NODQUOT;
731 return (error);
732 }
733 mutex_exit(&dq->dq_interlock);
734 *dqp = dq;
735 return (0);
736 }
737
738 /*
739 * Obtain a reference to a dquot.
740 */
741 void
742 dqref(struct dquot *dq)
743 {
744
745 KASSERT(mutex_owned(&dqlock));
746 dq->dq_cnt++;
747 KASSERT(dq->dq_cnt > 0);
748 }
749
750 /*
751 * Release a reference to a dquot.
752 */
753 void
754 dqrele(struct vnode *vp, struct dquot *dq)
755 {
756
757 if (dq == NODQUOT)
758 return;
759 mutex_enter(&dq->dq_interlock);
760 for (;;) {
761 mutex_enter(&dqlock);
762 if (dq->dq_cnt > 1) {
763 dq->dq_cnt--;
764 mutex_exit(&dqlock);
765 mutex_exit(&dq->dq_interlock);
766 return;
767 }
768 if ((dq->dq_flags & DQ_MOD) == 0)
769 break;
770 mutex_exit(&dqlock);
771 #ifdef QUOTA
772 if (dq->dq_ump->um_flags & UFS_QUOTA)
773 (void) dq1sync(vp, dq);
774 #endif
775 #ifdef QUOTA2
776 if (dq->dq_ump->um_flags & UFS_QUOTA2)
777 (void) dq2sync(vp, dq);
778 #endif
779 }
780 KASSERT(dq->dq_cnt == 1 && (dq->dq_flags & DQ_MOD) == 0);
781 LIST_REMOVE(dq, dq_hash);
782 mutex_exit(&dqlock);
783 mutex_exit(&dq->dq_interlock);
784 mutex_destroy(&dq->dq_interlock);
785 pool_cache_put(dquot_cache, dq);
786 }
787
788 int
789 qsync(struct mount *mp)
790 {
791 struct ufsmount *ump = VFSTOUFS(mp);
792 #ifdef QUOTA
793 if (ump->um_flags & UFS_QUOTA)
794 return q1sync(mp);
795 #endif
796 #ifdef QUOTA2
797 if (ump->um_flags & UFS_QUOTA2)
798 return q2sync(mp);
799 #endif
800 return 0;
801 }
802
803 #ifdef DIAGNOSTIC
804 /*
805 * Check the hash chains for stray dquot's.
806 */
807 void
808 dqflush(struct vnode *vp)
809 {
810 struct dquot *dq;
811 int i;
812
813 mutex_enter(&dqlock);
814 for (i = 0; i <= dqhash; i++)
815 LIST_FOREACH(dq, &dqhashtbl[i], dq_hash)
816 KASSERT(dq->dq_ump->um_quotas[dq->dq_type] != vp);
817 mutex_exit(&dqlock);
818 }
819 #endif
820