1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 /*
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
32 * All Rights Reserved
33 *
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
36 * contributors.
37 */
38
39
40 #pragma ident "%Z%%M% %I% %E% SMI"
41
42 /*
43 * Quota system calls.
44 */
45 #include <sys/types.h>
46 #include <sys/t_lock.h>
47 #include <sys/param.h>
48 #include <sys/time.h>
49 #include <sys/systm.h>
50 #include <sys/signal.h>
51 #include <sys/cred.h>
52 #include <sys/proc.h>
53 #include <sys/user.h>
54 #include <sys/proc.h>
55 #include <sys/vfs.h>
56 #include <sys/vnode.h>
57 #include <sys/uio.h>
58 #include <sys/buf.h>
59 #include <sys/file.h>
60 #include <sys/fs/ufs_inode.h>
61 #include <sys/fs/ufs_fs.h>
62 #include <sys/fs/ufs_quota.h>
63 #include <sys/errno.h>
64 #include <sys/debug.h>
65 #include <sys/cmn_err.h>
66 #include <sys/pathname.h>
67 #include <sys/mntent.h>
68 #include <sys/policy.h>
69
70 static int opendq();
71 static int setquota();
72 static int getquota();
73 static int quotasync();
74
75 /*
76 * Quota sub-system init flag.
77 */
78 int quotas_initialized = 0;
79
80 /*
81 * Sys call to allow users to find out
82 * their current position wrt quota's
83 * and to allow privileged users to alter it.
84 */
85
86 /*ARGSUSED*/
87 int
quotactl(struct vnode * vp,intptr_t arg,int flag,struct cred * cr)88 quotactl(struct vnode *vp, intptr_t arg, int flag, struct cred *cr)
89 {
90 struct quotctl quot;
91 struct ufsvfs *ufsvfsp;
92 int error = 0;
93
94 if ((flag & DATAMODEL_MASK) == DATAMODEL_NATIVE) {
95 if (copyin((caddr_t)arg, ", sizeof (struct quotctl)))
96 return (EFAULT);
97 }
98 #ifdef _SYSCALL32_IMPL
99 else {
100 /* quotctl struct from ILP32 callers */
101 struct quotctl32 quot32;
102 if (copyin((caddr_t)arg, "32, sizeof (struct quotctl32)))
103 return (EFAULT);
104 quot.op = quot32.op;
105 quot.uid = quot32.uid;
106 quot.addr = (caddr_t)(uintptr_t)quot32.addr;
107 }
108 #endif /* _SYSCALL32_IMPL */
109
110 if (quot.uid < 0)
111 quot.uid = crgetruid(cr);
112 if (quot.op == Q_SYNC && vp == NULL) {
113 ufsvfsp = NULL;
114 } else if (quot.op != Q_ALLSYNC) {
115 ufsvfsp = (struct ufsvfs *)(vp->v_vfsp->vfs_data);
116 }
117 switch (quot.op) {
118
119 case Q_QUOTAON:
120 rw_enter(&dq_rwlock, RW_WRITER);
121 if (quotas_initialized == 0) {
122 qtinit2();
123 quotas_initialized = 1;
124 }
125 rw_exit(&dq_rwlock);
126 error = opendq(ufsvfsp, vp, cr);
127 break;
128
129 case Q_QUOTAOFF:
130 error = closedq(ufsvfsp, cr);
131 if (!error) {
132 invalidatedq(ufsvfsp);
133 }
134 break;
135
136 case Q_SETQUOTA:
137 case Q_SETQLIM:
138 error = setquota(quot.op, (uid_t)quot.uid, ufsvfsp,
139 quot.addr, cr);
140 break;
141
142 case Q_GETQUOTA:
143 error = getquota((uid_t)quot.uid, ufsvfsp, (caddr_t)quot.addr,
144 cr);
145 break;
146
147 case Q_SYNC:
148 error = qsync(ufsvfsp);
149 break;
150
151 case Q_ALLSYNC:
152 (void) qsync(NULL);
153 break;
154
155 default:
156 error = EINVAL;
157 break;
158 }
159 return (error);
160 }
161
162 static int
opendq_scan_inode(struct inode * ip,void * arg)163 opendq_scan_inode(struct inode *ip, void *arg)
164 {
165 struct ufsvfs *ufsvfsp = ip->i_ufsvfs;
166
167 /*
168 * wrong file system or this is the quota inode; keep looking
169 */
170 if (ufsvfsp != (struct ufsvfs *)arg || ip == ip->i_ufsvfs->vfs_qinod) {
171 return (0);
172 }
173
174 ASSERT(RW_WRITE_HELD(&ufsvfsp->vfs_dqrwlock));
175 rw_enter(&ip->i_contents, RW_WRITER);
176 /*
177 * This inode is in the cache (by definition), is still valid,
178 * and is not a shadow inode or extended attribute directory inode,
179 * but does not have a quota so get the quota information.
180 */
181 if (ip->i_mode && (ip->i_mode & IFMT) != IFSHAD &&
182 (ip->i_mode & IFMT) != IFATTRDIR && ip->i_dquot == NULL) {
183 ip->i_dquot = getinoquota(ip);
184 }
185 rw_exit(&ip->i_contents);
186
187 return (0);
188 }
189
190 /*
191 * Set the quota file up for a particular file system.
192 * Called as the result of a quotaon (Q_QUOTAON) ioctl.
193 */
194 static int
opendq(struct ufsvfs * ufsvfsp,struct vnode * vp,struct cred * cr)195 opendq(
196 struct ufsvfs *ufsvfsp,
197 struct vnode *vp, /* quota file */
198 struct cred *cr)
199 {
200 struct inode *qip;
201 struct dquot *dqp;
202 int error;
203 int quotaon = 0;
204
205 if (secpolicy_fs_quota(cr, ufsvfsp->vfs_vfs) != 0)
206 return (EPERM);
207
208 VN_HOLD(vp);
209
210 /*
211 * Check to be sure its a regular file.
212 */
213 if (vp->v_type != VREG) {
214 VN_RELE(vp);
215 return (EACCES);
216 }
217
218 rw_enter(&ufsvfsp->vfs_dqrwlock, RW_WRITER);
219
220 /*
221 * We have vfs_dqrwlock as writer, so if quotas are disabled,
222 * then vfs_qinod should be NULL or we have a race somewhere.
223 */
224 ASSERT((ufsvfsp->vfs_qflags & MQ_ENABLED) || (ufsvfsp->vfs_qinod == 0));
225
226 if ((ufsvfsp->vfs_qflags & MQ_ENABLED) != 0) {
227 /*
228 * Quotas are already enabled on this file system.
229 *
230 * If the "quotas" file was replaced (different inode)
231 * while quotas were enabled we don't want to re-enable
232 * them with a new "quotas" file. Simply print a warning
233 * message to the console, release the new vnode, and
234 * return.
235 * XXX - The right way to fix this is to return EBUSY
236 * for the ioctl() issued by 'quotaon'.
237 */
238 if (VTOI(vp) != ufsvfsp->vfs_qinod) {
239 cmn_err(CE_WARN, "Previous quota file still in use."
240 " Disable quotas on %s before enabling.\n",
241 VTOI(vp)->i_fs->fs_fsmnt);
242 VN_RELE(vp);
243 rw_exit(&ufsvfsp->vfs_dqrwlock);
244 return (0);
245 }
246 (void) quotasync(ufsvfsp, /* do_lock */ 0);
247 /* remove extra hold on quota file */
248 VN_RELE(vp);
249 quotaon++;
250 qip = ufsvfsp->vfs_qinod;
251 } else {
252 int qlen;
253
254 ufsvfsp->vfs_qinod = VTOI(vp);
255 qip = ufsvfsp->vfs_qinod;
256 /*
257 * Force the file to have no partially allocated blocks
258 * to prevent a realloc from changing the location of
259 * the data. We must do this even if not logging in
260 * case we later remount to logging.
261 */
262 qlen = qip->i_fs->fs_bsize * NDADDR;
263
264 /*
265 * Largefiles: i_size needs to be atomically accessed now.
266 */
267 rw_enter(&qip->i_contents, RW_WRITER);
268 if (qip->i_size < qlen) {
269 if (ufs_itrunc(qip, (u_offset_t)qlen, (int)0, cr) != 0)
270 cmn_err(CE_WARN, "opendq failed to remove frags"
271 " from quota file\n");
272 rw_exit(&qip->i_contents);
273 (void) VOP_PUTPAGE(vp, (offset_t)0, (size_t)qip->i_size,
274 B_INVAL, kcred, NULL);
275 } else {
276 rw_exit(&qip->i_contents);
277 }
278 TRANS_MATA_IGET(ufsvfsp, qip);
279 }
280
281 /*
282 * The file system time limits are in the dquot for uid 0.
283 * The time limits set the relative time the other users
284 * can be over quota for this file system.
285 * If it is zero a default is used (see quota.h).
286 */
287 error = getdiskquota((uid_t)0, ufsvfsp, 1, &dqp);
288 if (error == 0) {
289 mutex_enter(&dqp->dq_lock);
290 ufsvfsp->vfs_btimelimit =
291 (dqp->dq_btimelimit? dqp->dq_btimelimit: DQ_BTIMELIMIT);
292 ufsvfsp->vfs_ftimelimit =
293 (dqp->dq_ftimelimit? dqp->dq_ftimelimit: DQ_FTIMELIMIT);
294
295 ufsvfsp->vfs_qflags = MQ_ENABLED; /* enable quotas */
296 vfs_setmntopt(ufsvfsp->vfs_vfs, MNTOPT_QUOTA, NULL, 0);
297 dqput(dqp);
298 mutex_exit(&dqp->dq_lock);
299 } else if (!quotaon) {
300 /*
301 * Some sort of I/O error on the quota file, and quotas were
302 * not already on when we got here so clean up.
303 */
304 ufsvfsp->vfs_qflags = 0;
305 ufsvfsp->vfs_qinod = NULL;
306 VN_RELE(ITOV(qip));
307 }
308
309 /*
310 * If quotas are enabled update all valid inodes in the
311 * cache with quota information.
312 */
313 if (ufsvfsp->vfs_qflags & MQ_ENABLED) {
314 (void) ufs_scan_inodes(0, opendq_scan_inode, ufsvfsp, ufsvfsp);
315 }
316
317 rw_exit(&ufsvfsp->vfs_dqrwlock);
318 return (error);
319 }
320
321 static int
closedq_scan_inode(struct inode * ip,void * arg)322 closedq_scan_inode(struct inode *ip, void *arg)
323 {
324 struct dquot *dqp;
325 struct ufsvfs *ufsvfsp = ip->i_ufsvfs;
326
327 /*
328 * wrong file system; keep looking
329 */
330 if (ufsvfsp != (struct ufsvfs *)arg)
331 return (0);
332
333 ASSERT(RW_WRITE_HELD(&ufsvfsp->vfs_dqrwlock));
334 rw_enter(&ip->i_contents, RW_WRITER);
335
336 /*
337 * Shadow inodes and extended attribute directories
338 * do not have quota info records.
339 */
340 if ((dqp = ip->i_dquot) != NULL) {
341 ASSERT((ip->i_mode & IFMT) != IFSHAD);
342 ASSERT((ip->i_mode & IFMT) != IFATTRDIR);
343 ip->i_dquot = NULL;
344 mutex_enter(&dqp->dq_lock);
345 dqput(dqp);
346
347 /*
348 * If we have a pending logging file system quota
349 * transaction, then cancel it. Clear the flag to
350 * prevent ufs_trans_push_quota() from trying to
351 * deal with this transaction just in case it is
352 * waiting for the mutex. We decrement the counter
353 * since the transaction won't be needing the quota
354 * info record anymore.
355 */
356 if (dqp->dq_flags & DQ_TRANS) {
357 dqp->dq_flags &= ~DQ_TRANS;
358 dqput(dqp);
359 }
360 mutex_exit(&dqp->dq_lock);
361 }
362 rw_exit(&ip->i_contents);
363
364 return (0);
365 }
366
367 /*
368 * Close off disk quotas for a file system.
369 */
370 int
closedq(struct ufsvfs * ufsvfsp,struct cred * cr)371 closedq(struct ufsvfs *ufsvfsp, struct cred *cr)
372 {
373 struct inode *qip;
374
375 if (secpolicy_fs_quota(cr, ufsvfsp->vfs_vfs) != 0)
376 return (EPERM);
377
378 rw_enter(&ufsvfsp->vfs_dqrwlock, RW_WRITER);
379
380 /*
381 * Quotas are not enabled on this file system so there is
382 * nothing more to do.
383 */
384 if ((ufsvfsp->vfs_qflags & MQ_ENABLED) == 0) {
385 rw_exit(&ufsvfsp->vfs_dqrwlock);
386 return (0);
387 }
388
389 /*
390 * At this point, the quota subsystem is quiescent on this file
391 * system so we can do all the work necessary to dismantle the
392 * quota stuff.
393 */
394 qip = ufsvfsp->vfs_qinod;
395 if (!qip)
396 return (ufs_fault(ufsvfsp->vfs_root, "closedq: NULL qip"));
397
398 ufsvfsp->vfs_qflags = 0; /* disable quotas */
399 vfs_setmntopt(ufsvfsp->vfs_vfs, MNTOPT_NOQUOTA, NULL, 0);
400
401 /*
402 * ufs_scan_inodes() depends on vfs_qinod, so we can't
403 * clear it until afterwards.
404 */
405 (void) ufs_scan_inodes(0, closedq_scan_inode, ufsvfsp, ufsvfsp);
406
407 ufsvfsp->vfs_qinod = NULL;
408 rw_exit(&ufsvfsp->vfs_dqrwlock);
409
410 /*
411 * Sync and release the quota file inode. Since we have a private
412 * pointer to the quota inode and vfs_qinod is now clear we do not
413 * need to hold vfs_dqrwlock.
414 */
415 (void) TRANS_SYNCIP(qip, 0, I_SYNC, TOP_SYNCIP_CLOSEDQ);
416 VN_RELE(ITOV(qip));
417 return (0);
418 }
419
420 /*
421 * Private data between setquota() and setquota_scan_inode().
422 */
423 struct setquota_data {
424 #define SQD_TYPE_NONE 0
425 #define SQD_TYPE_LIMIT 1
426 #define SQD_TYPE_NO_LIMIT 2
427 int sqd_type;
428 struct ufsvfs *sqd_ufsvfsp;
429 uid_t sqd_uid;
430 };
431
432 static int
setquota_scan_inode(struct inode * ip,void * arg)433 setquota_scan_inode(struct inode *ip, void *arg)
434 {
435 struct setquota_data *sqdp = (struct setquota_data *)arg;
436 struct ufsvfs *ufsvfsp = ip->i_ufsvfs;
437
438 /*
439 * wrong file system; keep looking
440 */
441 if (ufsvfsp != sqdp->sqd_ufsvfsp)
442 return (0);
443
444 ASSERT(RW_WRITE_HELD(&ufsvfsp->vfs_dqrwlock));
445
446 /*
447 * The file system does not have quotas enabled or this is the
448 * file system's quota inode; keep looking.
449 */
450 if ((ufsvfsp->vfs_qflags & MQ_ENABLED) == 0 ||
451 ip == ufsvfsp->vfs_qinod) {
452 return (0);
453 }
454
455 rw_enter(&ip->i_contents, RW_WRITER);
456 /*
457 * This inode is in the cache (by definition), is still valid,
458 * is not a shadow inode or extended attribute directory inode
459 * and has the right uid.
460 */
461 if (ip->i_mode && (ip->i_mode & IFMT) != IFSHAD &&
462 (ip->i_mode & IFMT) != IFATTRDIR && ip->i_uid == sqdp->sqd_uid) {
463 /*
464 * Transition is "no limit" to "at least one limit":
465 */
466 if (sqdp->sqd_type == SQD_TYPE_LIMIT &&
467 ip->i_dquot == NULL) {
468 ip->i_dquot = getinoquota(ip);
469 }
470 /*
471 * Transition is "at least one limit" to "no limit":
472 */
473 else if (sqdp->sqd_type == SQD_TYPE_NO_LIMIT && ip->i_dquot) {
474 mutex_enter(&ip->i_dquot->dq_lock);
475 dqput(ip->i_dquot);
476 mutex_exit(&ip->i_dquot->dq_lock);
477 ip->i_dquot = NULL;
478 }
479 }
480 rw_exit(&ip->i_contents);
481
482 return (0);
483 }
484
485 /*
486 * Set various fields of the dqblk according to the command.
487 * Q_SETQUOTA - assign an entire dqblk structure.
488 * Q_SETQLIM - assign a dqblk structure except for the usage.
489 */
490 static int
setquota(int cmd,uid_t uid,struct ufsvfs * ufsvfsp,caddr_t addr,struct cred * cr)491 setquota(int cmd, uid_t uid, struct ufsvfs *ufsvfsp,
492 caddr_t addr, struct cred *cr)
493 {
494 struct dquot *dqp;
495 struct inode *qip;
496 struct dquot *xdqp;
497 struct dqblk newlim;
498 int error;
499 int scan_type = SQD_TYPE_NONE;
500 daddr_t bn;
501 int contig;
502
503 if (secpolicy_fs_quota(cr, ufsvfsp->vfs_vfs) != 0)
504 return (EPERM);
505
506 rw_enter(&ufsvfsp->vfs_dqrwlock, RW_WRITER);
507
508 /*
509 * Quotas are not enabled on this file system so there is
510 * nothing more to do.
511 */
512 if ((ufsvfsp->vfs_qflags & MQ_ENABLED) == 0) {
513 rw_exit(&ufsvfsp->vfs_dqrwlock);
514 return (ESRCH);
515 }
516
517 /*
518 * At this point, the quota subsystem is quiescent on this file
519 * system so we can do all the work necessary to modify the quota
520 * information for this user.
521 */
522
523 if (copyin(addr, (caddr_t)&newlim, sizeof (struct dqblk)) != 0) {
524 rw_exit(&ufsvfsp->vfs_dqrwlock);
525 return (EFAULT);
526 }
527 error = getdiskquota(uid, ufsvfsp, 0, &xdqp);
528 if (error) {
529 rw_exit(&ufsvfsp->vfs_dqrwlock);
530 return (error);
531 }
532 dqp = xdqp;
533 /*
534 * Don't change disk usage on Q_SETQLIM
535 */
536 mutex_enter(&dqp->dq_lock);
537 if (cmd == Q_SETQLIM) {
538 newlim.dqb_curblocks = dqp->dq_curblocks;
539 newlim.dqb_curfiles = dqp->dq_curfiles;
540 }
541 if (uid == 0) {
542 /*
543 * Timelimits for uid 0 set the relative time
544 * the other users can be over quota for this file system.
545 * If it is zero a default is used (see quota.h).
546 */
547 ufsvfsp->vfs_btimelimit =
548 newlim.dqb_btimelimit? newlim.dqb_btimelimit: DQ_BTIMELIMIT;
549 ufsvfsp->vfs_ftimelimit =
550 newlim.dqb_ftimelimit? newlim.dqb_ftimelimit: DQ_FTIMELIMIT;
551 } else {
552 if (newlim.dqb_bsoftlimit &&
553 newlim.dqb_curblocks >= newlim.dqb_bsoftlimit) {
554 if (dqp->dq_bsoftlimit == 0 ||
555 dqp->dq_curblocks < dqp->dq_bsoftlimit) {
556 /* If we're suddenly over the limit(s), */
557 /* start the timer(s) */
558 newlim.dqb_btimelimit =
559 (uint32_t)gethrestime_sec() +
560 ufsvfsp->vfs_btimelimit;
561 dqp->dq_flags &= ~DQ_BLKS;
562 } else {
563 /* If we're currently over the soft */
564 /* limit and were previously over the */
565 /* soft limit then preserve the old */
566 /* time limit but make sure the DQ_BLKS */
567 /* flag is set since we must have been */
568 /* previously warned. */
569 newlim.dqb_btimelimit = dqp->dq_btimelimit;
570 dqp->dq_flags |= DQ_BLKS;
571 }
572 } else {
573 /* Either no quota or under quota, clear time limit */
574 newlim.dqb_btimelimit = 0;
575 dqp->dq_flags &= ~DQ_BLKS;
576 }
577
578 if (newlim.dqb_fsoftlimit &&
579 newlim.dqb_curfiles >= newlim.dqb_fsoftlimit) {
580 if (dqp->dq_fsoftlimit == 0 ||
581 dqp->dq_curfiles < dqp->dq_fsoftlimit) {
582 /* If we're suddenly over the limit(s), */
583 /* start the timer(s) */
584 newlim.dqb_ftimelimit =
585 (uint32_t)gethrestime_sec() +
586 ufsvfsp->vfs_ftimelimit;
587 dqp->dq_flags &= ~DQ_FILES;
588 } else {
589 /* If we're currently over the soft */
590 /* limit and were previously over the */
591 /* soft limit then preserve the old */
592 /* time limit but make sure the */
593 /* DQ_FILES flag is set since we must */
594 /* have been previously warned. */
595 newlim.dqb_ftimelimit = dqp->dq_ftimelimit;
596 dqp->dq_flags |= DQ_FILES;
597 }
598 } else {
599 /* Either no quota or under quota, clear time limit */
600 newlim.dqb_ftimelimit = 0;
601 dqp->dq_flags &= ~DQ_FILES;
602 }
603 }
604
605 /*
606 * If there was previously no limit and there is now at least
607 * one limit, then any inodes in the cache have NULL d_iquot
608 * fields (getinoquota() returns NULL when there are no limits).
609 */
610 if ((dqp->dq_fhardlimit == 0 && dqp->dq_fsoftlimit == 0 &&
611 dqp->dq_bhardlimit == 0 && dqp->dq_bsoftlimit == 0) &&
612 (newlim.dqb_fhardlimit || newlim.dqb_fsoftlimit ||
613 newlim.dqb_bhardlimit || newlim.dqb_bsoftlimit)) {
614 scan_type = SQD_TYPE_LIMIT;
615 }
616
617 /*
618 * If there was previously at least one limit and there is now
619 * no limit, then any inodes in the cache have non-NULL d_iquot
620 * fields need to be reset to NULL.
621 */
622 else if ((dqp->dq_fhardlimit || dqp->dq_fsoftlimit ||
623 dqp->dq_bhardlimit || dqp->dq_bsoftlimit) &&
624 (newlim.dqb_fhardlimit == 0 && newlim.dqb_fsoftlimit == 0 &&
625 newlim.dqb_bhardlimit == 0 && newlim.dqb_bsoftlimit == 0)) {
626 scan_type = SQD_TYPE_NO_LIMIT;
627 }
628
629 dqp->dq_dqb = newlim;
630 dqp->dq_flags |= DQ_MOD;
631
632 /*
633 * push the new quota to disk now. If this is a trans device
634 * then force the page out with ufs_putpage so it will be deltaed
635 * by ufs_startio.
636 */
637 qip = ufsvfsp->vfs_qinod;
638 rw_enter(&qip->i_contents, RW_WRITER);
639 (void) ufs_rdwri(UIO_WRITE, FWRITE | FSYNC, qip, (caddr_t)&dqp->dq_dqb,
640 sizeof (struct dqblk), dqoff(uid), UIO_SYSSPACE,
641 (int *)NULL, kcred);
642 rw_exit(&qip->i_contents);
643
644 (void) VOP_PUTPAGE(ITOV(qip), dqoff(dqp->dq_uid) & ~qip->i_fs->fs_bmask,
645 qip->i_fs->fs_bsize, B_INVAL, kcred, NULL);
646
647 /*
648 * We must set the dq_mof even if not we are not logging in case
649 * we are later remount to logging.
650 */
651 contig = 0;
652 rw_enter(&qip->i_contents, RW_WRITER);
653 error = bmap_read(qip, dqoff(dqp->dq_uid), &bn, &contig);
654 rw_exit(&qip->i_contents);
655 if (error || (bn == UFS_HOLE)) {
656 dqp->dq_mof = UFS_HOLE;
657 } else {
658 dqp->dq_mof = ldbtob(bn) +
659 (offset_t)((dqoff(dqp->dq_uid)) & (DEV_BSIZE - 1));
660 }
661
662 dqp->dq_flags &= ~DQ_MOD;
663 dqput(dqp);
664 mutex_exit(&dqp->dq_lock);
665 if (scan_type) {
666 struct setquota_data sqd;
667
668 sqd.sqd_type = scan_type;
669 sqd.sqd_ufsvfsp = ufsvfsp;
670 sqd.sqd_uid = uid;
671 (void) ufs_scan_inodes(0, setquota_scan_inode, &sqd, ufsvfsp);
672 }
673 rw_exit(&ufsvfsp->vfs_dqrwlock);
674 return (0);
675 }
676
677 /*
678 * Q_GETQUOTA - return current values in a dqblk structure.
679 */
680 static int
getquota(uid_t uid,struct ufsvfs * ufsvfsp,caddr_t addr,cred_t * cr)681 getquota(uid_t uid, struct ufsvfs *ufsvfsp, caddr_t addr, cred_t *cr)
682 {
683 struct dquot *dqp;
684 struct dquot *xdqp;
685 struct dqblk dqb;
686 int error = 0;
687
688 if (uid != crgetruid(cr) &&
689 secpolicy_fs_quota(cr, ufsvfsp->vfs_vfs) != 0)
690 return (EPERM);
691 rw_enter(&ufsvfsp->vfs_dqrwlock, RW_READER);
692 if ((ufsvfsp->vfs_qflags & MQ_ENABLED) == 0) {
693 rw_exit(&ufsvfsp->vfs_dqrwlock);
694 return (ESRCH);
695 }
696 error = getdiskquota(uid, ufsvfsp, 0, &xdqp);
697 if (error) {
698 rw_exit(&ufsvfsp->vfs_dqrwlock);
699 return (error);
700 }
701 dqp = xdqp;
702 mutex_enter(&dqp->dq_lock);
703 if (dqp->dq_fhardlimit == 0 && dqp->dq_fsoftlimit == 0 &&
704 dqp->dq_bhardlimit == 0 && dqp->dq_bsoftlimit == 0) {
705 error = ESRCH;
706 } else {
707 bcopy(&dqp->dq_dqb, &dqb, sizeof (struct dqblk));
708 }
709 dqput(dqp);
710 mutex_exit(&dqp->dq_lock);
711 rw_exit(&ufsvfsp->vfs_dqrwlock);
712 if (error == 0 && copyout(&dqb, addr, sizeof (struct dqblk)) != 0)
713 error = EFAULT;
714 return (error);
715 }
716
717 /*
718 * Q_SYNC - sync quota files to disk.
719 */
720 int
qsync(struct ufsvfs * ufsvfsp)721 qsync(struct ufsvfs *ufsvfsp)
722 {
723 return (quotasync(ufsvfsp, /* do_lock */ 1));
724 }
725
726 /*
727 * Sync quota information records to disk for the specified file system
728 * or all file systems with quotas if ufsvfsp == NULL. Grabs a reader
729 * lock on vfs_dqrwlock if it is needed.
730 *
731 * Currently, if ufsvfsp is NULL, then do_lock is always true, but the
732 * routine is coded to account for either do_lock value. This seemed
733 * to be the safer thing to do.
734 */
735 int
quotasync(struct ufsvfs * ufsvfsp,int do_lock)736 quotasync(struct ufsvfs *ufsvfsp, int do_lock)
737 {
738 struct dquot *dqp;
739
740 rw_enter(&dq_rwlock, RW_READER);
741 if (!quotas_initialized) {
742 rw_exit(&dq_rwlock);
743 return (ESRCH);
744 }
745 rw_exit(&dq_rwlock);
746
747 /*
748 * The operation applies to a specific file system only.
749 */
750 if (ufsvfsp) {
751 if (do_lock) {
752 rw_enter(&ufsvfsp->vfs_dqrwlock, RW_READER);
753 }
754
755 /*
756 * Quotas are not enabled on this file system so bail.
757 */
758 if ((ufsvfsp->vfs_qflags & MQ_ENABLED) == 0) {
759 if (do_lock) {
760 rw_exit(&ufsvfsp->vfs_dqrwlock);
761 }
762 return (ESRCH);
763 }
764
765 /*
766 * This operation is a no-op on a logging file system because
767 * quota information is treated as metadata and is in the log.
768 * This code path treats quota information as user data which
769 * is not necessary on a logging file system.
770 */
771 if (TRANS_ISTRANS(ufsvfsp)) {
772 if (do_lock) {
773 rw_exit(&ufsvfsp->vfs_dqrwlock);
774 }
775 return (0);
776 }
777
778 /*
779 * Try to sync all the quota info records for this
780 * file system:
781 */
782 for (dqp = dquot; dqp < dquotNDQUOT; dqp++) {
783 /*
784 * If someone else has it, then ignore it.
785 */
786 if (!mutex_tryenter(&dqp->dq_lock)) {
787 continue;
788 }
789
790 /*
791 * The quota info record is for this file system
792 * and it has changes.
793 */
794 if (dqp->dq_ufsvfsp == ufsvfsp &&
795 (dqp->dq_flags & DQ_MOD)) {
796 ASSERT(ufsvfsp->vfs_qflags & MQ_ENABLED);
797 dqupdate(dqp);
798 }
799
800 mutex_exit(&dqp->dq_lock);
801 }
802 if (do_lock) {
803 rw_exit(&ufsvfsp->vfs_dqrwlock);
804 }
805
806 return (0);
807 }
808
809 /*
810 * Try to sync all the quota info records for *all* file systems
811 * for which quotas are enabled.
812 */
813 for (dqp = dquot; dqp < dquotNDQUOT; dqp++) {
814 /*
815 * If someone else has it, then ignore it.
816 */
817 if (!mutex_tryenter(&dqp->dq_lock)) {
818 continue;
819 }
820
821 ufsvfsp = dqp->dq_ufsvfsp; /* shorthand */
822
823 /*
824 * This quota info record has no changes or is
825 * not a valid quota info record yet.
826 */
827 if ((dqp->dq_flags & DQ_MOD) == 0 || ufsvfsp == NULL) {
828 mutex_exit(&dqp->dq_lock);
829 continue;
830 }
831
832 /*
833 * Now we have a potential lock order problem:
834 *
835 * vfs_dqrwlock > dq_lock
836 *
837 * so if we have to get vfs_dqrwlock, then go thru hoops
838 * to avoid deadlock. If we cannot get the order right,
839 * then we ignore this quota info record.
840 */
841 if (do_lock) {
842 /*
843 * If we can't grab vfs_dqrwlock, then we don't
844 * want to wait to avoid deadlock.
845 */
846 if (rw_tryenter(&ufsvfsp->vfs_dqrwlock,
847 RW_READER) == 0) {
848 mutex_exit(&dqp->dq_lock);
849 continue;
850 }
851 /*
852 * Okay, now we have both dq_lock and vfs_dqrwlock.
853 * We should not deadlock for the following reasons:
854 * - If another thread has a reader lock on
855 * vfs_dqrwlock and is waiting for dq_lock,
856 * there is no conflict because we can also have
857 * a reader lock on vfs_dqrwlock.
858 * - If another thread has a writer lock on
859 * vfs_dqrwlock and is waiting for dq_lock,
860 * we would have failed the rw_tryenter() above
861 * and given up dq_lock.
862 * - Since we have dq_lock another thread cannot
863 * have it and be waiting for vfs_dqrwlock.
864 */
865 }
866
867 /*
868 * Since we got to this file system via a quota info
869 * record and we have vfs_dqrwlock this is paranoia
870 * to make sure that quotas are enabled.
871 */
872 ASSERT(ufsvfsp->vfs_qflags & MQ_ENABLED);
873
874 /*
875 * We are not logging. See above logging file system
876 * comment.
877 */
878 if (!TRANS_ISTRANS(ufsvfsp)) {
879 dqupdate(dqp);
880 }
881
882 /*
883 * Since we have a private copy of dqp->dq_ufsvfsp,
884 * we can drop dq_lock now.
885 */
886 mutex_exit(&dqp->dq_lock);
887
888 if (do_lock) {
889 rw_exit(&ufsvfsp->vfs_dqrwlock);
890 }
891 }
892
893 return (0);
894 }
895