]>
git.saurik.com Git - apple/xnu.git/blob - bsd/vfs/vfs_quota.c
2 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 * Copyright (c) 1982, 1986, 1990, 1993, 1995
25 * The Regents of the University of California. All rights reserved.
27 * This code is derived from software contributed to Berkeley by
28 * Robert Elz at The University of Melbourne.
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in the
37 * documentation and/or other materials provided with the distribution.
38 * 3. All advertising materials mentioning features or use of this software
39 * must display the following acknowledgement:
40 * This product includes software developed by the University of
41 * California, Berkeley and its contributors.
42 * 4. Neither the name of the University nor the names of its contributors
43 * may be used to endorse or promote products derived from this software
44 * without specific prior written permission.
46 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * derived from @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95
62 #include <sys/param.h>
63 #include <sys/kernel.h>
64 #include <sys/systm.h>
65 #include <sys/malloc.h>
66 #include <sys/file_internal.h>
67 #include <sys/proc_internal.h>
68 #include <sys/vnode_internal.h>
69 #include <sys/mount_internal.h>
70 #include <sys/quota.h>
71 #include <sys/uio_internal.h>
74 /* vars for quota file lock */
75 lck_grp_t
* qf_lck_grp
;
76 lck_grp_attr_t
* qf_lck_grp_attr
;
77 lck_attr_t
* qf_lck_attr
;
79 /* vars for quota list lock */
80 lck_grp_t
* quota_list_lck_grp
;
81 lck_grp_attr_t
* quota_list_lck_grp_attr
;
82 lck_attr_t
* quota_list_lck_attr
;
83 lck_mtx_t
* quota_list_mtx_lock
;
85 /* Routines to lock and unlock the quota global data */
86 static void dq_list_lock(void);
87 static void dq_list_unlock(void);
89 static void dq_lock_internal(struct dquot
*dq
);
90 static void dq_unlock_internal(struct dquot
*dq
);
92 static u_int32_t quotamagic
[MAXQUOTAS
] = INITQMAGICS
;
96 * Code pertaining to management of the in-core dquot data structures.
98 #define DQHASH(dqvp, id) \
99 (&dqhashtbl[((((int)(dqvp)) >> 8) + id) & dqhash])
100 LIST_HEAD(dqhash
, dquot
) *dqhashtbl
;
103 #define DQUOTINC 5 /* minimum free dquots desired */
104 long numdquot
, desireddquot
= DQUOTINC
;
109 TAILQ_HEAD(dqfreelist
, dquot
) dqfreelist
;
111 * Dquot dirty orphans list
113 TAILQ_HEAD(dqdirtylist
, dquot
) dqdirtylist
;
116 static int dqlookup(struct quotafile
*, u_long
, struct dqblk
*, u_int32_t
*);
117 static int dqsync_locked(struct dquot
*dq
);
119 static void qf_lock(struct quotafile
*);
120 static void qf_unlock(struct quotafile
*);
121 static int qf_ref(struct quotafile
*);
122 static void qf_rele(struct quotafile
*);
126 * Initialize the quota system.
132 dqhashtbl
= hashinit(desiredvnodes
, M_DQUOT
, &dqhash
);
133 TAILQ_INIT(&dqfreelist
);
134 TAILQ_INIT(&dqdirtylist
);
137 * Allocate quota list lock group attribute and group
139 quota_list_lck_grp_attr
= lck_grp_attr_alloc_init();
140 lck_grp_attr_setstat(quota_list_lck_grp_attr
);
141 quota_list_lck_grp
= lck_grp_alloc_init("quota list", quota_list_lck_grp_attr
);
144 * Allocate qouta list lock attribute
146 quota_list_lck_attr
= lck_attr_alloc_init();
147 //lck_attr_setdebug(quota_list_lck_attr);
150 * Allocate quota list lock
152 quota_list_mtx_lock
= lck_mtx_alloc_init(quota_list_lck_grp
, quota_list_lck_attr
);
156 * allocate quota file lock group attribute and group
158 qf_lck_grp_attr
= lck_grp_attr_alloc_init();
159 lck_grp_attr_setstat(qf_lck_grp_attr
);
160 qf_lck_grp
= lck_grp_alloc_init("quota file", qf_lck_grp_attr
);
163 * Allocate quota file lock attribute
165 qf_lck_attr
= lck_attr_alloc_init();
166 //lck_attr_setdebug(qf_lck_attr);
174 lck_mtx_lock(quota_list_mtx_lock
);
180 lck_mtx_unlock(quota_list_mtx_lock
);
185 * must be called with the quota_list_lock held
188 dq_lock_internal(struct dquot
*dq
)
190 while (dq
->dq_lflags
& DQ_LLOCK
) {
191 dq
->dq_lflags
|= DQ_LWANT
;
192 msleep(&dq
->dq_lflags
, quota_list_mtx_lock
, PVFS
, "dq_lock_internal", 0);
194 dq
->dq_lflags
|= DQ_LLOCK
;
198 * must be called with the quota_list_lock held
201 dq_unlock_internal(struct dquot
*dq
)
203 int wanted
= dq
->dq_lflags
& DQ_LWANT
;
205 dq
->dq_lflags
&= ~(DQ_LLOCK
| DQ_LWANT
);
208 wakeup(&dq
->dq_lflags
);
212 dqlock(struct dquot
*dq
) {
214 lck_mtx_lock(quota_list_mtx_lock
);
216 dq_lock_internal(dq
);
218 lck_mtx_unlock(quota_list_mtx_lock
);
222 dqunlock(struct dquot
*dq
) {
224 lck_mtx_lock(quota_list_mtx_lock
);
226 dq_unlock_internal(dq
);
228 lck_mtx_unlock(quota_list_mtx_lock
);
234 qf_get(struct quotafile
*qfp
, int type
)
243 while ( (qfp
->qf_qflags
& (QTF_OPENING
| QTF_CLOSING
)) ) {
244 if ( (qfp
->qf_qflags
& QTF_OPENING
) ) {
248 if ( (qfp
->qf_qflags
& QTF_CLOSING
) ) {
249 qfp
->qf_qflags
|= QTF_WANTED
;
250 msleep(&qfp
->qf_qflags
, quota_list_mtx_lock
, PVFS
, "qf_get", 0);
253 if (qfp
->qf_vp
!= NULLVP
)
256 qfp
->qf_qflags
|= QTF_OPENING
;
260 if ( (qfp
->qf_qflags
& QTF_CLOSING
) ) {
264 qfp
->qf_qflags
|= QTF_CLOSING
;
266 while ( (qfp
->qf_qflags
& QTF_OPENING
) || qfp
->qf_refcnt
) {
267 qfp
->qf_qflags
|= QTF_WANTED
;
268 msleep(&qfp
->qf_qflags
, quota_list_mtx_lock
, PVFS
, "qf_get", 0);
270 if (qfp
->qf_vp
== NULLVP
) {
271 qfp
->qf_qflags
&= ~QTF_CLOSING
;
282 qf_put(struct quotafile
*qfp
, int type
)
291 qfp
->qf_qflags
&= ~type
;
294 if ( (qfp
->qf_qflags
& QTF_WANTED
) ) {
295 qfp
->qf_qflags
&= ~QTF_WANTED
;
296 wakeup(&qfp
->qf_qflags
);
303 qf_lock(struct quotafile
*qfp
)
305 lck_mtx_lock(&qfp
->qf_lock
);
309 qf_unlock(struct quotafile
*qfp
)
311 lck_mtx_unlock(&qfp
->qf_lock
);
316 * take a reference on the quota file while we're
317 * in dqget... this will prevent a quota_off from
318 * occurring while we're potentially playing with
319 * the quota file... the quota_off will stall until
320 * all the current references 'die'... once we start
321 * into quoto_off, all new references will be rejected
322 * we also don't want any dqgets being processed while
323 * we're in the middle of the quota_on... once we've
324 * actually got the quota file open and the associated
325 * struct quotafile inited, we can let them come through
327 * quota list lock must be held on entry
330 qf_ref(struct quotafile
*qfp
)
334 if ( (qfp
->qf_qflags
& (QTF_OPENING
| QTF_CLOSING
)) || (qfp
->qf_vp
== NULLVP
) )
343 * drop our reference and wakeup any waiters if
344 * we were the last one holding a ref
346 * quota list lock must be held on entry
349 qf_rele(struct quotafile
*qfp
)
353 if ( (qfp
->qf_qflags
& QTF_WANTED
) && qfp
->qf_refcnt
== 0) {
354 qfp
->qf_qflags
&= ~QTF_WANTED
;
355 wakeup(&qfp
->qf_qflags
);
361 dqfileinit(struct quotafile
*qfp
)
366 lck_mtx_init(&qfp
->qf_lock
, qf_lck_grp
, qf_lck_attr
);
371 * Initialize a quota file
373 * must be called with the quota file lock held
376 dqfileopen(qfp
, type
)
377 struct quotafile
*qfp
;
380 struct dqfilehdr header
;
381 struct vfs_context context
;
385 char uio_buf
[ UIO_SIZEOF(1) ];
387 context
.vc_proc
= current_proc();
388 context
.vc_ucred
= qfp
->qf_cred
;
390 /* Obtain the file size */
391 if ((error
= vnode_size(qfp
->qf_vp
, &file_size
, &context
)) != 0)
394 /* Read the file header */
395 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
396 &uio_buf
[0], sizeof(uio_buf
));
397 uio_addiov(auio
, CAST_USER_ADDR_T(&header
), sizeof (header
));
398 error
= VNOP_READ(qfp
->qf_vp
, auio
, 0, &context
);
401 else if (uio_resid(auio
)) {
405 /* Sanity check the quota file header. */
406 if ((header
.dqh_magic
!= quotamagic
[type
]) ||
407 (header
.dqh_version
> QF_VERSION
) ||
408 (!powerof2(header
.dqh_maxentries
)) ||
409 (header
.dqh_maxentries
> (file_size
/ sizeof(struct dqblk
)))) {
413 /* Set up the time limits for this quota. */
414 if (header
.dqh_btime
> 0)
415 qfp
->qf_btime
= header
.dqh_btime
;
417 qfp
->qf_btime
= MAX_DQ_TIME
;
418 if (header
.dqh_itime
> 0)
419 qfp
->qf_itime
= header
.dqh_itime
;
421 qfp
->qf_itime
= MAX_IQ_TIME
;
423 /* Calculate the hash table constants. */
424 qfp
->qf_maxentries
= header
.dqh_maxentries
;
425 qfp
->qf_entrycnt
= header
.dqh_entrycnt
;
426 qfp
->qf_shift
= dqhashshift(header
.dqh_maxentries
);
432 * Close down a quota file
435 dqfileclose(struct quotafile
*qfp
, __unused
int type
)
437 struct dqfilehdr header
;
438 struct vfs_context context
;
440 char uio_buf
[ UIO_SIZEOF(1) ];
442 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
443 &uio_buf
[0], sizeof(uio_buf
));
444 uio_addiov(auio
, CAST_USER_ADDR_T(&header
), sizeof (header
));
446 context
.vc_proc
= current_proc();
447 context
.vc_ucred
= qfp
->qf_cred
;
449 if (VNOP_READ(qfp
->qf_vp
, auio
, 0, &context
) == 0) {
450 header
.dqh_entrycnt
= qfp
->qf_entrycnt
;
451 uio_reset(auio
, 0, UIO_SYSSPACE
, UIO_WRITE
);
452 uio_addiov(auio
, CAST_USER_ADDR_T(&header
), sizeof (header
));
453 (void) VNOP_WRITE(qfp
->qf_vp
, auio
, 0, &context
);
459 * Obtain a dquot structure for the specified identifier and quota file
460 * reading the information from the file if necessary.
463 dqget(id
, qfp
, type
, dqp
)
465 struct quotafile
*qfp
;
470 struct dquot
*ndq
= NULL
;
471 struct dquot
*fdq
= NULL
;
476 if ( id
== 0 || qfp
->qf_vp
== NULLVP
) {
482 if ( (qf_ref(qfp
)) ) {
488 if ( (dqvp
= qfp
->qf_vp
) == NULLVP
) {
495 dqh
= DQHASH(dqvp
, id
);
499 * Check the cache first.
501 for (dq
= dqh
->lh_first
; dq
; dq
= dq
->dq_hash
.le_next
) {
502 if (dq
->dq_id
!= id
||
503 dq
->dq_qfile
->qf_vp
!= dqvp
)
506 dq_lock_internal(dq
);
508 * dq_lock_internal may drop the quota_list_lock to msleep, so
509 * we need to re-evaluate the identity of this dq
511 if (dq
->dq_id
!= id
|| dq
->dq_qfile
== NULL
||
512 dq
->dq_qfile
->qf_vp
!= dqvp
) {
513 dq_unlock_internal(dq
);
517 * Cache hit with no references. Take
518 * the structure off the free list.
520 if (dq
->dq_cnt
++ == 0) {
521 if (dq
->dq_flags
& DQ_MOD
)
522 TAILQ_REMOVE(&dqdirtylist
, dq
, dq_freelist
);
524 TAILQ_REMOVE(&dqfreelist
, dq
, dq_freelist
);
526 dq_unlock_internal(dq
);
530 * we grabbed this from the free list in the first pass
531 * but we found the dq we were looking for in
532 * the cache the 2nd time through
533 * so stick it back on the free list and return the cached entry
535 TAILQ_INSERT_HEAD(&dqfreelist
, fdq
, dq_freelist
);
542 * we allocated this in the first pass
543 * but we found the dq we were looking for in
544 * the cache the 2nd time through so free it
553 * Not in cache, allocate a new one.
555 if (TAILQ_EMPTY(&dqfreelist
) &&
556 numdquot
< MAXQUOTAS
* desiredvnodes
)
557 desireddquot
+= DQUOTINC
;
561 * we captured this from the free list
562 * in the first pass through, so go
567 } else if (numdquot
< desireddquot
) {
570 * drop the quota list lock since MALLOC may block
574 ndq
= (struct dquot
*)_MALLOC(sizeof *dq
, M_DQUOT
, M_WAITOK
);
575 bzero((char *)ndq
, sizeof *dq
);
579 * need to look for the entry again in the cache
580 * since we dropped the quota list lock and
581 * someone else may have beaten us to creating it
586 * we allocated this in the first pass through
587 * and we're still under out target, so go
595 if (TAILQ_EMPTY(&dqfreelist
)) {
601 * we allocated this in the first pass through
602 * but we're now at the limit of our cache size
611 dq
= TAILQ_FIRST(&dqfreelist
);
613 dq_lock_internal(dq
);
615 if (dq
->dq_cnt
|| (dq
->dq_flags
& DQ_MOD
)) {
617 * we lost the race while we weren't holding
618 * the quota list lock... dq_lock_internal
619 * will drop it to msleep... this dq has been
620 * reclaimed... go find another
622 dq_unlock_internal(dq
);
625 * need to look for the entry again in the cache
626 * since we dropped the quota list lock and
627 * someone else may have beaten us to creating it
631 TAILQ_REMOVE(&dqfreelist
, dq
, dq_freelist
);
633 if (dq
->dq_qfile
!= NULL
) {
634 LIST_REMOVE(dq
, dq_hash
);
638 dq_unlock_internal(dq
);
641 * because we may have dropped the quota list lock
642 * in the call to dq_lock_internal, we need to
643 * relookup in the hash in case someone else
644 * caused a dq with this identity to be created...
645 * if we don't find it, we'll use this one
651 * we've either freshly allocated a dq
652 * or we've atomically pulled it out of
653 * the hash and freelists... no one else
654 * can have a reference, which means no
655 * one else can be trying to use this dq
657 dq_lock_internal(dq
);
660 * Initialize the contents of the dquot structure.
668 * once we insert it in the hash and
669 * drop the quota_list_lock, it can be
670 * 'found'... however, we're still holding
671 * the dq_lock which will keep us from doing
672 * anything with it until we've finished
675 LIST_INSERT_HEAD(dqh
, dq
, dq_hash
);
680 * we allocated this in the first pass through
681 * but we didn't need it, so free it after
682 * we've droped the quota list lock
687 error
= dqlookup(qfp
, id
, &dq
->dq_dqb
, &dq
->dq_index
);
690 * I/O error in reading quota file, release
691 * quota structure and reflect problem to caller.
698 LIST_REMOVE(dq
, dq_hash
);
700 dq_unlock_internal(dq
);
710 * Check for no limit to enforce.
711 * Initialize time values if necessary.
713 if (dq
->dq_isoftlimit
== 0 && dq
->dq_bsoftlimit
== 0 &&
714 dq
->dq_ihardlimit
== 0 && dq
->dq_bhardlimit
== 0)
715 dq
->dq_flags
|= DQ_FAKE
;
716 if (dq
->dq_id
!= 0) {
720 if (dq
->dq_btime
== 0)
721 dq
->dq_btime
= tv
.tv_sec
+ qfp
->qf_btime
;
722 if (dq
->dq_itime
== 0)
723 dq
->dq_itime
= tv
.tv_sec
+ qfp
->qf_itime
;
726 dq_unlock_internal(dq
);
735 * Lookup a dqblk structure for the specified identifier and
736 * quota file. If there is no entry for this identifier then
737 * one is inserted. The actual hash table index is returned.
740 dqlookup(qfp
, id
, dqb
, index
)
741 struct quotafile
*qfp
;
747 struct vfs_context context
;
752 char uio_buf
[ UIO_SIZEOF(1) ];
759 context
.vc_proc
= current_proc();
760 context
.vc_ucred
= qfp
->qf_cred
;
762 mask
= qfp
->qf_maxentries
- 1;
763 i
= dqhash1(id
, qfp
->qf_shift
, mask
);
764 skip
= dqhash2(id
, mask
);
766 for (last
= (i
+ (qfp
->qf_maxentries
-1) * skip
) & mask
;
768 i
= (i
+ skip
) & mask
) {
769 auio
= uio_createwithbuffer(1, dqoffset(i
), UIO_SYSSPACE
, UIO_READ
,
770 &uio_buf
[0], sizeof(uio_buf
));
771 uio_addiov(auio
, CAST_USER_ADDR_T(dqb
), sizeof (struct dqblk
));
772 error
= VNOP_READ(dqvp
, auio
, 0, &context
);
774 printf("dqlookup: error %d looking up id %d at index %d\n", error
, id
, i
);
776 } else if (uio_resid(auio
)) {
778 printf("dqlookup: error looking up id %d at index %d\n", id
, i
);
782 * An empty entry means there is no entry
783 * with that id. In this case a new dqb
784 * record will be inserted.
786 if (dqb
->dqb_id
== 0) {
787 bzero(dqb
, sizeof(struct dqblk
));
790 * Write back to reserve entry for this id
792 uio_reset(auio
, dqoffset(i
), UIO_SYSSPACE
, UIO_WRITE
);
793 uio_addiov(auio
, CAST_USER_ADDR_T(dqb
), sizeof (struct dqblk
));
794 error
= VNOP_WRITE(dqvp
, auio
, 0, &context
);
795 if (uio_resid(auio
) && error
== 0)
801 /* An id match means an entry was found. */
802 if (dqb
->dqb_id
== id
)
807 *index
= i
; /* remember index so we don't have to recompute it later */
814 * Release a reference to a dquot.
817 dqrele(struct dquot
*dq
)
824 if (dq
->dq_cnt
> 1) {
830 if (dq
->dq_flags
& DQ_MOD
)
831 (void) dqsync_locked(dq
);
835 TAILQ_INSERT_TAIL(&dqfreelist
, dq
, dq_freelist
);
836 dq_unlock_internal(dq
);
841 * Release a reference to a dquot but don't do any I/O.
844 dqreclaim(register struct dquot
*dq
)
851 dq_lock_internal(dq
);
853 if (--dq
->dq_cnt
> 0) {
854 dq_unlock_internal(dq
);
858 if (dq
->dq_flags
& DQ_MOD
)
859 TAILQ_INSERT_TAIL(&dqdirtylist
, dq
, dq_freelist
);
861 TAILQ_INSERT_TAIL(&dqfreelist
, dq
, dq_freelist
);
863 dq_unlock_internal(dq
);
868 * Update a quota file's orphaned disk quotas.
872 struct quotafile
*qfp
;
878 TAILQ_FOREACH(dq
, &dqdirtylist
, dq_freelist
) {
879 if (dq
->dq_qfile
!= qfp
)
882 dq_lock_internal(dq
);
884 if (dq
->dq_qfile
!= qfp
) {
886 * the identity of this dq changed while
887 * the quota_list_lock was dropped
888 * dq_lock_internal can drop it to msleep
890 dq_unlock_internal(dq
);
893 if ((dq
->dq_flags
& DQ_MOD
) == 0) {
895 * someone cleaned and removed this from
896 * the dq from the dirty list while the
897 * quota_list_lock was dropped
899 dq_unlock_internal(dq
);
903 panic("dqsync_orphans: dquot in use");
905 TAILQ_REMOVE(&dqdirtylist
, dq
, dq_freelist
);
909 * we're still holding the dqlock at this point
910 * with the reference count == 0
911 * we shouldn't be able
912 * to pick up another one since we hold dqlock
914 (void) dqsync_locked(dq
);
918 TAILQ_INSERT_TAIL(&dqfreelist
, dq
, dq_freelist
);
920 dq_unlock_internal(dq
);
927 dqsync(struct dquot
*dq
)
934 if ( (dq
->dq_flags
& DQ_MOD
) )
935 error
= dqsync_locked(dq
);
944 * Update the disk quota in the quota file.
947 dqsync_locked(struct dquot
*dq
)
949 struct proc
*p
= current_proc(); /* XXX */
950 struct vfs_context context
;
954 char uio_buf
[ UIO_SIZEOF(1) ];
956 if (dq
->dq_id
== 0) {
957 dq
->dq_flags
&= ~DQ_MOD
;
960 if (dq
->dq_qfile
== NULL
)
961 panic("dqsync: NULL dq_qfile");
962 if ((dqvp
= dq
->dq_qfile
->qf_vp
) == NULLVP
)
963 panic("dqsync: NULL qf_vp");
965 auio
= uio_createwithbuffer(1, dqoffset(dq
->dq_index
), UIO_SYSSPACE
,
966 UIO_WRITE
, &uio_buf
[0], sizeof(uio_buf
));
967 uio_addiov(auio
, CAST_USER_ADDR_T(&dq
->dq_dqb
), sizeof (struct dqblk
));
970 context
.vc_ucred
= dq
->dq_qfile
->qf_cred
;
972 error
= VNOP_WRITE(dqvp
, auio
, 0, &context
);
973 if (uio_resid(auio
) && error
== 0)
975 dq
->dq_flags
&= ~DQ_MOD
;
981 * Flush all entries from the cache for a particular vnode.
985 register struct vnode
*vp
;
987 register struct dquot
*dq
, *nextdq
;
991 * Move all dquot's that used to refer to this quota
992 * file off their hash chains (they will eventually
993 * fall off the head of the free list and be re-used).
997 for (dqh
= &dqhashtbl
[dqhash
]; dqh
>= dqhashtbl
; dqh
--) {
998 for (dq
= dqh
->lh_first
; dq
; dq
= nextdq
) {
999 nextdq
= dq
->dq_hash
.le_next
;
1000 if (dq
->dq_qfile
->qf_vp
!= vp
)
1003 panic("dqflush: stray dquot");
1004 LIST_REMOVE(dq
, dq_hash
);
1005 dq
->dq_qfile
= NULL
;
1012 * LP64 support for munging dqblk structure.
1013 * XXX conversion of user_time_t to time_t loses precision; not an issue for
1014 * XXX us now, since we are only ever setting 32 bits worth of time into it.
1016 __private_extern__
void
1017 munge_dqblk(struct dqblk
*dqblkp
, struct user_dqblk
*user_dqblkp
, boolean_t to64
)
1020 /* munge kernel (32 bit) dqblk into user (64 bit) dqblk */
1021 bcopy((caddr_t
)dqblkp
, (caddr_t
)user_dqblkp
, offsetof(struct dqblk
, dqb_btime
));
1022 user_dqblkp
->dqb_id
= dqblkp
->dqb_id
;
1023 user_dqblkp
->dqb_itime
= dqblkp
->dqb_itime
;
1024 user_dqblkp
->dqb_btime
= dqblkp
->dqb_btime
;
1027 /* munge user (64 bit) dqblk into kernel (32 bit) dqblk */
1028 bcopy((caddr_t
)user_dqblkp
, (caddr_t
)dqblkp
, offsetof(struct dqblk
, dqb_btime
));
1029 dqblkp
->dqb_id
= user_dqblkp
->dqb_id
;
1030 dqblkp
->dqb_itime
= user_dqblkp
->dqb_itime
; /* XXX - lose precision */
1031 dqblkp
->dqb_btime
= user_dqblkp
->dqb_btime
; /* XXX - lose precision */