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