xref: /illumos-gate/usr/src/uts/common/fs/ufs/quotacalls.c (revision 2d6eb4a5)
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, &quot, 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, &quot32, 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