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