|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986, 1990 Regents of the University of California.
3: * All rights reserved.
4: *
5: * This code is derived from software contributed to Berkeley by
6: * Robert Elz at The University of Melbourne.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: *
1.1.1.2 ! root 36: * from: @(#)ufs_quota.c 7.11 (Berkeley) 6/21/91
! 37: * ufs_quota.c,v 1.2.2.1 1993/07/31 12:10:48 cgd Exp
1.1 root 38: */
39: #include "param.h"
40: #include "kernel.h"
41: #include "systm.h"
42: #include "namei.h"
43: #include "malloc.h"
44: #include "file.h"
45: #include "proc.h"
46: #include "vnode.h"
47: #include "mount.h"
48:
49: #include "fs.h"
50: #include "quota.h"
51: #include "inode.h"
52: #include "ufsmount.h"
53:
54: /*
55: * Quota name to error message mapping.
56: */
57: static char *quotatypes[] = INITQFNAMES;
58:
59: /*
60: * Set up the quotas for an inode.
61: *
62: * This routine completely defines the semantics of quotas.
63: * If other criterion want to be used to establish quotas, the
64: * MAXQUOTAS value in quotas.h should be increased, and the
65: * additional dquots set up here.
66: */
67: getinoquota(ip)
68: register struct inode *ip;
69: {
70: struct ufsmount *ump;
71: struct vnode *vp = ITOV(ip);
72: int error;
73:
74: ump = VFSTOUFS(vp->v_mount);
75: /*
76: * Set up the user quota based on file uid.
77: * EINVAL means that quotas are not enabled.
78: */
79: if (ip->i_dquot[USRQUOTA] == NODQUOT &&
80: (error =
81: dqget(vp, ip->i_uid, ump, USRQUOTA, &ip->i_dquot[USRQUOTA])) &&
82: error != EINVAL)
83: return (error);
84: /*
85: * Set up the group quota based on file gid.
86: * EINVAL means that quotas are not enabled.
87: */
88: if (ip->i_dquot[GRPQUOTA] == NODQUOT &&
89: (error =
90: dqget(vp, ip->i_gid, ump, GRPQUOTA, &ip->i_dquot[GRPQUOTA])) &&
91: error != EINVAL)
92: return (error);
93: return (0);
94: }
95:
96: /*
97: * Update disk usage, and take corrective action.
98: */
99: chkdq(ip, change, cred, flags)
100: register struct inode *ip;
101: long change;
102: struct ucred *cred;
103: int flags;
104: {
105: register struct dquot *dq;
106: register int i;
107: int ncurblocks, error;
108:
109: #ifdef DIAGNOSTIC
110: if ((flags & CHOWN) == 0)
111: chkdquot(ip);
112: #endif
113: if (change == 0)
114: return (0);
115: if (change < 0) {
116: for (i = 0; i < MAXQUOTAS; i++) {
117: if ((dq = ip->i_dquot[i]) == NODQUOT)
118: continue;
119: while (dq->dq_flags & DQ_LOCK) {
120: dq->dq_flags |= DQ_WANT;
1.1.1.2 ! root 121: tsleep((caddr_t)dq, PINOD+1, "chkdq1", 0);
1.1 root 122: }
123: ncurblocks = dq->dq_curblocks + change;
124: if (ncurblocks >= 0)
125: dq->dq_curblocks = ncurblocks;
126: else
127: dq->dq_curblocks = 0;
128: dq->dq_flags &= ~DQ_BLKS;
129: dq->dq_flags |= DQ_MOD;
130: }
131: return (0);
132: }
133: if ((flags & FORCE) == 0 && cred->cr_uid != 0) {
134: for (i = 0; i < MAXQUOTAS; i++) {
135: if ((dq = ip->i_dquot[i]) == NODQUOT)
136: continue;
137: if (error = chkdqchg(ip, change, cred, i))
138: return (error);
139: }
140: }
141: for (i = 0; i < MAXQUOTAS; i++) {
142: if ((dq = ip->i_dquot[i]) == NODQUOT)
143: continue;
144: while (dq->dq_flags & DQ_LOCK) {
145: dq->dq_flags |= DQ_WANT;
1.1.1.2 ! root 146: tsleep((caddr_t)dq, PINOD+1, "chkdq2", 0);
1.1 root 147: }
148: dq->dq_curblocks += change;
149: dq->dq_flags |= DQ_MOD;
150: }
151: return (0);
152: }
153:
154: /*
155: * Check for a valid change to a users allocation.
156: * Issue an error message if appropriate.
157: */
158: chkdqchg(ip, change, cred, type)
159: struct inode *ip;
160: long change;
161: struct ucred *cred;
162: int type;
163: {
164: register struct dquot *dq = ip->i_dquot[type];
165: long ncurblocks = dq->dq_curblocks + change;
166:
167: /*
168: * If user would exceed their hard limit, disallow space allocation.
169: */
170: if (ncurblocks >= dq->dq_bhardlimit && dq->dq_bhardlimit) {
171: if ((dq->dq_flags & DQ_BLKS) == 0 &&
172: ip->i_uid == cred->cr_uid) {
173: uprintf("\n%s: write failed, %s disk limit reached\n",
174: ip->i_fs->fs_fsmnt, quotatypes[type]);
175: dq->dq_flags |= DQ_BLKS;
176: }
177: return (EDQUOT);
178: }
179: /*
180: * If user is over their soft limit for too long, disallow space
181: * allocation. Reset time limit as they cross their soft limit.
182: */
183: if (ncurblocks >= dq->dq_bsoftlimit && dq->dq_bsoftlimit) {
184: if (dq->dq_curblocks < dq->dq_bsoftlimit) {
185: dq->dq_btime = time.tv_sec +
186: VFSTOUFS(ITOV(ip)->v_mount)->um_btime[type];
187: if (ip->i_uid == cred->cr_uid)
188: uprintf("\n%s: warning, %s %s\n",
189: ip->i_fs->fs_fsmnt, quotatypes[type],
190: "disk quota exceeded");
191: return (0);
192: }
193: if (time.tv_sec > dq->dq_btime) {
194: if ((dq->dq_flags & DQ_BLKS) == 0 &&
195: ip->i_uid == cred->cr_uid) {
196: uprintf("\n%s: write failed, %s %s\n",
197: ip->i_fs->fs_fsmnt, quotatypes[type],
198: "disk quota exceeded too long");
199: dq->dq_flags |= DQ_BLKS;
200: }
201: return (EDQUOT);
202: }
203: }
204: return (0);
205: }
206:
207: /*
208: * Check the inode limit, applying corrective action.
209: */
210: chkiq(ip, change, cred, flags)
211: register struct inode *ip;
212: long change;
213: struct ucred *cred;
214: int flags;
215: {
216: register struct dquot *dq;
217: register int i;
218: int ncurinodes, error;
219:
220: #ifdef DIAGNOSTIC
221: if ((flags & CHOWN) == 0)
222: chkdquot(ip);
223: #endif
224: if (change == 0)
225: return (0);
226: if (change < 0) {
227: for (i = 0; i < MAXQUOTAS; i++) {
228: if ((dq = ip->i_dquot[i]) == NODQUOT)
229: continue;
230: while (dq->dq_flags & DQ_LOCK) {
231: dq->dq_flags |= DQ_WANT;
1.1.1.2 ! root 232: tsleep((caddr_t)dq, PINOD+1, "chkiq1", 0);
1.1 root 233: }
234: ncurinodes = dq->dq_curinodes + change;
235: if (ncurinodes >= 0)
236: dq->dq_curinodes = ncurinodes;
237: else
238: dq->dq_curinodes = 0;
239: dq->dq_flags &= ~DQ_INODS;
240: dq->dq_flags |= DQ_MOD;
241: }
242: return (0);
243: }
244: if ((flags & FORCE) == 0 && cred->cr_uid != 0) {
245: for (i = 0; i < MAXQUOTAS; i++) {
246: if ((dq = ip->i_dquot[i]) == NODQUOT)
247: continue;
248: if (error = chkiqchg(ip, change, cred, i))
249: return (error);
250: }
251: }
252: for (i = 0; i < MAXQUOTAS; i++) {
253: if ((dq = ip->i_dquot[i]) == NODQUOT)
254: continue;
255: while (dq->dq_flags & DQ_LOCK) {
256: dq->dq_flags |= DQ_WANT;
1.1.1.2 ! root 257: tsleep((caddr_t)dq, PINOD+1, "chkiq2", 0);
1.1 root 258: }
259: dq->dq_curinodes += change;
260: dq->dq_flags |= DQ_MOD;
261: }
262: return (0);
263: }
264:
265: /*
266: * Check for a valid change to a users allocation.
267: * Issue an error message if appropriate.
268: */
269: chkiqchg(ip, change, cred, type)
270: struct inode *ip;
271: long change;
272: struct ucred *cred;
273: int type;
274: {
275: register struct dquot *dq = ip->i_dquot[type];
276: long ncurinodes = dq->dq_curinodes + change;
277:
278: /*
279: * If user would exceed their hard limit, disallow inode allocation.
280: */
281: if (ncurinodes >= dq->dq_ihardlimit && dq->dq_ihardlimit) {
282: if ((dq->dq_flags & DQ_INODS) == 0 &&
283: ip->i_uid == cred->cr_uid) {
284: uprintf("\n%s: write failed, %s inode limit reached\n",
285: ip->i_fs->fs_fsmnt, quotatypes[type]);
286: dq->dq_flags |= DQ_INODS;
287: }
288: return (EDQUOT);
289: }
290: /*
291: * If user is over their soft limit for too long, disallow inode
292: * allocation. Reset time limit as they cross their soft limit.
293: */
294: if (ncurinodes >= dq->dq_isoftlimit && dq->dq_isoftlimit) {
295: if (dq->dq_curinodes < dq->dq_isoftlimit) {
296: dq->dq_itime = time.tv_sec +
297: VFSTOUFS(ITOV(ip)->v_mount)->um_itime[type];
298: if (ip->i_uid == cred->cr_uid)
299: uprintf("\n%s: warning, %s %s\n",
300: ip->i_fs->fs_fsmnt, quotatypes[type],
301: "inode quota exceeded");
302: return (0);
303: }
304: if (time.tv_sec > dq->dq_itime) {
305: if ((dq->dq_flags & DQ_INODS) == 0 &&
306: ip->i_uid == cred->cr_uid) {
307: uprintf("\n%s: write failed, %s %s\n",
308: ip->i_fs->fs_fsmnt, quotatypes[type],
309: "inode quota exceeded too long");
310: dq->dq_flags |= DQ_INODS;
311: }
312: return (EDQUOT);
313: }
314: }
315: return (0);
316: }
317:
318: #ifdef DIAGNOSTIC
319: /*
320: * On filesystems with quotas enabled,
321: * it is an error for a file to change size and not
322: * to have a dquot structure associated with it.
323: */
324: chkdquot(ip)
325: register struct inode *ip;
326: {
327: struct ufsmount *ump = VFSTOUFS(ITOV(ip)->v_mount);
328: register int i;
329:
330: for (i = 0; i < MAXQUOTAS; i++) {
331: if (ump->um_quotas[i] == NULLVP ||
332: (ump->um_qflags[i] & (QTF_OPENING|QTF_CLOSING)))
333: continue;
334: if (ip->i_dquot[i] == NODQUOT) {
335: vprint("chkdquot: missing dquot", ITOV(ip));
336: panic("missing dquot");
337: }
338: }
339: }
340: #endif /* DIAGNOSTIC */
341:
342: /*
343: * Code to process quotactl commands.
344: */
345:
346: /*
347: * Q_QUOTAON - set up a quota file for a particular file system.
348: */
349: quotaon(p, mp, type, fname)
350: struct proc *p;
351: struct mount *mp;
352: register int type;
353: caddr_t fname;
354: {
355: register struct ufsmount *ump = VFSTOUFS(mp);
356: register struct vnode *vp, **vpp;
357: struct vnode *nextvp;
358: struct dquot *dq;
359: int error;
360: struct nameidata nd;
361:
362: vpp = &ump->um_quotas[type];
363: nd.ni_segflg = UIO_USERSPACE;
364: nd.ni_dirp = fname;
365: if (error = vn_open(&nd, p, FREAD|FWRITE, 0))
366: return (error);
367: vp = nd.ni_vp;
368: VOP_UNLOCK(vp);
369: if (vp->v_type != VREG) {
370: (void) vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
371: return (EACCES);
372: }
373: if (vfs_busy(mp)) {
374: (void) vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
375: return (EBUSY);
376: }
377: if (*vpp != vp)
378: quotaoff(p, mp, type);
379: ump->um_qflags[type] |= QTF_OPENING;
380: mp->mnt_flag |= MNT_QUOTA;
381: vp->v_flag |= VSYSTEM;
382: *vpp = vp;
383: /*
384: * Save the credential of the process that turned on quotas.
385: * Set up the time limits for this quota.
386: */
387: crhold(p->p_ucred);
388: ump->um_cred[type] = p->p_ucred;
389: ump->um_btime[type] = MAX_DQ_TIME;
390: ump->um_itime[type] = MAX_IQ_TIME;
391: if (dqget(NULLVP, 0, ump, type, &dq) == 0) {
392: if (dq->dq_btime > 0)
393: ump->um_btime[type] = dq->dq_btime;
394: if (dq->dq_itime > 0)
395: ump->um_itime[type] = dq->dq_itime;
396: dqrele(NULLVP, dq);
397: }
398: /*
399: * Search vnodes associated with this mount point,
400: * adding references to quota file being opened.
401: * NB: only need to add dquot's for inodes being modified.
402: */
403: again:
404: for (vp = mp->mnt_mounth; vp; vp = nextvp) {
405: nextvp = vp->v_mountf;
406: if (vp->v_writecount == 0)
407: continue;
408: if (vget(vp))
409: goto again;
410: if (error = getinoquota(VTOI(vp))) {
411: vput(vp);
412: break;
413: }
414: vput(vp);
415: if (vp->v_mountf != nextvp || vp->v_mount != mp)
416: goto again;
417: }
418: ump->um_qflags[type] &= ~QTF_OPENING;
419: if (error)
420: quotaoff(p, mp, type);
421: vfs_unbusy(mp);
422: return (error);
423: }
424:
425: /*
426: * Q_QUOTAOFF - turn off disk quotas for a filesystem.
427: */
428: quotaoff(p, mp, type)
429: struct proc *p;
430: struct mount *mp;
431: register int type;
432: {
433: register struct vnode *vp;
434: struct vnode *qvp, *nextvp;
435: struct ufsmount *ump = VFSTOUFS(mp);
436: register struct dquot *dq;
437: register struct inode *ip;
438: int error;
439:
440: if ((mp->mnt_flag & MNT_MPBUSY) == 0)
441: panic("quotaoff: not busy");
442: if ((qvp = ump->um_quotas[type]) == NULLVP)
443: return (0);
444: ump->um_qflags[type] |= QTF_CLOSING;
445: /*
446: * Search vnodes associated with this mount point,
447: * deleting any references to quota file being closed.
448: */
449: again:
450: for (vp = mp->mnt_mounth; vp; vp = nextvp) {
451: nextvp = vp->v_mountf;
452: if (vget(vp))
453: goto again;
454: ip = VTOI(vp);
455: dq = ip->i_dquot[type];
456: ip->i_dquot[type] = NODQUOT;
457: dqrele(vp, dq);
458: vput(vp);
459: if (vp->v_mountf != nextvp || vp->v_mount != mp)
460: goto again;
461: }
462: dqflush(qvp);
463: qvp->v_flag &= ~VSYSTEM;
464: error = vn_close(qvp, FREAD|FWRITE, p->p_ucred, p);
465: ump->um_quotas[type] = NULLVP;
466: crfree(ump->um_cred[type]);
467: ump->um_cred[type] = NOCRED;
468: ump->um_qflags[type] &= ~QTF_CLOSING;
469: for (type = 0; type < MAXQUOTAS; type++)
470: if (ump->um_quotas[type] != NULLVP)
471: break;
472: if (type == MAXQUOTAS)
473: mp->mnt_flag &= ~MNT_QUOTA;
474: return (error);
475: }
476:
477: /*
478: * Q_GETQUOTA - return current values in a dqblk structure.
479: */
480: getquota(mp, id, type, addr)
481: struct mount *mp;
482: u_long id;
483: int type;
484: caddr_t addr;
485: {
486: struct dquot *dq;
487: int error;
488:
489: if (error = dqget(NULLVP, id, VFSTOUFS(mp), type, &dq))
490: return (error);
491: error = copyout((caddr_t)&dq->dq_dqb, addr, sizeof (struct dqblk));
492: dqrele(NULLVP, dq);
493: return (error);
494: }
495:
496: /*
497: * Q_SETQUOTA - assign an entire dqblk structure.
498: */
499: setquota(mp, id, type, addr)
500: struct mount *mp;
501: u_long id;
502: int type;
503: caddr_t addr;
504: {
505: register struct dquot *dq;
506: struct dquot *ndq;
507: struct ufsmount *ump = VFSTOUFS(mp);
508: struct dqblk newlim;
509: int error;
510:
511: if (error = copyin(addr, (caddr_t)&newlim, sizeof (struct dqblk)))
512: return (error);
513: if (error = dqget(NULLVP, id, ump, type, &ndq))
514: return (error);
515: dq = ndq;
516: while (dq->dq_flags & DQ_LOCK) {
517: dq->dq_flags |= DQ_WANT;
1.1.1.2 ! root 518: tsleep((caddr_t)dq, PINOD+1, "setquot", 0);
1.1 root 519: }
520: /*
521: * Copy all but the current values.
522: * Reset time limit if previously had no soft limit or were
523: * under it, but now have a soft limit and are over it.
524: */
525: newlim.dqb_curblocks = dq->dq_curblocks;
526: newlim.dqb_curinodes = dq->dq_curinodes;
527: if (dq->dq_id != 0) {
528: newlim.dqb_btime = dq->dq_btime;
529: newlim.dqb_itime = dq->dq_itime;
530: }
531: if (newlim.dqb_bsoftlimit &&
532: dq->dq_curblocks >= newlim.dqb_bsoftlimit &&
533: (dq->dq_bsoftlimit == 0 || dq->dq_curblocks < dq->dq_bsoftlimit))
534: newlim.dqb_btime = time.tv_sec + ump->um_btime[type];
535: if (newlim.dqb_isoftlimit &&
536: dq->dq_curinodes >= newlim.dqb_isoftlimit &&
537: (dq->dq_isoftlimit == 0 || dq->dq_curinodes < dq->dq_isoftlimit))
538: newlim.dqb_itime = time.tv_sec + ump->um_itime[type];
539: dq->dq_dqb = newlim;
540: if (dq->dq_curblocks < dq->dq_bsoftlimit)
541: dq->dq_flags &= ~DQ_BLKS;
542: if (dq->dq_curinodes < dq->dq_isoftlimit)
543: dq->dq_flags &= ~DQ_INODS;
544: if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
545: dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
546: dq->dq_flags |= DQ_FAKE;
547: else
548: dq->dq_flags &= ~DQ_FAKE;
549: dq->dq_flags |= DQ_MOD;
550: dqrele(NULLVP, dq);
551: return (0);
552: }
553:
554: /*
555: * Q_SETUSE - set current inode and block usage.
556: */
557: setuse(mp, id, type, addr)
558: struct mount *mp;
559: u_long id;
560: int type;
561: caddr_t addr;
562: {
563: register struct dquot *dq;
564: struct ufsmount *ump = VFSTOUFS(mp);
565: struct dquot *ndq;
566: struct dqblk usage;
567: int error;
568:
569: if (error = copyin(addr, (caddr_t)&usage, sizeof (struct dqblk)))
570: return (error);
571: if (error = dqget(NULLVP, id, ump, type, &ndq))
572: return (error);
573: dq = ndq;
574: while (dq->dq_flags & DQ_LOCK) {
575: dq->dq_flags |= DQ_WANT;
1.1.1.2 ! root 576: tsleep((caddr_t)dq, PINOD+1, "setuse", 0);
1.1 root 577: }
578: /*
579: * Reset time limit if have a soft limit and were
580: * previously under it, but are now over it.
581: */
582: if (dq->dq_bsoftlimit && dq->dq_curblocks < dq->dq_bsoftlimit &&
583: usage.dqb_curblocks >= dq->dq_bsoftlimit)
584: dq->dq_btime = time.tv_sec + ump->um_btime[type];
585: if (dq->dq_isoftlimit && dq->dq_curinodes < dq->dq_isoftlimit &&
586: usage.dqb_curinodes >= dq->dq_isoftlimit)
587: dq->dq_itime = time.tv_sec + ump->um_itime[type];
588: dq->dq_curblocks = usage.dqb_curblocks;
589: dq->dq_curinodes = usage.dqb_curinodes;
590: if (dq->dq_curblocks < dq->dq_bsoftlimit)
591: dq->dq_flags &= ~DQ_BLKS;
592: if (dq->dq_curinodes < dq->dq_isoftlimit)
593: dq->dq_flags &= ~DQ_INODS;
594: dq->dq_flags |= DQ_MOD;
595: dqrele(NULLVP, dq);
596: return (0);
597: }
598:
599: /*
600: * Q_SYNC - sync quota files to disk.
601: */
602: qsync(mp)
603: struct mount *mp;
604: {
605: struct ufsmount *ump = VFSTOUFS(mp);
606: register struct vnode *vp, *nextvp;
607: register struct dquot *dq;
608: register int i;
609:
610: /*
611: * Check if the mount point has any quotas.
612: * If not, simply return.
613: */
614: if ((mp->mnt_flag & MNT_MPBUSY) == 0)
615: panic("qsync: not busy");
616: for (i = 0; i < MAXQUOTAS; i++)
617: if (ump->um_quotas[i] != NULLVP)
618: break;
619: if (i == MAXQUOTAS)
620: return (0);
621: /*
622: * Search vnodes associated with this mount point,
623: * synchronizing any modified dquot structures.
624: */
625: again:
626: for (vp = mp->mnt_mounth; vp; vp = nextvp) {
627: nextvp = vp->v_mountf;
628: if (VOP_ISLOCKED(vp))
629: continue;
630: if (vget(vp))
631: goto again;
632: for (i = 0; i < MAXQUOTAS; i++) {
633: dq = VTOI(vp)->i_dquot[i];
634: if (dq != NODQUOT && (dq->dq_flags & DQ_MOD))
635: dqsync(vp, dq);
636: }
637: vput(vp);
638: if (vp->v_mountf != nextvp || vp->v_mount != mp)
639: goto again;
640: }
641: return (0);
642: }
643:
644: /*
645: * Code pertaining to management of the in-core dquot data structures.
646: */
647:
648: /*
649: * Dquot cache - hash chain headers.
650: */
651: union dqhead {
652: union dqhead *dqh_head[2];
653: struct dquot *dqh_chain[2];
654: };
655: #define dqh_forw dqh_chain[0]
656: #define dqh_back dqh_chain[1]
657:
658: union dqhead *dqhashtbl;
659: long dqhash;
660:
661: /*
662: * Dquot free list.
663: */
664: #define DQUOTINC 5 /* minimum free dquots desired */
665: struct dquot *dqfreel, **dqback = &dqfreel;
666: long numdquot, desireddquot = DQUOTINC;
667:
668: /*
669: * Initialize the quota system.
670: */
671: dqinit()
672: {
673: register union dqhead *dhp;
674: register long dqhashsize;
675:
676: dqhashsize = roundup((desiredvnodes + 1) * sizeof *dhp / 2,
677: NBPG * CLSIZE);
678: dqhashtbl = (union dqhead *)malloc(dqhashsize, M_DQUOT, M_WAITOK);
679: for (dqhash = 1; dqhash <= dqhashsize / sizeof *dhp; dqhash <<= 1)
680: /* void */;
681: dqhash = (dqhash >> 1) - 1;
682: for (dhp = &dqhashtbl[dqhash]; dhp >= dqhashtbl; dhp--) {
683: dhp->dqh_head[0] = dhp;
684: dhp->dqh_head[1] = dhp;
685: }
686: }
687:
688: /*
689: * Obtain a dquot structure for the specified identifier and quota file
690: * reading the information from the file if necessary.
691: */
692: dqget(vp, id, ump, type, dqp)
693: struct vnode *vp;
694: u_long id;
695: register struct ufsmount *ump;
696: register int type;
697: struct dquot **dqp;
698: {
699: register struct dquot *dq;
700: register union dqhead *dh;
701: register struct dquot *dp;
702: register struct vnode *dqvp;
703: struct iovec aiov;
704: struct uio auio;
705: int error;
706:
707: dqvp = ump->um_quotas[type];
708: if (dqvp == NULLVP || (ump->um_qflags[type] & QTF_CLOSING)) {
709: *dqp = NODQUOT;
710: return (EINVAL);
711: }
712: /*
713: * Check the cache first.
714: */
715: dh = &dqhashtbl[((((int)(dqvp)) >> 8) + id) & dqhash];
716: for (dq = dh->dqh_forw; dq != (struct dquot *)dh; dq = dq->dq_forw) {
717: if (dq->dq_id != id ||
718: dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
719: continue;
720: /*
721: * Cache hit with no references. Take
722: * the structure off the free list.
723: */
724: if (dq->dq_cnt == 0) {
725: dp = dq->dq_freef;
726: if (dp != NODQUOT)
727: dp->dq_freeb = dq->dq_freeb;
728: else
729: dqback = dq->dq_freeb;
730: *dq->dq_freeb = dp;
731: }
732: DQREF(dq);
733: *dqp = dq;
734: return (0);
735: }
736: /*
737: * Not in cache, allocate a new one.
738: */
739: if (dqfreel == NODQUOT && numdquot < MAXQUOTAS * desiredvnodes)
740: desireddquot += DQUOTINC;
741: if (numdquot < desireddquot) {
742: dq = (struct dquot *)malloc(sizeof *dq, M_DQUOT, M_WAITOK);
743: bzero((char *)dq, sizeof *dq);
744: numdquot++;
745: } else {
746: if ((dq = dqfreel) == NULL) {
747: tablefull("dquot");
748: *dqp = NODQUOT;
749: return (EUSERS);
750: }
751: if (dq->dq_cnt || (dq->dq_flags & DQ_MOD))
752: panic("free dquot isn't");
753: if ((dp = dq->dq_freef) != NODQUOT)
754: dp->dq_freeb = &dqfreel;
755: else
756: dqback = &dqfreel;
757: dqfreel = dp;
758: dq->dq_freef = NULL;
759: dq->dq_freeb = NULL;
760: remque(dq);
761: }
762: /*
763: * Initialize the contents of the dquot structure.
764: */
765: if (vp != dqvp)
766: VOP_LOCK(dqvp);
767: insque(dq, dh);
768: DQREF(dq);
769: dq->dq_flags = DQ_LOCK;
770: dq->dq_id = id;
771: dq->dq_ump = ump;
772: dq->dq_type = type;
773: auio.uio_iov = &aiov;
774: auio.uio_iovcnt = 1;
775: aiov.iov_base = (caddr_t)&dq->dq_dqb;
776: aiov.iov_len = sizeof (struct dqblk);
777: auio.uio_resid = sizeof (struct dqblk);
778: auio.uio_offset = (off_t)(id * sizeof (struct dqblk));
779: auio.uio_segflg = UIO_SYSSPACE;
780: auio.uio_rw = UIO_READ;
781: auio.uio_procp = (struct proc *)0;
782: error = VOP_READ(dqvp, &auio, 0, ump->um_cred[type]);
783: if (auio.uio_resid == sizeof(struct dqblk) && error == 0)
784: bzero((caddr_t)&dq->dq_dqb, sizeof(struct dqblk));
785: if (vp != dqvp)
786: VOP_UNLOCK(dqvp);
787: if (dq->dq_flags & DQ_WANT)
788: wakeup((caddr_t)dq);
789: dq->dq_flags = 0;
790: /*
791: * I/O error in reading quota file, release
792: * quota structure and reflect problem to caller.
793: */
794: if (error) {
795: remque(dq);
796: dq->dq_forw = dq; /* on a private, unfindable hash list */
797: dq->dq_back = dq;
798: dqrele(vp, dq);
799: *dqp = NODQUOT;
800: return (error);
801: }
802: /*
803: * Check for no limit to enforce.
804: * Initialize time values if necessary.
805: */
806: if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
807: dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
808: dq->dq_flags |= DQ_FAKE;
809: if (dq->dq_id != 0) {
810: if (dq->dq_btime == 0)
811: dq->dq_btime = time.tv_sec + ump->um_btime[type];
812: if (dq->dq_itime == 0)
813: dq->dq_itime = time.tv_sec + ump->um_itime[type];
814: }
815: *dqp = dq;
816: return (0);
817: }
818:
819: /*
820: * Obtain a reference to a dquot.
821: */
822: dqref(dq)
823: struct dquot *dq;
824: {
825:
826: dq->dq_cnt++;
827: }
828:
829: /*
830: * Release a reference to a dquot.
831: */
832: dqrele(vp, dq)
833: struct vnode *vp;
834: register struct dquot *dq;
835: {
836:
837: if (dq == NODQUOT)
838: return;
839: if (dq->dq_cnt > 1) {
840: dq->dq_cnt--;
841: return;
842: }
843: if (dq->dq_flags & DQ_MOD)
844: (void) dqsync(vp, dq);
845: if (--dq->dq_cnt > 0)
846: return;
847: if (dqfreel != NODQUOT) {
848: *dqback = dq;
849: dq->dq_freeb = dqback;
850: } else {
851: dqfreel = dq;
852: dq->dq_freeb = &dqfreel;
853: }
854: dq->dq_freef = NODQUOT;
855: dqback = &dq->dq_freef;
856: }
857:
858: /*
859: * Update the disk quota in the quota file.
860: */
861: dqsync(vp, dq)
862: struct vnode *vp;
863: register struct dquot *dq;
864: {
865: struct vnode *dqvp;
866: struct iovec aiov;
867: struct uio auio;
868: int error;
869:
870: if (dq == NODQUOT)
871: panic("dqsync: dquot");
872: if ((dq->dq_flags & DQ_MOD) == 0)
873: return (0);
874: if ((dqvp = dq->dq_ump->um_quotas[dq->dq_type]) == NULLVP)
875: panic("dqsync: file");
876: if (vp != dqvp)
877: VOP_LOCK(dqvp);
878: while (dq->dq_flags & DQ_LOCK) {
879: dq->dq_flags |= DQ_WANT;
1.1.1.2 ! root 880: tsleep((caddr_t)dq, PINOD+2, "dqsync", 0);
1.1 root 881: if ((dq->dq_flags & DQ_MOD) == 0) {
882: if (vp != dqvp)
883: VOP_UNLOCK(dqvp);
884: return (0);
885: }
886: }
887: dq->dq_flags |= DQ_LOCK;
888: auio.uio_iov = &aiov;
889: auio.uio_iovcnt = 1;
890: aiov.iov_base = (caddr_t)&dq->dq_dqb;
891: aiov.iov_len = sizeof (struct dqblk);
892: auio.uio_resid = sizeof (struct dqblk);
893: auio.uio_offset = (off_t)(dq->dq_id * sizeof (struct dqblk));
894: auio.uio_segflg = UIO_SYSSPACE;
895: auio.uio_rw = UIO_WRITE;
896: auio.uio_procp = (struct proc *)0;
897: error = VOP_WRITE(dqvp, &auio, 0, dq->dq_ump->um_cred[dq->dq_type]);
898: if (auio.uio_resid && error == 0)
899: error = EIO;
900: if (dq->dq_flags & DQ_WANT)
901: wakeup((caddr_t)dq);
902: dq->dq_flags &= ~(DQ_MOD|DQ_LOCK|DQ_WANT);
903: if (vp != dqvp)
904: VOP_UNLOCK(dqvp);
905: return (error);
906: }
907:
908: /*
909: * Flush all entries from the cache for a particular vnode.
910: */
911: dqflush(vp)
912: register struct vnode *vp;
913: {
914: register union dqhead *dh;
915: register struct dquot *dq, *nextdq;
916:
917: /*
918: * Move all dquot's that used to refer to this quota
919: * file off their hash chains (they will eventually
920: * fall off the head of the free list and be re-used).
921: */
922: for (dh = &dqhashtbl[dqhash]; dh >= dqhashtbl; dh--) {
923: for (dq = dh->dqh_forw; dq != (struct dquot *)dh; dq = nextdq) {
924: nextdq = dq->dq_forw;
925: if (dq->dq_ump->um_quotas[dq->dq_type] != vp)
926: continue;
927: if (dq->dq_cnt)
928: panic("dqflush: stray dquot");
929: remque(dq);
930: dq->dq_forw = dq;
931: dq->dq_back = dq;
932: dq->dq_ump = (struct ufsmount *)0;
933: }
934: }
935: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.