1 /* $NetBSD: ulfs_quota1.c,v 1.9 2015/07/26 08:33:53 hannken Exp $ */
2 /* from NetBSD: ufs_quota1.c,v 1.18 2012/02/02 03:00:48 matt Exp */
5 * Copyright (c) 1982, 1986, 1990, 1993, 1995
6 * The Regents of the University of California. All rights reserved.
8 * This code is derived from software contributed to Berkeley by
9 * Robert Elz at The University of Melbourne.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: ulfs_quota1.c,v 1.9 2015/07/26 08:33:53 hannken Exp $");
41 #include <sys/param.h>
42 #include <sys/kernel.h>
43 #include <sys/systm.h>
44 #include <sys/namei.h>
47 #include <sys/vnode.h>
48 #include <sys/mount.h>
49 #include <sys/kauth.h>
51 #include <ufs/lfs/ulfs_quota1.h>
52 #include <ufs/lfs/ulfs_inode.h>
53 #include <ufs/lfs/ulfsmount.h>
54 #include <ufs/lfs/ulfs_extern.h>
55 #include <ufs/lfs/ulfs_quota.h>
57 static int chkdqchg(struct inode
*, int64_t, kauth_cred_t
, int);
58 static int chkiqchg(struct inode
*, int32_t, kauth_cred_t
, int);
61 * Update disk usage, and take corrective action.
64 lfs_chkdq1(struct inode
*ip
, int64_t change
, kauth_cred_t cred
, int flags
)
68 int ncurblocks
, error
;
70 if ((error
= lfs_getinoquota(ip
)) != 0)
75 for (i
= 0; i
< ULFS_MAXQUOTAS
; i
++) {
76 if ((dq
= ip
->i_dquot
[i
]) == NODQUOT
)
78 mutex_enter(&dq
->dq_interlock
);
79 ncurblocks
= dq
->dq_curblocks
+ change
;
81 dq
->dq_curblocks
= ncurblocks
;
84 dq
->dq_flags
&= ~DQ_WARN(QL_BLOCK
);
85 dq
->dq_flags
|= DQ_MOD
;
86 mutex_exit(&dq
->dq_interlock
);
90 for (i
= 0; i
< ULFS_MAXQUOTAS
; i
++) {
91 if ((dq
= ip
->i_dquot
[i
]) == NODQUOT
)
93 if ((flags
& FORCE
) == 0 &&
94 kauth_authorize_system(cred
, KAUTH_SYSTEM_FS_QUOTA
,
95 KAUTH_REQ_SYSTEM_FS_QUOTA_NOLIMIT
, KAUTH_ARG(i
),
96 KAUTH_ARG(QL_BLOCK
), NULL
) != 0) {
97 mutex_enter(&dq
->dq_interlock
);
98 error
= chkdqchg(ip
, change
, cred
, i
);
99 mutex_exit(&dq
->dq_interlock
);
104 for (i
= 0; i
< ULFS_MAXQUOTAS
; i
++) {
105 if ((dq
= ip
->i_dquot
[i
]) == NODQUOT
)
107 mutex_enter(&dq
->dq_interlock
);
108 dq
->dq_curblocks
+= change
;
109 dq
->dq_flags
|= DQ_MOD
;
110 mutex_exit(&dq
->dq_interlock
);
116 * Check for a valid change to a users allocation.
117 * Issue an error message if appropriate.
120 chkdqchg(struct inode
*ip
, int64_t change
, kauth_cred_t cred
, int type
)
122 struct dquot
*dq
= ip
->i_dquot
[type
];
123 long ncurblocks
= dq
->dq_curblocks
+ change
;
125 KASSERT(mutex_owned(&dq
->dq_interlock
));
127 * If user would exceed their hard limit, disallow space allocation.
129 if (ncurblocks
>= dq
->dq_bhardlimit
&& dq
->dq_bhardlimit
) {
130 if ((dq
->dq_flags
& DQ_WARN(QL_BLOCK
)) == 0 &&
131 ip
->i_uid
== kauth_cred_geteuid(cred
)) {
132 uprintf("\n%s: write failed, %s disk limit reached\n",
133 ITOV(ip
)->v_mount
->mnt_stat
.f_mntonname
,
134 lfs_quotatypes
[type
]);
135 dq
->dq_flags
|= DQ_WARN(QL_BLOCK
);
140 * If user is over their soft limit for too long, disallow space
141 * allocation. Reset time limit as they cross their soft limit.
143 if (ncurblocks
>= dq
->dq_bsoftlimit
&& dq
->dq_bsoftlimit
) {
144 if (dq
->dq_curblocks
< dq
->dq_bsoftlimit
) {
146 time_second
+ ip
->i_ump
->umq1_btime
[type
];
147 if (ip
->i_uid
== kauth_cred_geteuid(cred
))
148 uprintf("\n%s: warning, %s %s\n",
149 ITOV(ip
)->v_mount
->mnt_stat
.f_mntonname
,
150 lfs_quotatypes
[type
], "disk quota exceeded");
153 if (time_second
> dq
->dq_btime
) {
154 if ((dq
->dq_flags
& DQ_WARN(QL_BLOCK
)) == 0 &&
155 ip
->i_uid
== kauth_cred_geteuid(cred
)) {
156 uprintf("\n%s: write failed, %s %s\n",
157 ITOV(ip
)->v_mount
->mnt_stat
.f_mntonname
,
158 lfs_quotatypes
[type
],
159 "disk quota exceeded for too long");
160 dq
->dq_flags
|= DQ_WARN(QL_BLOCK
);
169 * Check the inode limit, applying corrective action.
172 lfs_chkiq1(struct inode
*ip
, int32_t change
, kauth_cred_t cred
, int flags
)
176 int ncurinodes
, error
;
178 if ((error
= lfs_getinoquota(ip
)) != 0)
183 for (i
= 0; i
< ULFS_MAXQUOTAS
; i
++) {
184 if ((dq
= ip
->i_dquot
[i
]) == NODQUOT
)
186 mutex_enter(&dq
->dq_interlock
);
187 ncurinodes
= dq
->dq_curinodes
+ change
;
189 dq
->dq_curinodes
= ncurinodes
;
191 dq
->dq_curinodes
= 0;
192 dq
->dq_flags
&= ~DQ_WARN(QL_FILE
);
193 dq
->dq_flags
|= DQ_MOD
;
194 mutex_exit(&dq
->dq_interlock
);
198 for (i
= 0; i
< ULFS_MAXQUOTAS
; i
++) {
199 if ((dq
= ip
->i_dquot
[i
]) == NODQUOT
)
201 if ((flags
& FORCE
) == 0 && kauth_authorize_system(cred
,
202 KAUTH_SYSTEM_FS_QUOTA
, KAUTH_REQ_SYSTEM_FS_QUOTA_NOLIMIT
,
203 KAUTH_ARG(i
), KAUTH_ARG(QL_FILE
), NULL
) != 0) {
204 mutex_enter(&dq
->dq_interlock
);
205 error
= chkiqchg(ip
, change
, cred
, i
);
206 mutex_exit(&dq
->dq_interlock
);
211 for (i
= 0; i
< ULFS_MAXQUOTAS
; i
++) {
212 if ((dq
= ip
->i_dquot
[i
]) == NODQUOT
)
214 mutex_enter(&dq
->dq_interlock
);
215 dq
->dq_curinodes
+= change
;
216 dq
->dq_flags
|= DQ_MOD
;
217 mutex_exit(&dq
->dq_interlock
);
223 * Check for a valid change to a users allocation.
224 * Issue an error message if appropriate.
227 chkiqchg(struct inode
*ip
, int32_t change
, kauth_cred_t cred
, int type
)
229 struct dquot
*dq
= ip
->i_dquot
[type
];
230 long ncurinodes
= dq
->dq_curinodes
+ change
;
232 KASSERT(mutex_owned(&dq
->dq_interlock
));
234 * If user would exceed their hard limit, disallow inode allocation.
236 if (ncurinodes
>= dq
->dq_ihardlimit
&& dq
->dq_ihardlimit
) {
237 if ((dq
->dq_flags
& DQ_WARN(QL_FILE
)) == 0 &&
238 ip
->i_uid
== kauth_cred_geteuid(cred
)) {
239 uprintf("\n%s: write failed, %s inode limit reached\n",
240 ITOV(ip
)->v_mount
->mnt_stat
.f_mntonname
,
241 lfs_quotatypes
[type
]);
242 dq
->dq_flags
|= DQ_WARN(QL_FILE
);
247 * If user is over their soft limit for too long, disallow inode
248 * allocation. Reset time limit as they cross their soft limit.
250 if (ncurinodes
>= dq
->dq_isoftlimit
&& dq
->dq_isoftlimit
) {
251 if (dq
->dq_curinodes
< dq
->dq_isoftlimit
) {
253 time_second
+ ip
->i_ump
->umq1_itime
[type
];
254 if (ip
->i_uid
== kauth_cred_geteuid(cred
))
255 uprintf("\n%s: warning, %s %s\n",
256 ITOV(ip
)->v_mount
->mnt_stat
.f_mntonname
,
257 lfs_quotatypes
[type
], "inode quota exceeded");
260 if (time_second
> dq
->dq_itime
) {
261 if ((dq
->dq_flags
& DQ_WARN(QL_FILE
)) == 0 &&
262 ip
->i_uid
== kauth_cred_geteuid(cred
)) {
263 uprintf("\n%s: write failed, %s %s\n",
264 ITOV(ip
)->v_mount
->mnt_stat
.f_mntonname
,
265 lfs_quotatypes
[type
],
266 "inode quota exceeded for too long");
267 dq
->dq_flags
|= DQ_WARN(QL_FILE
);
276 lfsquota1_umount(struct mount
*mp
, int flags
)
279 struct ulfsmount
*ump
= VFSTOULFS(mp
);
280 struct lfs
*fs
= ump
->um_lfs
;
281 struct lwp
*l
= curlwp
;
283 if ((fs
->um_flags
& ULFS_QUOTA
) == 0)
286 if ((error
= vflush(mp
, NULLVP
, SKIPSYSTEM
| flags
)) != 0)
289 for (i
= 0; i
< ULFS_MAXQUOTAS
; i
++) {
290 if (ump
->um_quotas
[i
] != NULLVP
) {
291 lfsquota1_handle_cmd_quotaoff(l
, ump
, i
);
298 * Code to process quotactl commands.
302 * set up a quota file for a particular file system.
305 lfsquota1_handle_cmd_quotaon(struct lwp
*l
, struct ulfsmount
*ump
, int type
,
308 struct mount
*mp
= ump
->um_mountp
;
309 struct lfs
*fs
= ump
->um_lfs
;
310 struct vnode
*vp
, **vpp
;
311 struct vnode_iterator
*marker
;
317 if (fs
->um_flags
& ULFS_QUOTA2
) {
318 uprintf("%s: quotas v2 already enabled\n",
319 mp
->mnt_stat
.f_mntonname
);
323 vpp
= &ump
->um_quotas
[type
];
325 pb
= pathbuf_create(fname
);
329 NDINIT(&nd
, LOOKUP
, FOLLOW
, pb
);
330 if ((error
= vn_open(&nd
, FREAD
|FWRITE
, 0)) != 0) {
338 if (vp
->v_type
!= VREG
) {
339 (void) vn_close(vp
, FREAD
|FWRITE
, l
->l_cred
);
343 lfsquota1_handle_cmd_quotaoff(l
, ump
, type
);
344 mutex_enter(&lfs_dqlock
);
345 while ((ump
->umq1_qflags
[type
] & (QTF_CLOSING
| QTF_OPENING
)) != 0)
346 cv_wait(&lfs_dqcv
, &lfs_dqlock
);
347 ump
->umq1_qflags
[type
] |= QTF_OPENING
;
348 mutex_exit(&lfs_dqlock
);
349 mp
->mnt_flag
|= MNT_QUOTA
;
350 vp
->v_vflag
|= VV_SYSTEM
; /* XXXSMP */
353 * Save the credential of the process that turned on quotas.
354 * Set up the time limits for this quota.
356 kauth_cred_hold(l
->l_cred
);
357 ump
->um_cred
[type
] = l
->l_cred
;
358 ump
->umq1_btime
[type
] = MAX_DQ_TIME
;
359 ump
->umq1_itime
[type
] = MAX_IQ_TIME
;
360 if (lfs_dqget(NULLVP
, 0, ump
, type
, &dq
) == 0) {
361 if (dq
->dq_btime
> 0)
362 ump
->umq1_btime
[type
] = dq
->dq_btime
;
363 if (dq
->dq_itime
> 0)
364 ump
->umq1_itime
[type
] = dq
->dq_itime
;
365 lfs_dqrele(NULLVP
, dq
);
368 * Search vnodes associated with this mount point,
369 * adding references to quota file being opened.
370 * NB: only need to add dquot's for inodes being modified.
372 vfs_vnode_iterator_init(mp
, &marker
);
373 while ((vp
= vfs_vnode_iterator_next(marker
, NULL
, NULL
))) {
374 error
= vn_lock(vp
, LK_EXCLUSIVE
);
379 mutex_enter(vp
->v_interlock
);
380 if (VTOI(vp
) == NULL
|| vp
->v_type
== VNON
||
381 vp
->v_writecount
== 0) {
382 mutex_exit(vp
->v_interlock
);
386 mutex_exit(vp
->v_interlock
);
387 if ((error
= lfs_getinoquota(VTOI(vp
))) != 0) {
393 vfs_vnode_iterator_destroy(marker
);
395 mutex_enter(&lfs_dqlock
);
396 ump
->umq1_qflags
[type
] &= ~QTF_OPENING
;
397 cv_broadcast(&lfs_dqcv
);
399 fs
->um_flags
|= ULFS_QUOTA
;
400 mutex_exit(&lfs_dqlock
);
402 lfsquota1_handle_cmd_quotaoff(l
, ump
, type
);
407 * turn off disk quotas for a filesystem.
410 lfsquota1_handle_cmd_quotaoff(struct lwp
*l
, struct ulfsmount
*ump
, int type
)
412 struct mount
*mp
= ump
->um_mountp
;
413 struct lfs
*fs
= ump
->um_lfs
;
416 struct vnode_iterator
*marker
;
422 mutex_enter(&lfs_dqlock
);
423 while ((ump
->umq1_qflags
[type
] & (QTF_CLOSING
| QTF_OPENING
)) != 0)
424 cv_wait(&lfs_dqcv
, &lfs_dqlock
);
425 if ((qvp
= ump
->um_quotas
[type
]) == NULLVP
) {
426 mutex_exit(&lfs_dqlock
);
429 ump
->umq1_qflags
[type
] |= QTF_CLOSING
;
430 fs
->um_flags
&= ~ULFS_QUOTA
;
431 mutex_exit(&lfs_dqlock
);
433 * Search vnodes associated with this mount point,
434 * deleting any references to quota file being closed.
436 vfs_vnode_iterator_init(mp
, &marker
);
437 while ((vp
= vfs_vnode_iterator_next(marker
, NULL
, NULL
))) {
438 error
= vn_lock(vp
, LK_EXCLUSIVE
);
444 if (ip
== NULL
|| vp
->v_type
== VNON
) {
448 dq
= ip
->i_dquot
[type
];
449 ip
->i_dquot
[type
] = NODQUOT
;
453 vfs_vnode_iterator_destroy(marker
);
457 qvp
->v_vflag
&= ~VV_SYSTEM
;
458 error
= vn_close(qvp
, FREAD
|FWRITE
, l
->l_cred
);
459 mutex_enter(&lfs_dqlock
);
460 ump
->um_quotas
[type
] = NULLVP
;
461 cred
= ump
->um_cred
[type
];
462 ump
->um_cred
[type
] = NOCRED
;
463 for (i
= 0; i
< ULFS_MAXQUOTAS
; i
++)
464 if (ump
->um_quotas
[i
] != NULLVP
)
466 ump
->umq1_qflags
[type
] &= ~QTF_CLOSING
;
467 cv_broadcast(&lfs_dqcv
);
468 mutex_exit(&lfs_dqlock
);
469 kauth_cred_free(cred
);
470 if (i
== ULFS_MAXQUOTAS
)
471 mp
->mnt_flag
&= ~MNT_QUOTA
;
476 lfsquota1_handle_cmd_get(struct ulfsmount
*ump
, const struct quotakey
*qk
,
481 struct quotaval blocks
, files
;
485 idtype
= qk
->qk_idtype
;
488 if (ump
->um_quotas
[idtype
] == NULLVP
)
491 if (id
== QUOTA_DEFAULTID
) { /* we want the grace period of id 0 */
492 if ((error
= lfs_dqget(NULLVP
, 0, ump
, idtype
, &dq
)) != 0)
496 if ((error
= lfs_dqget(NULLVP
, id
, ump
, idtype
, &dq
)) != 0)
499 lfs_dqblk_to_quotavals(&dq
->dq_un
.dq1_dqb
, &blocks
, &files
);
500 lfs_dqrele(NULLVP
, dq
);
501 if (id
== QUOTA_DEFAULTID
) {
502 if (blocks
.qv_expiretime
> 0)
503 blocks
.qv_grace
= blocks
.qv_expiretime
;
505 blocks
.qv_grace
= MAX_DQ_TIME
;
506 if (files
.qv_expiretime
> 0)
507 files
.qv_grace
= files
.qv_expiretime
;
509 files
.qv_grace
= MAX_DQ_TIME
;
512 switch (qk
->qk_objtype
) {
513 case QUOTA_OBJTYPE_BLOCKS
:
516 case QUOTA_OBJTYPE_FILES
:
527 quota1_encode_limit(uint64_t lim
)
529 if (lim
== QUOTA_NOLIMIT
|| lim
>= 0xffffffff) {
536 lfsquota1_handle_cmd_put(struct ulfsmount
*ump
, const struct quotakey
*key
,
537 const struct quotaval
*val
)
543 switch (key
->qk_idtype
) {
544 case QUOTA_IDTYPE_USER
:
545 case QUOTA_IDTYPE_GROUP
:
551 switch (key
->qk_objtype
) {
552 case QUOTA_OBJTYPE_BLOCKS
:
553 case QUOTA_OBJTYPE_FILES
:
559 if (ump
->um_quotas
[key
->qk_idtype
] == NULLVP
)
562 if (key
->qk_id
== QUOTA_DEFAULTID
) {
563 /* just update grace times */
566 if ((error
= lfs_dqget(NULLVP
, id
, ump
, key
->qk_idtype
, &dq
)) != 0)
568 mutex_enter(&dq
->dq_interlock
);
569 if (val
->qv_grace
!= QUOTA_NOTIME
) {
570 if (key
->qk_objtype
== QUOTA_OBJTYPE_BLOCKS
)
571 ump
->umq1_btime
[key
->qk_idtype
] = dq
->dq_btime
=
573 if (key
->qk_objtype
== QUOTA_OBJTYPE_FILES
)
574 ump
->umq1_itime
[key
->qk_idtype
] = dq
->dq_itime
=
577 dq
->dq_flags
|= DQ_MOD
;
578 mutex_exit(&dq
->dq_interlock
);
579 lfs_dqrele(NULLVP
, dq
);
583 if ((error
= lfs_dqget(NULLVP
, key
->qk_id
, ump
, key
->qk_idtype
, &dq
)) != 0)
585 mutex_enter(&dq
->dq_interlock
);
587 * Copy all but the current values.
588 * Reset time limit if previously had no soft limit or were
589 * under it, but now have a soft limit and are over it.
591 dqb
.dqb_curblocks
= dq
->dq_curblocks
;
592 dqb
.dqb_curinodes
= dq
->dq_curinodes
;
593 dqb
.dqb_btime
= dq
->dq_btime
;
594 dqb
.dqb_itime
= dq
->dq_itime
;
595 if (key
->qk_objtype
== QUOTA_OBJTYPE_BLOCKS
) {
596 dqb
.dqb_bsoftlimit
= quota1_encode_limit(val
->qv_softlimit
);
597 dqb
.dqb_bhardlimit
= quota1_encode_limit(val
->qv_hardlimit
);
598 dqb
.dqb_isoftlimit
= dq
->dq_isoftlimit
;
599 dqb
.dqb_ihardlimit
= dq
->dq_ihardlimit
;
601 KASSERT(key
->qk_objtype
== QUOTA_OBJTYPE_FILES
);
602 dqb
.dqb_bsoftlimit
= dq
->dq_bsoftlimit
;
603 dqb
.dqb_bhardlimit
= dq
->dq_bhardlimit
;
604 dqb
.dqb_isoftlimit
= quota1_encode_limit(val
->qv_softlimit
);
605 dqb
.dqb_ihardlimit
= quota1_encode_limit(val
->qv_hardlimit
);
607 if (dq
->dq_id
== 0 && val
->qv_grace
!= QUOTA_NOTIME
) {
608 /* also update grace time if available */
609 if (key
->qk_objtype
== QUOTA_OBJTYPE_BLOCKS
) {
610 ump
->umq1_btime
[key
->qk_idtype
] = dqb
.dqb_btime
=
613 if (key
->qk_objtype
== QUOTA_OBJTYPE_FILES
) {
614 ump
->umq1_itime
[key
->qk_idtype
] = dqb
.dqb_itime
=
618 if (dqb
.dqb_bsoftlimit
&&
619 dq
->dq_curblocks
>= dqb
.dqb_bsoftlimit
&&
620 (dq
->dq_bsoftlimit
== 0 || dq
->dq_curblocks
< dq
->dq_bsoftlimit
))
621 dqb
.dqb_btime
= time_second
+ ump
->umq1_btime
[key
->qk_idtype
];
622 if (dqb
.dqb_isoftlimit
&&
623 dq
->dq_curinodes
>= dqb
.dqb_isoftlimit
&&
624 (dq
->dq_isoftlimit
== 0 || dq
->dq_curinodes
< dq
->dq_isoftlimit
))
625 dqb
.dqb_itime
= time_second
+ ump
->umq1_itime
[key
->qk_idtype
];
626 dq
->dq_un
.dq1_dqb
= dqb
;
627 if (dq
->dq_curblocks
< dq
->dq_bsoftlimit
)
628 dq
->dq_flags
&= ~DQ_WARN(QL_BLOCK
);
629 if (dq
->dq_curinodes
< dq
->dq_isoftlimit
)
630 dq
->dq_flags
&= ~DQ_WARN(QL_FILE
);
631 if (dq
->dq_isoftlimit
== 0 && dq
->dq_bsoftlimit
== 0 &&
632 dq
->dq_ihardlimit
== 0 && dq
->dq_bhardlimit
== 0)
633 dq
->dq_flags
|= DQ_FAKE
;
635 dq
->dq_flags
&= ~DQ_FAKE
;
636 dq
->dq_flags
|= DQ_MOD
;
637 mutex_exit(&dq
->dq_interlock
);
638 lfs_dqrele(NULLVP
, dq
);
645 * Q_SETQUOTA - assign an entire dqblk structure.
648 setquota1(struct mount
*mp
, u_long id
, int type
, struct dqblk
*dqb
)
652 struct ulfsmount
*ump
= VFSTOULFS(mp
);
655 if ((error
= lfs_dqget(NULLVP
, id
, ump
, type
, &ndq
)) != 0)
658 mutex_enter(&dq
->dq_interlock
);
660 * Copy all but the current values.
661 * Reset time limit if previously had no soft limit or were
662 * under it, but now have a soft limit and are over it.
664 dqb
->dqb_curblocks
= dq
->dq_curblocks
;
665 dqb
->dqb_curinodes
= dq
->dq_curinodes
;
666 if (dq
->dq_id
!= 0) {
667 dqb
->dqb_btime
= dq
->dq_btime
;
668 dqb
->dqb_itime
= dq
->dq_itime
;
670 if (dqb
->dqb_bsoftlimit
&&
671 dq
->dq_curblocks
>= dqb
->dqb_bsoftlimit
&&
672 (dq
->dq_bsoftlimit
== 0 || dq
->dq_curblocks
< dq
->dq_bsoftlimit
))
673 dqb
->dqb_btime
= time_second
+ ump
->umq1_btime
[type
];
674 if (dqb
->dqb_isoftlimit
&&
675 dq
->dq_curinodes
>= dqb
->dqb_isoftlimit
&&
676 (dq
->dq_isoftlimit
== 0 || dq
->dq_curinodes
< dq
->dq_isoftlimit
))
677 dqb
->dqb_itime
= time_second
+ ump
->umq1_itime
[type
];
678 dq
->dq_un
.dq1_dqb
= *dqb
;
679 if (dq
->dq_curblocks
< dq
->dq_bsoftlimit
)
680 dq
->dq_flags
&= ~DQ_WARN(QL_BLOCK
);
681 if (dq
->dq_curinodes
< dq
->dq_isoftlimit
)
682 dq
->dq_flags
&= ~DQ_WARN(QL_FILE
);
683 if (dq
->dq_isoftlimit
== 0 && dq
->dq_bsoftlimit
== 0 &&
684 dq
->dq_ihardlimit
== 0 && dq
->dq_bhardlimit
== 0)
685 dq
->dq_flags
|= DQ_FAKE
;
687 dq
->dq_flags
&= ~DQ_FAKE
;
688 dq
->dq_flags
|= DQ_MOD
;
689 mutex_exit(&dq
->dq_interlock
);
690 lfs_dqrele(NULLVP
, dq
);
695 * Q_SETUSE - set current inode and block usage.
698 setuse(struct mount
*mp
, u_long id
, int type
, void *addr
)
701 struct ulfsmount
*ump
= VFSTOULFS(mp
);
706 error
= copyin(addr
, (void *)&usage
, sizeof (struct dqblk
));
709 if ((error
= lfs_dqget(NULLVP
, id
, ump
, type
, &ndq
)) != 0)
712 mutex_enter(&dq
->dq_interlock
);
714 * Reset time limit if have a soft limit and were
715 * previously under it, but are now over it.
717 if (dq
->dq_bsoftlimit
&& dq
->dq_curblocks
< dq
->dq_bsoftlimit
&&
718 usage
.dqb_curblocks
>= dq
->dq_bsoftlimit
)
719 dq
->dq_btime
= time_second
+ ump
->umq1_btime
[type
];
720 if (dq
->dq_isoftlimit
&& dq
->dq_curinodes
< dq
->dq_isoftlimit
&&
721 usage
.dqb_curinodes
>= dq
->dq_isoftlimit
)
722 dq
->dq_itime
= time_second
+ ump
->umq1_itime
[type
];
723 dq
->dq_curblocks
= usage
.dqb_curblocks
;
724 dq
->dq_curinodes
= usage
.dqb_curinodes
;
725 if (dq
->dq_curblocks
< dq
->dq_bsoftlimit
)
726 dq
->dq_flags
&= ~DQ_WARN(QL_BLOCK
);
727 if (dq
->dq_curinodes
< dq
->dq_isoftlimit
)
728 dq
->dq_flags
&= ~DQ_WARN(QL_FILE
);
729 dq
->dq_flags
|= DQ_MOD
;
730 mutex_exit(&dq
->dq_interlock
);
731 lfs_dqrele(NULLVP
, dq
);
737 * Q_SYNC - sync quota files to disk.
740 lfs_q1sync(struct mount
*mp
)
742 struct ulfsmount
*ump
= VFSTOULFS(mp
);
744 struct vnode_iterator
*marker
;
749 * Check if the mount point has any quotas.
750 * If not, simply return.
752 for (i
= 0; i
< ULFS_MAXQUOTAS
; i
++)
753 if (ump
->um_quotas
[i
] != NULLVP
)
755 if (i
== ULFS_MAXQUOTAS
)
759 * Search vnodes associated with this mount point,
760 * synchronizing any modified dquot structures.
762 vfs_vnode_iterator_init(mp
, &marker
);
763 while ((vp
= vfs_vnode_iterator_next(marker
, NULL
, NULL
))) {
764 error
= vn_lock(vp
, LK_EXCLUSIVE
);
769 if (VTOI(vp
) == NULL
|| vp
->v_type
== VNON
) {
773 for (i
= 0; i
< ULFS_MAXQUOTAS
; i
++) {
774 dq
= VTOI(vp
)->i_dquot
[i
];
777 mutex_enter(&dq
->dq_interlock
);
778 if (dq
->dq_flags
& DQ_MOD
)
780 mutex_exit(&dq
->dq_interlock
);
784 vfs_vnode_iterator_destroy(marker
);
789 * Obtain a dquot structure for the specified identifier and quota file
790 * reading the information from the file if necessary.
793 lfs_dq1get(struct vnode
*dqvp
, u_long id
, struct ulfsmount
*ump
, int type
,
800 KASSERT(mutex_owned(&dq
->dq_interlock
));
801 vn_lock(dqvp
, LK_EXCLUSIVE
| LK_RETRY
);
802 auio
.uio_iov
= &aiov
;
804 aiov
.iov_base
= (void *)&dq
->dq_un
.dq1_dqb
;
805 aiov
.iov_len
= sizeof (struct dqblk
);
806 auio
.uio_resid
= sizeof (struct dqblk
);
807 auio
.uio_offset
= (off_t
)(id
* sizeof (struct dqblk
));
808 auio
.uio_rw
= UIO_READ
;
809 UIO_SETUP_SYSSPACE(&auio
);
810 error
= VOP_READ(dqvp
, &auio
, 0, ump
->um_cred
[type
]);
811 if (auio
.uio_resid
== sizeof(struct dqblk
) && error
== 0)
812 memset((void *)&dq
->dq_un
.dq1_dqb
, 0, sizeof(struct dqblk
));
815 * I/O error in reading quota file, release
816 * quota structure and reflect problem to caller.
821 * Check for no limit to enforce.
822 * Initialize time values if necessary.
824 if (dq
->dq_isoftlimit
== 0 && dq
->dq_bsoftlimit
== 0 &&
825 dq
->dq_ihardlimit
== 0 && dq
->dq_bhardlimit
== 0)
826 dq
->dq_flags
|= DQ_FAKE
;
827 if (dq
->dq_id
!= 0) {
828 if (dq
->dq_btime
== 0)
829 dq
->dq_btime
= time_second
+ ump
->umq1_btime
[type
];
830 if (dq
->dq_itime
== 0)
831 dq
->dq_itime
= time_second
+ ump
->umq1_itime
[type
];
837 * Update the disk quota in the quota file.
840 lfs_dq1sync(struct vnode
*vp
, struct dquot
*dq
)
848 panic("dq1sync: dquot");
849 KASSERT(mutex_owned(&dq
->dq_interlock
));
850 if ((dq
->dq_flags
& DQ_MOD
) == 0)
852 if ((dqvp
= dq
->dq_ump
->um_quotas
[dq
->dq_type
]) == NULLVP
)
853 panic("dq1sync: file");
855 vn_lock(dqvp
, LK_EXCLUSIVE
| LK_RETRY
);
856 auio
.uio_iov
= &aiov
;
858 aiov
.iov_base
= (void *)&dq
->dq_un
.dq1_dqb
;
859 aiov
.iov_len
= sizeof (struct dqblk
);
860 auio
.uio_resid
= sizeof (struct dqblk
);
861 auio
.uio_offset
= (off_t
)(dq
->dq_id
* sizeof (struct dqblk
));
862 auio
.uio_rw
= UIO_WRITE
;
863 UIO_SETUP_SYSSPACE(&auio
);
864 error
= VOP_WRITE(dqvp
, &auio
, 0, dq
->dq_ump
->um_cred
[dq
->dq_type
]);
865 if (auio
.uio_resid
&& error
== 0)
867 dq
->dq_flags
&= ~DQ_MOD
;