]>
git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfs_quota.c
2 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * Copyright (c) 1982, 1986, 1990, 1993, 1995
27 * The Regents of the University of California. All rights reserved.
29 * This code is derived from software contributed to Berkeley by
30 * Robert Elz at The University of Melbourne.
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * derived from @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95
64 #include <sys/param.h>
65 #include <sys/kernel.h>
66 #include <sys/systm.h>
67 #include <sys/mount.h>
68 #include <sys/namei.h>
69 #include <sys/malloc.h>
72 #include <sys/vnode.h>
73 #include <sys/quota.h>
76 #include <hfs/hfs_cnode.h>
77 #include <hfs/hfs_quota.h>
78 #include <hfs/hfs_mount.h>
81 * Quota name to error message mapping.
83 static char *quotatypes
[] = INITQFNAMES
;
86 * Set up the quotas for a cnode.
88 * This routine completely defines the semantics of quotas.
89 * If other criterion want to be used to establish quotas, the
90 * MAXQUOTAS value in quotas.h should be increased, and the
91 * additional dquots set up here.
95 register struct cnode
*cp
;
97 struct hfsmount
*hfsmp
;
101 vp
= cp
->c_vp
? cp
->c_vp
: cp
->c_rsrc_vp
;
102 hfsmp
= VFSTOHFS(vp
->v_mount
);
104 * Set up the user quota based on file uid.
105 * EINVAL means that quotas are not enabled.
107 if (cp
->c_dquot
[USRQUOTA
] == NODQUOT
&&
109 dqget(vp
, cp
->c_uid
, &hfsmp
->hfs_qfiles
[USRQUOTA
], USRQUOTA
, &cp
->c_dquot
[USRQUOTA
])) &&
113 * Set up the group quota based on file gid.
114 * EINVAL means that quotas are not enabled.
116 if (cp
->c_dquot
[GRPQUOTA
] == NODQUOT
&&
118 dqget(vp
, cp
->c_gid
, &hfsmp
->hfs_qfiles
[GRPQUOTA
], GRPQUOTA
, &cp
->c_dquot
[GRPQUOTA
])) &&
125 * Update disk usage, and take corrective action.
128 hfs_chkdq(cp
, change
, cred
, flags
)
129 register struct cnode
*cp
;
134 register struct dquot
*dq
;
141 if ((flags
& CHOWN
) == 0)
147 for (i
= 0; i
< MAXQUOTAS
; i
++) {
148 if ((dq
= cp
->c_dquot
[i
]) == NODQUOT
)
150 while (dq
->dq_flags
& DQ_LOCK
) {
151 dq
->dq_flags
|= DQ_WANT
;
152 sleep((caddr_t
)dq
, PINOD
+1);
154 ncurbytes
= dq
->dq_curbytes
+ change
;
156 dq
->dq_curbytes
= ncurbytes
;
159 dq
->dq_flags
&= ~DQ_BLKS
;
160 dq
->dq_flags
|= DQ_MOD
;
166 cred
= kernproc
->p_ucred
;
167 if ((cred
->cr_uid
!= 0) || (p
->p_flag
& P_FORCEQUOTA
)) {
168 for (i
= 0; i
< MAXQUOTAS
; i
++) {
169 if ((dq
= cp
->c_dquot
[i
]) == NODQUOT
)
171 error
= hfs_chkdqchg(cp
, change
, cred
, i
);
177 if ((flags
& FORCE
) || error
== 0) {
178 for (i
= 0; i
< MAXQUOTAS
; i
++) {
179 if ((dq
= cp
->c_dquot
[i
]) == NODQUOT
)
181 while (dq
->dq_flags
& DQ_LOCK
) {
182 dq
->dq_flags
|= DQ_WANT
;
183 sleep((caddr_t
)dq
, PINOD
+1);
185 dq
->dq_curbytes
+= change
;
186 dq
->dq_flags
|= DQ_MOD
;
193 * Check for a valid change to a users allocation.
194 * Issue an error message if appropriate.
197 hfs_chkdqchg(cp
, change
, cred
, type
)
203 register struct dquot
*dq
= cp
->c_dquot
[type
];
204 u_int64_t ncurbytes
= dq
->dq_curbytes
+ change
;
205 struct vnode
*vp
= cp
->c_vp
? cp
->c_vp
: cp
->c_rsrc_vp
;
208 * If user would exceed their hard limit, disallow space allocation.
210 if (ncurbytes
>= dq
->dq_bhardlimit
&& dq
->dq_bhardlimit
) {
211 if ((dq
->dq_flags
& DQ_BLKS
) == 0 &&
212 cp
->c_uid
== cred
->cr_uid
) {
214 printf("\n%s: write failed, %s disk limit reached\n",
215 vp
->v_mount
->mnt_stat
.f_mntonname
,
218 dq
->dq_flags
|= DQ_BLKS
;
223 * If user is over their soft limit for too long, disallow space
224 * allocation. Reset time limit as they cross their soft limit.
226 if (ncurbytes
>= dq
->dq_bsoftlimit
&& dq
->dq_bsoftlimit
) {
227 if (dq
->dq_curbytes
< dq
->dq_bsoftlimit
) {
228 dq
->dq_btime
= time
.tv_sec
+
229 VFSTOHFS(vp
->v_mount
)->hfs_qfiles
[type
].qf_btime
;
231 if (cp
->c_uid
== cred
->cr_uid
)
232 printf("\n%s: warning, %s %s\n",
233 vp
->v_mount
->mnt_stat
.f_mntonname
,
234 quotatypes
[type
], "disk quota exceeded");
238 if (time
.tv_sec
> dq
->dq_btime
) {
239 if ((dq
->dq_flags
& DQ_BLKS
) == 0 &&
240 cp
->c_uid
== cred
->cr_uid
) {
242 printf("\n%s: write failed, %s %s\n",
243 vp
->v_mount
->mnt_stat
.f_mntonname
,
245 "disk quota exceeded for too long");
247 dq
->dq_flags
|= DQ_BLKS
;
256 * Check the inode limit, applying corrective action.
259 hfs_chkiq(cp
, change
, cred
, flags
)
260 register struct cnode
*cp
;
265 register struct dquot
*dq
;
267 int ncurinodes
, error
=0;
271 if ((flags
& CHOWN
) == 0)
277 for (i
= 0; i
< MAXQUOTAS
; i
++) {
278 if ((dq
= cp
->c_dquot
[i
]) == NODQUOT
)
280 while (dq
->dq_flags
& DQ_LOCK
) {
281 dq
->dq_flags
|= DQ_WANT
;
282 sleep((caddr_t
)dq
, PINOD
+1);
284 ncurinodes
= dq
->dq_curinodes
+ change
;
286 dq
->dq_curinodes
= ncurinodes
;
288 dq
->dq_curinodes
= 0;
289 dq
->dq_flags
&= ~DQ_INODS
;
290 dq
->dq_flags
|= DQ_MOD
;
296 cred
= kernproc
->p_ucred
;
297 if ((cred
->cr_uid
!= 0) || (p
->p_flag
& P_FORCEQUOTA
)) {
298 for (i
= 0; i
< MAXQUOTAS
; i
++) {
299 if ((dq
= cp
->c_dquot
[i
]) == NODQUOT
)
301 error
= hfs_chkiqchg(cp
, change
, cred
, i
);
307 if ((flags
& FORCE
) || error
== 0) {
308 for (i
= 0; i
< MAXQUOTAS
; i
++) {
309 if ((dq
= cp
->c_dquot
[i
]) == NODQUOT
)
311 while (dq
->dq_flags
& DQ_LOCK
) {
312 dq
->dq_flags
|= DQ_WANT
;
313 sleep((caddr_t
)dq
, PINOD
+1);
315 dq
->dq_curinodes
+= change
;
316 dq
->dq_flags
|= DQ_MOD
;
323 * Check for a valid change to a users allocation.
324 * Issue an error message if appropriate.
327 hfs_chkiqchg(cp
, change
, cred
, type
)
333 register struct dquot
*dq
= cp
->c_dquot
[type
];
334 long ncurinodes
= dq
->dq_curinodes
+ change
;
335 struct vnode
*vp
= cp
->c_vp
? cp
->c_vp
: cp
->c_rsrc_vp
;
338 * If user would exceed their hard limit, disallow cnode allocation.
340 if (ncurinodes
>= dq
->dq_ihardlimit
&& dq
->dq_ihardlimit
) {
341 if ((dq
->dq_flags
& DQ_INODS
) == 0 &&
342 cp
->c_uid
== cred
->cr_uid
) {
344 printf("\n%s: write failed, %s cnode limit reached\n",
345 vp
->v_mount
->mnt_stat
.f_mntonname
,
348 dq
->dq_flags
|= DQ_INODS
;
353 * If user is over their soft limit for too long, disallow cnode
354 * allocation. Reset time limit as they cross their soft limit.
356 if (ncurinodes
>= dq
->dq_isoftlimit
&& dq
->dq_isoftlimit
) {
357 if (dq
->dq_curinodes
< dq
->dq_isoftlimit
) {
358 dq
->dq_itime
= time
.tv_sec
+
359 VFSTOHFS(vp
->v_mount
)->hfs_qfiles
[type
].qf_itime
;
361 if (cp
->c_uid
== cred
->cr_uid
)
362 printf("\n%s: warning, %s %s\n",
363 vp
->v_mount
->mnt_stat
.f_mntonname
,
364 quotatypes
[type
], "cnode quota exceeded");
368 if (time
.tv_sec
> dq
->dq_itime
) {
369 if ((dq
->dq_flags
& DQ_INODS
) == 0 &&
370 cp
->c_uid
== cred
->cr_uid
) {
372 printf("\n%s: write failed, %s %s\n",
373 vp
->v_mount
->mnt_stat
.f_mntonname
,
375 "cnode quota exceeded for too long");
377 dq
->dq_flags
|= DQ_INODS
;
387 * On filesystems with quotas enabled, it is an error for a file to change
388 * size and not to have a dquot structure associated with it.
392 register struct cnode
*cp
;
394 struct vnode
*vp
= cp
->c_vp
? cp
->c_vp
: cp
->c_rsrc_vp
;
395 struct hfsmount
*hfsmp
= VFSTOHFS(vp
->v_mount
);
398 for (i
= 0; i
< MAXQUOTAS
; i
++) {
399 if (hfsmp
->hfs_qfiles
[i
].qf_vp
== NULLVP
||
400 (hfsmp
->hfs_qfiles
[i
].qf_qflags
& (QTF_OPENING
|QTF_CLOSING
)))
402 if (cp
->c_dquot
[i
] == NODQUOT
) {
403 vprint("chkdquot: missing dquot", vp
);
404 panic("missing dquot");
411 * Code to process quotactl commands.
415 * Q_QUOTAON - set up a quota file for a particular file system.
418 hfs_quotaon(p
, mp
, type
, fname
, segflg
)
425 struct hfsmount
*hfsmp
= VFSTOHFS(mp
);
426 struct vnode
*vp
, **vpp
;
427 struct vnode
*nextvp
;
432 vpp
= &hfsmp
->hfs_qfiles
[type
].qf_vp
;
433 NDINIT(&nd
, LOOKUP
, FOLLOW
, segflg
, fname
, p
);
434 if (error
= vn_open(&nd
, FREAD
|FWRITE
, 0))
437 VOP_UNLOCK(vp
, 0, p
);
438 if (vp
->v_type
!= VREG
) {
439 (void) vn_close(vp
, FREAD
|FWRITE
, p
->p_ucred
, p
);
443 hfs_quotaoff(p
, mp
, type
);
444 hfsmp
->hfs_qfiles
[type
].qf_qflags
|= QTF_OPENING
;
445 mp
->mnt_flag
|= MNT_QUOTA
;
446 vp
->v_flag
|= VNOFLUSH
;
449 * Save the credential of the process that turned on quotas.
452 hfsmp
->hfs_qfiles
[type
].qf_cred
= p
->p_ucred
;
453 /* Finish initializing the quota file */
454 if (error
= dqfileopen(&hfsmp
->hfs_qfiles
[type
], type
))
457 * Search vnodes associated with this mount point,
458 * adding references to quota file being opened.
459 * NB: only need to add dquot's for cnodes being modified.
462 for (vp
= mp
->mnt_vnodelist
.lh_first
; vp
!= NULL
; vp
= nextvp
) {
463 nextvp
= vp
->v_mntvnodes
.le_next
;
464 if (vp
->v_writecount
== 0)
466 if (vget(vp
, LK_EXCLUSIVE
, p
))
468 if (error
= hfs_getinoquota(VTOC(vp
))) {
473 if (vp
->v_mntvnodes
.le_next
!= nextvp
|| vp
->v_mount
!= mp
)
477 hfsmp
->hfs_qfiles
[type
].qf_qflags
&= ~QTF_OPENING
;
479 hfs_quotaoff(p
, mp
, type
);
484 * Q_QUOTAOFF - turn off disk quotas for a filesystem.
487 hfs_quotaoff(p
, mp
, type
)
493 struct vnode
*qvp
, *nextvp
;
494 struct hfsmount
*hfsmp
= VFSTOHFS(mp
);
500 if ((qvp
= hfsmp
->hfs_qfiles
[type
].qf_vp
) == NULLVP
)
502 hfsmp
->hfs_qfiles
[type
].qf_qflags
|= QTF_CLOSING
;
505 * Sync out any orpaned dirty dquot entries.
507 dqsync_orphans(&hfsmp
->hfs_qfiles
[type
]);
510 * Search vnodes associated with this mount point,
511 * deleting any references to quota file being closed.
514 for (vp
= mp
->mnt_vnodelist
.lh_first
; vp
!= NULL
; vp
= nextvp
) {
515 nextvp
= vp
->v_mntvnodes
.le_next
;
516 if (vget(vp
, LK_EXCLUSIVE
, p
))
519 dq
= cp
->c_dquot
[type
];
520 cp
->c_dquot
[type
] = NODQUOT
;
523 if (vp
->v_mntvnodes
.le_next
!= nextvp
|| vp
->v_mount
!= mp
)
527 /* Finish tearing down the quota file */
528 dqfileclose(&hfsmp
->hfs_qfiles
[type
], type
);
529 qvp
->v_flag
&= ~VNOFLUSH
;
530 error
= vn_close(qvp
, FREAD
|FWRITE
, p
->p_ucred
, p
);
531 hfsmp
->hfs_qfiles
[type
].qf_vp
= NULLVP
;
532 cred
= hfsmp
->hfs_qfiles
[type
].qf_cred
;
533 if (cred
!= NOCRED
) {
534 hfsmp
->hfs_qfiles
[type
].qf_cred
= NOCRED
;
537 hfsmp
->hfs_qfiles
[type
].qf_qflags
&= ~QTF_CLOSING
;
538 for (type
= 0; type
< MAXQUOTAS
; type
++)
539 if (hfsmp
->hfs_qfiles
[type
].qf_vp
!= NULLVP
)
541 if (type
== MAXQUOTAS
)
542 mp
->mnt_flag
&= ~MNT_QUOTA
;
547 * Q_GETQUOTA - return current values in a dqblk structure.
550 hfs_getquota(mp
, id
, type
, addr
)
559 if (error
= dqget(NULLVP
, id
, &VFSTOHFS(mp
)->hfs_qfiles
[type
], type
, &dq
))
561 error
= copyout((caddr_t
)&dq
->dq_dqb
, addr
, sizeof (struct dqblk
));
567 * Q_SETQUOTA - assign an entire dqblk structure.
570 hfs_setquota(mp
, id
, type
, addr
)
576 register struct dquot
*dq
;
578 struct hfsmount
*hfsmp
= VFSTOHFS(mp
);
582 if (error
= copyin(addr
, (caddr_t
)&newlim
, sizeof (struct dqblk
)))
584 if (error
= dqget(NULLVP
, id
, &hfsmp
->hfs_qfiles
[type
], type
, &ndq
))
587 while (dq
->dq_flags
& DQ_LOCK
) {
588 dq
->dq_flags
|= DQ_WANT
;
589 sleep((caddr_t
)dq
, PINOD
+1);
592 * Copy all but the current values.
593 * Reset time limit if previously had no soft limit or were
594 * under it, but now have a soft limit and are over it.
596 newlim
.dqb_curbytes
= dq
->dq_curbytes
;
597 newlim
.dqb_curinodes
= dq
->dq_curinodes
;
598 if (dq
->dq_id
!= 0) {
599 newlim
.dqb_btime
= dq
->dq_btime
;
600 newlim
.dqb_itime
= dq
->dq_itime
;
602 if (newlim
.dqb_bsoftlimit
&&
603 dq
->dq_curbytes
>= newlim
.dqb_bsoftlimit
&&
604 (dq
->dq_bsoftlimit
== 0 || dq
->dq_curbytes
< dq
->dq_bsoftlimit
))
605 newlim
.dqb_btime
= time
.tv_sec
+ hfsmp
->hfs_qfiles
[type
].qf_btime
;
606 if (newlim
.dqb_isoftlimit
&&
607 dq
->dq_curinodes
>= newlim
.dqb_isoftlimit
&&
608 (dq
->dq_isoftlimit
== 0 || dq
->dq_curinodes
< dq
->dq_isoftlimit
))
609 newlim
.dqb_itime
= time
.tv_sec
+ hfsmp
->hfs_qfiles
[type
].qf_itime
;
611 if (dq
->dq_curbytes
< dq
->dq_bsoftlimit
)
612 dq
->dq_flags
&= ~DQ_BLKS
;
613 if (dq
->dq_curinodes
< dq
->dq_isoftlimit
)
614 dq
->dq_flags
&= ~DQ_INODS
;
615 if (dq
->dq_isoftlimit
== 0 && dq
->dq_bsoftlimit
== 0 &&
616 dq
->dq_ihardlimit
== 0 && dq
->dq_bhardlimit
== 0)
617 dq
->dq_flags
|= DQ_FAKE
;
619 dq
->dq_flags
&= ~DQ_FAKE
;
620 dq
->dq_flags
|= DQ_MOD
;
626 * Q_SETUSE - set current cnode and byte usage.
629 hfs_setuse(mp
, id
, type
, addr
)
635 register struct dquot
*dq
;
636 struct hfsmount
*hfsmp
= VFSTOHFS(mp
);
641 if (error
= copyin(addr
, (caddr_t
)&usage
, sizeof (struct dqblk
)))
643 if (error
= dqget(NULLVP
, id
, &hfsmp
->hfs_qfiles
[type
], type
, &ndq
))
646 while (dq
->dq_flags
& DQ_LOCK
) {
647 dq
->dq_flags
|= DQ_WANT
;
648 sleep((caddr_t
)dq
, PINOD
+1);
651 * Reset time limit if have a soft limit and were
652 * previously under it, but are now over it.
654 if (dq
->dq_bsoftlimit
&& dq
->dq_curbytes
< dq
->dq_bsoftlimit
&&
655 usage
.dqb_curbytes
>= dq
->dq_bsoftlimit
)
656 dq
->dq_btime
= time
.tv_sec
+ hfsmp
->hfs_qfiles
[type
].qf_btime
;
657 if (dq
->dq_isoftlimit
&& dq
->dq_curinodes
< dq
->dq_isoftlimit
&&
658 usage
.dqb_curinodes
>= dq
->dq_isoftlimit
)
659 dq
->dq_itime
= time
.tv_sec
+ hfsmp
->hfs_qfiles
[type
].qf_itime
;
660 dq
->dq_curbytes
= usage
.dqb_curbytes
;
661 dq
->dq_curinodes
= usage
.dqb_curinodes
;
662 if (dq
->dq_curbytes
< dq
->dq_bsoftlimit
)
663 dq
->dq_flags
&= ~DQ_BLKS
;
664 if (dq
->dq_curinodes
< dq
->dq_isoftlimit
)
665 dq
->dq_flags
&= ~DQ_INODS
;
666 dq
->dq_flags
|= DQ_MOD
;
672 * Q_SYNC - sync quota files to disk.
678 struct hfsmount
*hfsmp
= VFSTOHFS(mp
);
679 struct proc
*p
= current_proc(); /* XXX */
680 struct vnode
*vp
, *nextvp
;
685 * Check if the mount point has any quotas.
686 * If not, simply return.
688 for (i
= 0; i
< MAXQUOTAS
; i
++)
689 if (hfsmp
->hfs_qfiles
[i
].qf_vp
!= NULLVP
)
695 * Sync out any orpaned dirty dquot entries.
697 for (i
= 0; i
< MAXQUOTAS
; i
++)
698 if (hfsmp
->hfs_qfiles
[i
].qf_vp
!= NULLVP
)
699 dqsync_orphans(&hfsmp
->hfs_qfiles
[i
]);
702 * Search vnodes associated with this mount point,
703 * synchronizing any modified dquot structures.
705 simple_lock(&mntvnode_slock
);
707 for (vp
= mp
->mnt_vnodelist
.lh_first
; vp
!= NULL
; vp
= nextvp
) {
708 if (vp
->v_mount
!= mp
)
711 nextvp
= vp
->v_mntvnodes
.le_next
;
712 simple_lock(&vp
->v_interlock
);
713 simple_unlock(&mntvnode_slock
);
715 error
= vget(vp
, LK_EXCLUSIVE
| LK_NOWAIT
| LK_INTERLOCK
, p
);
717 simple_lock(&mntvnode_slock
);
723 // Make sure that this is really an hfs vnode.
725 if ( vp
->v_mount
!= mp
726 || vp
->v_type
== VNON
727 || vp
->v_tag
!= VT_HFS
728 || VTOC(vp
) == NULL
) {
731 simple_lock(&mntvnode_slock
);
735 for (i
= 0; i
< MAXQUOTAS
; i
++) {
736 dq
= VTOC(vp
)->c_dquot
[i
];
737 if (dq
!= NODQUOT
&& (dq
->dq_flags
& DQ_MOD
))
741 simple_lock(&mntvnode_slock
);
742 if (vp
->v_mntvnodes
.le_next
!= nextvp
)
745 simple_unlock(&mntvnode_slock
);
750 * Q_QUOTASTAT - get quota on/off status
753 hfs_quotastat(mp
, type
, addr
)
758 struct hfsmount
*hfsmp
= VFSTOHFS(mp
);
762 if ((mp
->mnt_flag
& MNT_QUOTA
) && (hfsmp
->hfs_qfiles
[type
].qf_vp
!= NULLVP
))
763 qstat
= 1; /* quotas are on for this type */
765 qstat
= 0; /* quotas are off for this type */
767 error
= copyout ((caddr_t
)&qstat
, addr
, sizeof(qstat
));