]>
git.saurik.com Git - apple/xnu.git/blob - bsd/ufs/ufs/ufs_quota.c
eff293ea168c1bb60962ce0a3f178a010b1792c6
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
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
58 * @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95
61 #include <sys/param.h>
62 #include <sys/kernel.h>
63 #include <sys/systm.h>
64 #include <sys/namei.h>
65 #include <sys/malloc.h>
68 #include <sys/vnode.h>
69 #include <sys/mount.h>
71 #include <ufs/ufs/quota.h>
72 #include <ufs/ufs/inode.h>
73 #include <ufs/ufs/ufsmount.h>
74 #include <ufs/ufs/ufs_extern.h>
77 * Quota name to error message mapping.
79 static char *quotatypes
[] = INITQFNAMES
;
82 * Set up the quotas for an inode.
84 * This routine completely defines the semantics of quotas.
85 * If other criterion want to be used to establish quotas, the
86 * MAXQUOTAS value in quotas.h should be increased, and the
87 * additional dquots set up here.
91 register struct inode
*ip
;
94 struct vnode
*vp
= ITOV(ip
);
97 ump
= VFSTOUFS(vp
->v_mount
);
99 * Set up the user quota based on file uid.
100 * EINVAL means that quotas are not enabled.
102 if (ip
->i_dquot
[USRQUOTA
] == NODQUOT
&&
104 dqget(vp
, ip
->i_uid
, ump
, USRQUOTA
, &ip
->i_dquot
[USRQUOTA
])) &&
108 * Set up the group quota based on file gid.
109 * EINVAL means that quotas are not enabled.
111 if (ip
->i_dquot
[GRPQUOTA
] == NODQUOT
&&
113 dqget(vp
, ip
->i_gid
, ump
, GRPQUOTA
, &ip
->i_dquot
[GRPQUOTA
])) &&
120 * Update disk usage, and take corrective action.
123 chkdq(ip
, change
, cred
, flags
)
124 register struct inode
*ip
;
129 register struct dquot
*dq
;
131 int ncurblocks
, error
;
134 if ((flags
& CHOWN
) == 0)
140 for (i
= 0; i
< MAXQUOTAS
; i
++) {
141 if ((dq
= ip
->i_dquot
[i
]) == NODQUOT
)
143 while (dq
->dq_flags
& DQ_LOCK
) {
144 dq
->dq_flags
|= DQ_WANT
;
145 sleep((caddr_t
)dq
, PINOD
+1);
147 ncurblocks
= dq
->dq_curblocks
+ change
;
149 dq
->dq_curblocks
= ncurblocks
;
151 dq
->dq_curblocks
= 0;
152 dq
->dq_flags
&= ~DQ_BLKS
;
153 dq
->dq_flags
|= DQ_MOD
;
157 if ((flags
& FORCE
) == 0 && cred
->cr_uid
!= 0) {
158 for (i
= 0; i
< MAXQUOTAS
; i
++) {
159 if ((dq
= ip
->i_dquot
[i
]) == NODQUOT
)
161 if (error
= chkdqchg(ip
, change
, cred
, i
))
165 for (i
= 0; i
< MAXQUOTAS
; i
++) {
166 if ((dq
= ip
->i_dquot
[i
]) == NODQUOT
)
168 while (dq
->dq_flags
& DQ_LOCK
) {
169 dq
->dq_flags
|= DQ_WANT
;
170 sleep((caddr_t
)dq
, PINOD
+1);
172 dq
->dq_curblocks
+= change
;
173 dq
->dq_flags
|= DQ_MOD
;
179 * Check for a valid change to a users allocation.
180 * Issue an error message if appropriate.
183 chkdqchg(ip
, change
, cred
, type
)
189 register struct dquot
*dq
= ip
->i_dquot
[type
];
190 long ncurblocks
= dq
->dq_curblocks
+ change
;
193 * If user would exceed their hard limit, disallow space allocation.
195 if (ncurblocks
>= dq
->dq_bhardlimit
&& dq
->dq_bhardlimit
) {
196 if ((dq
->dq_flags
& DQ_BLKS
) == 0 &&
197 ip
->i_uid
== cred
->cr_uid
) {
198 uprintf("\n%s: write failed, %s disk limit reached\n",
199 ITOV(ip
)->v_mount
->mnt_stat
.f_mntonname
,
201 dq
->dq_flags
|= DQ_BLKS
;
206 * If user is over their soft limit for too long, disallow space
207 * allocation. Reset time limit as they cross their soft limit.
209 if (ncurblocks
>= dq
->dq_bsoftlimit
&& dq
->dq_bsoftlimit
) {
210 if (dq
->dq_curblocks
< dq
->dq_bsoftlimit
) {
211 dq
->dq_btime
= time
.tv_sec
+
212 VFSTOUFS(ITOV(ip
)->v_mount
)->um_btime
[type
];
213 if (ip
->i_uid
== cred
->cr_uid
)
214 uprintf("\n%s: warning, %s %s\n",
215 ITOV(ip
)->v_mount
->mnt_stat
.f_mntonname
,
216 quotatypes
[type
], "disk quota exceeded");
219 if (time
.tv_sec
> dq
->dq_btime
) {
220 if ((dq
->dq_flags
& DQ_BLKS
) == 0 &&
221 ip
->i_uid
== cred
->cr_uid
) {
222 uprintf("\n%s: write failed, %s %s\n",
223 ITOV(ip
)->v_mount
->mnt_stat
.f_mntonname
,
225 "disk quota exceeded for too long");
226 dq
->dq_flags
|= DQ_BLKS
;
235 * Check the inode limit, applying corrective action.
238 chkiq(ip
, change
, cred
, flags
)
239 register struct inode
*ip
;
244 register struct dquot
*dq
;
246 int ncurinodes
, error
;
249 if ((flags
& CHOWN
) == 0)
255 for (i
= 0; i
< MAXQUOTAS
; i
++) {
256 if ((dq
= ip
->i_dquot
[i
]) == NODQUOT
)
258 while (dq
->dq_flags
& DQ_LOCK
) {
259 dq
->dq_flags
|= DQ_WANT
;
260 sleep((caddr_t
)dq
, PINOD
+1);
262 ncurinodes
= dq
->dq_curinodes
+ change
;
264 dq
->dq_curinodes
= ncurinodes
;
266 dq
->dq_curinodes
= 0;
267 dq
->dq_flags
&= ~DQ_INODS
;
268 dq
->dq_flags
|= DQ_MOD
;
272 if ((flags
& FORCE
) == 0 && cred
->cr_uid
!= 0) {
273 for (i
= 0; i
< MAXQUOTAS
; i
++) {
274 if ((dq
= ip
->i_dquot
[i
]) == NODQUOT
)
276 if (error
= chkiqchg(ip
, change
, cred
, i
))
280 for (i
= 0; i
< MAXQUOTAS
; i
++) {
281 if ((dq
= ip
->i_dquot
[i
]) == NODQUOT
)
283 while (dq
->dq_flags
& DQ_LOCK
) {
284 dq
->dq_flags
|= DQ_WANT
;
285 sleep((caddr_t
)dq
, PINOD
+1);
287 dq
->dq_curinodes
+= change
;
288 dq
->dq_flags
|= DQ_MOD
;
294 * Check for a valid change to a users allocation.
295 * Issue an error message if appropriate.
298 chkiqchg(ip
, change
, cred
, type
)
304 register struct dquot
*dq
= ip
->i_dquot
[type
];
305 long ncurinodes
= dq
->dq_curinodes
+ change
;
308 * If user would exceed their hard limit, disallow inode allocation.
310 if (ncurinodes
>= dq
->dq_ihardlimit
&& dq
->dq_ihardlimit
) {
311 if ((dq
->dq_flags
& DQ_INODS
) == 0 &&
312 ip
->i_uid
== cred
->cr_uid
) {
313 uprintf("\n%s: write failed, %s inode limit reached\n",
314 ITOV(ip
)->v_mount
->mnt_stat
.f_mntonname
,
316 dq
->dq_flags
|= DQ_INODS
;
321 * If user is over their soft limit for too long, disallow inode
322 * allocation. Reset time limit as they cross their soft limit.
324 if (ncurinodes
>= dq
->dq_isoftlimit
&& dq
->dq_isoftlimit
) {
325 if (dq
->dq_curinodes
< dq
->dq_isoftlimit
) {
326 dq
->dq_itime
= time
.tv_sec
+
327 VFSTOUFS(ITOV(ip
)->v_mount
)->um_itime
[type
];
328 if (ip
->i_uid
== cred
->cr_uid
)
329 uprintf("\n%s: warning, %s %s\n",
330 ITOV(ip
)->v_mount
->mnt_stat
.f_mntonname
,
331 quotatypes
[type
], "inode quota exceeded");
334 if (time
.tv_sec
> dq
->dq_itime
) {
335 if ((dq
->dq_flags
& DQ_INODS
) == 0 &&
336 ip
->i_uid
== cred
->cr_uid
) {
337 uprintf("\n%s: write failed, %s %s\n",
338 ITOV(ip
)->v_mount
->mnt_stat
.f_mntonname
,
340 "inode quota exceeded for too long");
341 dq
->dq_flags
|= DQ_INODS
;
351 * On filesystems with quotas enabled, it is an error for a file to change
352 * size and not to have a dquot structure associated with it.
356 register struct inode
*ip
;
358 struct ufsmount
*ump
= VFSTOUFS(ITOV(ip
)->v_mount
);
361 for (i
= 0; i
< MAXQUOTAS
; i
++) {
362 if (ump
->um_quotas
[i
] == NULLVP
||
363 (ump
->um_qflags
[i
] & (QTF_OPENING
|QTF_CLOSING
)))
365 if (ip
->i_dquot
[i
] == NODQUOT
) {
366 vprint("chkdquot: missing dquot", ITOV(ip
));
367 panic("missing dquot");
374 * Code to process quotactl commands.
378 * Q_QUOTAON - set up a quota file for a particular file system.
381 quotaon(p
, mp
, type
, fname
)
387 struct ufsmount
*ump
= VFSTOUFS(mp
);
388 struct vnode
*vp
, **vpp
;
389 struct vnode
*nextvp
;
394 vpp
= &ump
->um_quotas
[type
];
395 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, fname
, p
);
396 if (error
= vn_open(&nd
, FREAD
|FWRITE
, 0))
399 VOP_UNLOCK(vp
, 0, p
);
400 if (vp
->v_type
!= VREG
) {
401 (void) vn_close(vp
, FREAD
|FWRITE
, p
->p_ucred
, p
);
405 quotaoff(p
, mp
, type
);
406 ump
->um_qflags
[type
] |= QTF_OPENING
;
407 mp
->mnt_flag
|= MNT_QUOTA
;
408 vp
->v_flag
|= VSYSTEM
;
411 * Save the credential of the process that turned on quotas.
412 * Set up the time limits for this quota.
415 ump
->um_cred
[type
] = p
->p_ucred
;
416 ump
->um_btime
[type
] = MAX_DQ_TIME
;
417 ump
->um_itime
[type
] = MAX_IQ_TIME
;
418 if (dqget(NULLVP
, 0, ump
, type
, &dq
) == 0) {
419 if (dq
->dq_btime
> 0)
420 ump
->um_btime
[type
] = dq
->dq_btime
;
421 if (dq
->dq_itime
> 0)
422 ump
->um_itime
[type
] = dq
->dq_itime
;
426 * Search vnodes associated with this mount point,
427 * adding references to quota file being opened.
428 * NB: only need to add dquot's for inodes being modified.
431 for (vp
= mp
->mnt_vnodelist
.lh_first
; vp
!= NULL
; vp
= nextvp
) {
432 nextvp
= vp
->v_mntvnodes
.le_next
;
433 if (vp
->v_writecount
== 0)
435 if (vget(vp
, LK_EXCLUSIVE
, p
))
437 if (error
= getinoquota(VTOI(vp
))) {
442 if (vp
->v_mntvnodes
.le_next
!= nextvp
|| vp
->v_mount
!= mp
)
445 ump
->um_qflags
[type
] &= ~QTF_OPENING
;
447 quotaoff(p
, mp
, type
);
452 * Q_QUOTAOFF - turn off disk quotas for a filesystem.
455 quotaoff(p
, mp
, type
)
461 struct vnode
*qvp
, *nextvp
;
462 struct ufsmount
*ump
= VFSTOUFS(mp
);
468 if ((qvp
= ump
->um_quotas
[type
]) == NULLVP
)
470 ump
->um_qflags
[type
] |= QTF_CLOSING
;
472 * Search vnodes associated with this mount point,
473 * deleting any references to quota file being closed.
476 for (vp
= mp
->mnt_vnodelist
.lh_first
; vp
!= NULL
; vp
= nextvp
) {
477 nextvp
= vp
->v_mntvnodes
.le_next
;
478 if (vget(vp
, LK_EXCLUSIVE
, p
))
481 dq
= ip
->i_dquot
[type
];
482 ip
->i_dquot
[type
] = NODQUOT
;
485 if (vp
->v_mntvnodes
.le_next
!= nextvp
|| vp
->v_mount
!= mp
)
489 qvp
->v_flag
&= ~VSYSTEM
;
490 error
= vn_close(qvp
, FREAD
|FWRITE
, p
->p_ucred
, p
);
491 ump
->um_quotas
[type
] = NULLVP
;
492 cred
= ump
->um_cred
[type
];
493 if (cred
!= NOCRED
) {
494 ump
->um_cred
[type
] = NOCRED
;
497 ump
->um_qflags
[type
] &= ~QTF_CLOSING
;
498 for (type
= 0; type
< MAXQUOTAS
; type
++)
499 if (ump
->um_quotas
[type
] != NULLVP
)
501 if (type
== MAXQUOTAS
)
502 mp
->mnt_flag
&= ~MNT_QUOTA
;
507 * Q_GETQUOTA - return current values in a dqblk structure.
510 getquota(mp
, id
, type
, addr
)
519 if (error
= dqget(NULLVP
, id
, VFSTOUFS(mp
), type
, &dq
))
521 error
= copyout((caddr_t
)&dq
->dq_dqb
, addr
, sizeof (struct dqblk
));
527 * Q_SETQUOTA - assign an entire dqblk structure.
530 setquota(mp
, id
, type
, addr
)
536 register struct dquot
*dq
;
538 struct ufsmount
*ump
= VFSTOUFS(mp
);
542 if (error
= copyin(addr
, (caddr_t
)&newlim
, sizeof (struct dqblk
)))
544 if (error
= dqget(NULLVP
, id
, ump
, type
, &ndq
))
547 while (dq
->dq_flags
& DQ_LOCK
) {
548 dq
->dq_flags
|= DQ_WANT
;
549 sleep((caddr_t
)dq
, PINOD
+1);
552 * Copy all but the current values.
553 * Reset time limit if previously had no soft limit or were
554 * under it, but now have a soft limit and are over it.
556 newlim
.dqb_curblocks
= dq
->dq_curblocks
;
557 newlim
.dqb_curinodes
= dq
->dq_curinodes
;
558 if (dq
->dq_id
!= 0) {
559 newlim
.dqb_btime
= dq
->dq_btime
;
560 newlim
.dqb_itime
= dq
->dq_itime
;
562 if (newlim
.dqb_bsoftlimit
&&
563 dq
->dq_curblocks
>= newlim
.dqb_bsoftlimit
&&
564 (dq
->dq_bsoftlimit
== 0 || dq
->dq_curblocks
< dq
->dq_bsoftlimit
))
565 newlim
.dqb_btime
= time
.tv_sec
+ ump
->um_btime
[type
];
566 if (newlim
.dqb_isoftlimit
&&
567 dq
->dq_curinodes
>= newlim
.dqb_isoftlimit
&&
568 (dq
->dq_isoftlimit
== 0 || dq
->dq_curinodes
< dq
->dq_isoftlimit
))
569 newlim
.dqb_itime
= time
.tv_sec
+ ump
->um_itime
[type
];
571 if (dq
->dq_curblocks
< dq
->dq_bsoftlimit
)
572 dq
->dq_flags
&= ~DQ_BLKS
;
573 if (dq
->dq_curinodes
< dq
->dq_isoftlimit
)
574 dq
->dq_flags
&= ~DQ_INODS
;
575 if (dq
->dq_isoftlimit
== 0 && dq
->dq_bsoftlimit
== 0 &&
576 dq
->dq_ihardlimit
== 0 && dq
->dq_bhardlimit
== 0)
577 dq
->dq_flags
|= DQ_FAKE
;
579 dq
->dq_flags
&= ~DQ_FAKE
;
580 dq
->dq_flags
|= DQ_MOD
;
586 * Q_SETUSE - set current inode and block usage.
589 setuse(mp
, id
, type
, addr
)
595 register struct dquot
*dq
;
596 struct ufsmount
*ump
= VFSTOUFS(mp
);
601 if (error
= copyin(addr
, (caddr_t
)&usage
, sizeof (struct dqblk
)))
603 if (error
= dqget(NULLVP
, id
, ump
, type
, &ndq
))
606 while (dq
->dq_flags
& DQ_LOCK
) {
607 dq
->dq_flags
|= DQ_WANT
;
608 sleep((caddr_t
)dq
, PINOD
+1);
611 * Reset time limit if have a soft limit and were
612 * previously under it, but are now over it.
614 if (dq
->dq_bsoftlimit
&& dq
->dq_curblocks
< dq
->dq_bsoftlimit
&&
615 usage
.dqb_curblocks
>= dq
->dq_bsoftlimit
)
616 dq
->dq_btime
= time
.tv_sec
+ ump
->um_btime
[type
];
617 if (dq
->dq_isoftlimit
&& dq
->dq_curinodes
< dq
->dq_isoftlimit
&&
618 usage
.dqb_curinodes
>= dq
->dq_isoftlimit
)
619 dq
->dq_itime
= time
.tv_sec
+ ump
->um_itime
[type
];
620 dq
->dq_curblocks
= usage
.dqb_curblocks
;
621 dq
->dq_curinodes
= usage
.dqb_curinodes
;
622 if (dq
->dq_curblocks
< dq
->dq_bsoftlimit
)
623 dq
->dq_flags
&= ~DQ_BLKS
;
624 if (dq
->dq_curinodes
< dq
->dq_isoftlimit
)
625 dq
->dq_flags
&= ~DQ_INODS
;
626 dq
->dq_flags
|= DQ_MOD
;
632 * Q_SYNC - sync quota files to disk.
638 struct ufsmount
*ump
= VFSTOUFS(mp
);
639 struct proc
*p
= current_proc(); /* XXX */
640 struct vnode
*vp
, *nextvp
;
645 * Check if the mount point has any quotas.
646 * If not, simply return.
648 for (i
= 0; i
< MAXQUOTAS
; i
++)
649 if (ump
->um_quotas
[i
] != NULLVP
)
654 * Search vnodes associated with this mount point,
655 * synchronizing any modified dquot structures.
657 simple_lock(&mntvnode_slock
);
659 for (vp
= mp
->mnt_vnodelist
.lh_first
; vp
!= NULL
; vp
= nextvp
) {
660 if (vp
->v_mount
!= mp
)
662 nextvp
= vp
->v_mntvnodes
.le_next
;
663 simple_lock(&vp
->v_interlock
);
664 simple_unlock(&mntvnode_slock
);
665 error
= vget(vp
, LK_EXCLUSIVE
| LK_NOWAIT
| LK_INTERLOCK
, p
);
667 simple_lock(&mntvnode_slock
);
672 for (i
= 0; i
< MAXQUOTAS
; i
++) {
673 dq
= VTOI(vp
)->i_dquot
[i
];
674 if (dq
!= NODQUOT
&& (dq
->dq_flags
& DQ_MOD
))
678 simple_lock(&mntvnode_slock
);
679 if (vp
->v_mntvnodes
.le_next
!= nextvp
)
682 simple_unlock(&mntvnode_slock
);
687 * Code pertaining to management of the in-core dquot data structures.
689 #define DQHASH(dqvp, id) \
690 (&dqhashtbl[((((int)(dqvp)) >> 8) + id) & dqhash])
691 LIST_HEAD(dqhash
, dquot
) *dqhashtbl
;
697 #define DQUOTINC 5 /* minimum free dquots desired */
698 TAILQ_HEAD(dqfreelist
, dquot
) dqfreelist
;
699 long numdquot
, desireddquot
= DQUOTINC
;
702 * Initialize the quota system.
708 dqhashtbl
= hashinit(desiredvnodes
, M_DQUOT
, &dqhash
);
709 TAILQ_INIT(&dqfreelist
);
713 * Obtain a dquot structure for the specified identifier and quota file
714 * reading the information from the file if necessary.
717 dqget(vp
, id
, ump
, type
, dqp
)
720 register struct ufsmount
*ump
;
724 struct proc
*p
= current_proc(); /* XXX */
732 dqvp
= ump
->um_quotas
[type
];
733 if (dqvp
== NULLVP
|| (ump
->um_qflags
[type
] & QTF_CLOSING
)) {
738 * Check the cache first.
740 dqh
= DQHASH(dqvp
, id
);
741 for (dq
= dqh
->lh_first
; dq
; dq
= dq
->dq_hash
.le_next
) {
742 if (dq
->dq_id
!= id
||
743 dq
->dq_ump
->um_quotas
[dq
->dq_type
] != dqvp
)
746 * Cache hit with no references. Take
747 * the structure off the free list.
750 TAILQ_REMOVE(&dqfreelist
, dq
, dq_freelist
);
756 * Not in cache, allocate a new one.
758 if (dqfreelist
.tqh_first
== NODQUOT
&&
759 numdquot
< MAXQUOTAS
* desiredvnodes
)
760 desireddquot
+= DQUOTINC
;
761 if (numdquot
< desireddquot
) {
762 dq
= (struct dquot
*)_MALLOC(sizeof *dq
, M_DQUOT
, M_WAITOK
);
763 bzero((char *)dq
, sizeof *dq
);
766 if ((dq
= dqfreelist
.tqh_first
) == NULL
) {
771 if (dq
->dq_cnt
|| (dq
->dq_flags
& DQ_MOD
))
772 panic("free dquot isn't");
773 TAILQ_REMOVE(&dqfreelist
, dq
, dq_freelist
);
774 LIST_REMOVE(dq
, dq_hash
);
777 * Initialize the contents of the dquot structure.
780 vn_lock(dqvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
781 LIST_INSERT_HEAD(dqh
, dq
, dq_hash
);
783 dq
->dq_flags
= DQ_LOCK
;
787 auio
.uio_iov
= &aiov
;
789 aiov
.iov_base
= (caddr_t
)&dq
->dq_dqb
;
790 aiov
.iov_len
= sizeof (struct dqblk
);
791 auio
.uio_resid
= sizeof (struct dqblk
);
792 auio
.uio_offset
= (off_t
)(id
* sizeof (struct dqblk
));
793 auio
.uio_segflg
= UIO_SYSSPACE
;
794 auio
.uio_rw
= UIO_READ
;
795 auio
.uio_procp
= (struct proc
*)0;
796 error
= VOP_READ(dqvp
, &auio
, 0, ump
->um_cred
[type
]);
798 if (auio
.uio_resid
== sizeof(struct dqblk
) && error
== 0)
799 bzero((caddr_t
)&dq
->dq_dqb
, sizeof(struct dqblk
));
801 VOP_UNLOCK(dqvp
, 0, p
);
802 if (dq
->dq_flags
& DQ_WANT
)
806 * I/O error in reading quota file, release
807 * quota structure and reflect problem to caller.
810 LIST_REMOVE(dq
, dq_hash
);
816 * Check for no limit to enforce.
817 * Initialize time values if necessary.
819 if (dq
->dq_isoftlimit
== 0 && dq
->dq_bsoftlimit
== 0 &&
820 dq
->dq_ihardlimit
== 0 && dq
->dq_bhardlimit
== 0)
821 dq
->dq_flags
|= DQ_FAKE
;
822 if (dq
->dq_id
!= 0) {
823 if (dq
->dq_btime
== 0)
824 dq
->dq_btime
= time
.tv_sec
+ ump
->um_btime
[type
];
825 if (dq
->dq_itime
== 0)
826 dq
->dq_itime
= time
.tv_sec
+ ump
->um_itime
[type
];
833 * Obtain a reference to a dquot.
844 * Release a reference to a dquot.
849 register struct dquot
*dq
;
854 if (dq
->dq_cnt
> 1) {
858 if (dq
->dq_flags
& DQ_MOD
)
859 (void) dqsync(vp
, dq
);
860 if (--dq
->dq_cnt
> 0)
862 TAILQ_INSERT_TAIL(&dqfreelist
, dq
, dq_freelist
);
866 * Update the disk quota in the quota file.
873 struct proc
*p
= current_proc(); /* XXX */
880 panic("dqsync: dquot");
881 if ((dq
->dq_flags
& DQ_MOD
) == 0)
883 if ((dqvp
= dq
->dq_ump
->um_quotas
[dq
->dq_type
]) == NULLVP
)
884 panic("dqsync: file");
886 vn_lock(dqvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
887 while (dq
->dq_flags
& DQ_LOCK
) {
888 dq
->dq_flags
|= DQ_WANT
;
889 sleep((caddr_t
)dq
, PINOD
+2);
890 if ((dq
->dq_flags
& DQ_MOD
) == 0) {
892 VOP_UNLOCK(dqvp
, 0, p
);
896 dq
->dq_flags
|= DQ_LOCK
;
897 auio
.uio_iov
= &aiov
;
899 aiov
.iov_base
= (caddr_t
)&dq
->dq_dqb
;
900 aiov
.iov_len
= sizeof (struct dqblk
);
901 auio
.uio_resid
= sizeof (struct dqblk
);
902 auio
.uio_offset
= (off_t
)(dq
->dq_id
* sizeof (struct dqblk
));
903 auio
.uio_segflg
= UIO_SYSSPACE
;
904 auio
.uio_rw
= UIO_WRITE
;
905 auio
.uio_procp
= (struct proc
*)0;
906 error
= VOP_WRITE(dqvp
, &auio
, 0, dq
->dq_ump
->um_cred
[dq
->dq_type
]);
907 if (auio
.uio_resid
&& error
== 0)
909 if (dq
->dq_flags
& DQ_WANT
)
911 dq
->dq_flags
&= ~(DQ_MOD
|DQ_LOCK
|DQ_WANT
);
913 VOP_UNLOCK(dqvp
, 0, p
);
918 * Flush all entries from the cache for a particular vnode.
922 register struct vnode
*vp
;
924 register struct dquot
*dq
, *nextdq
;
928 * Move all dquot's that used to refer to this quota
929 * file off their hash chains (they will eventually
930 * fall off the head of the free list and be re-used).
932 for (dqh
= &dqhashtbl
[dqhash
]; dqh
>= dqhashtbl
; dqh
--) {
933 for (dq
= dqh
->lh_first
; dq
; dq
= nextdq
) {
934 nextdq
= dq
->dq_hash
.le_next
;
935 if (dq
->dq_ump
->um_quotas
[dq
->dq_type
] != vp
)
938 panic("dqflush: stray dquot");
939 LIST_REMOVE(dq
, dq_hash
);
940 dq
->dq_ump
= (struct ufsmount
*)0;