1/* $NetBSD$ */ 2 3/* 4 * Copyright (c) 1982, 1986, 1990, 1993, 1995 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Robert Elz at The University of Melbourne. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95 35 */ 36 37#include <sys/cdefs.h> 38__KERNEL_RCSID(0, "$NetBSD$"); 39 40#if defined(_KERNEL_OPT) 41#include "opt_quota.h" 42#endif 43#include <sys/param.h> 44#include <sys/kernel.h> 45#include <sys/systm.h> 46#include <sys/namei.h> 47#include <sys/file.h> 48#include <sys/proc.h> 49#include <sys/vnode.h> 50#include <sys/mount.h> 51#include <sys/kauth.h> 52 53#include <sys/quotactl.h> 54#include <ufs/ufs/quota.h> 55#include <ufs/ufs/quota1.h> /* for INITQFNAMES; should be moved to quota.h */ 56#include <ufs/ufs/inode.h> 57#include <ufs/ufs/ufsmount.h> 58#include <ufs/ufs/ufs_extern.h> 59#include <ufs/ufs/ufs_quota.h> 60 61kmutex_t dqlock; 62kcondvar_t dqcv; 63const char *quotatypes[MAXQUOTAS] = INITQFNAMES; 64 65/* 66 * Code pertaining to management of the in-core dquot data structures. 67 */ 68#define DQHASH(dqvp, id) \ 69 (((((long)(dqvp)) >> 8) + id) & dqhash) 70static LIST_HEAD(dqhashhead, dquot) *dqhashtbl; 71static u_long dqhash; 72static pool_cache_t dquot_cache; 73 74 75static int quota_handle_cmd_stat(struct mount *, struct lwp *, 76 struct quotactl_args *args); 77static int quota_handle_cmd_idtypestat(struct mount *, struct lwp *, 78 struct quotactl_args *args); 79static int quota_handle_cmd_objtypestat(struct mount *, struct lwp *, 80 struct quotactl_args *args); 81static int quota_handle_cmd_get(struct mount *, struct lwp *, 82 struct quotactl_args *args); 83static int quota_handle_cmd_put(struct mount *, struct lwp *, 84 struct quotactl_args *args); 85static int quota_handle_cmd_cursorget(struct mount *, struct lwp *, 86 struct quotactl_args *args); 87static int quota_handle_cmd_delete(struct mount *, struct lwp *, 88 struct quotactl_args *args); 89static int quota_handle_cmd_quotaon(struct mount *, struct lwp *, 90 struct quotactl_args *args); 91static int quota_handle_cmd_quotaoff(struct mount *, struct lwp *, 92 struct quotactl_args *args); 93static int quota_handle_cmd_cursoropen(struct mount *, struct lwp *, 94 struct quotactl_args *args); 95static int quota_handle_cmd_cursorclose(struct mount *, struct lwp *, 96 struct quotactl_args *args); 97static int quota_handle_cmd_cursorskipidtype(struct mount *, struct lwp *, 98 struct quotactl_args *args); 99static int quota_handle_cmd_cursoratend(struct mount *, struct lwp *, 100 struct quotactl_args *args); 101static int quota_handle_cmd_cursorrewind(struct mount *, struct lwp *, 102 struct quotactl_args *args); 103 104/* 105 * Initialize the quota fields of an inode. 106 */ 107void 108ufsquota_init(struct inode *ip) 109{ 110 int i; 111 112 for (i = 0; i < MAXQUOTAS; i++) 113 ip->i_dquot[i] = NODQUOT; 114} 115 116/* 117 * Release the quota fields from an inode. 118 */ 119void 120ufsquota_free(struct inode *ip) 121{ 122 int i; 123 124 for (i = 0; i < MAXQUOTAS; i++) { 125 dqrele(ITOV(ip), ip->i_dquot[i]); 126 ip->i_dquot[i] = NODQUOT; 127 } 128} 129 130/* 131 * Update disk usage, and take corrective action. 132 */ 133int 134chkdq(struct inode *ip, int64_t change, kauth_cred_t cred, int flags) 135{ 136 /* do not track snapshot usage, or we will deadlock */ 137 if ((ip->i_flags & SF_SNAPSHOT) != 0) 138 return 0; 139 140#ifdef QUOTA 141 if (ip->i_ump->um_flags & UFS_QUOTA) 142 return chkdq1(ip, change, cred, flags); 143#endif 144#ifdef QUOTA2 145 if (ip->i_ump->um_flags & UFS_QUOTA2) 146 return chkdq2(ip, change, cred, flags); 147#endif 148 return 0; 149} 150 151/* 152 * Check the inode limit, applying corrective action. 153 */ 154int 155chkiq(struct inode *ip, int32_t change, kauth_cred_t cred, int flags) 156{ 157 /* do not track snapshot usage, or we will deadlock */ 158 if ((ip->i_flags & SF_SNAPSHOT) != 0) 159 return 0; 160#ifdef QUOTA 161 if (ip->i_ump->um_flags & UFS_QUOTA) 162 return chkiq1(ip, change, cred, flags); 163#endif 164#ifdef QUOTA2 165 if (ip->i_ump->um_flags & UFS_QUOTA2) 166 return chkiq2(ip, change, cred, flags); 167#endif 168 return 0; 169} 170 171int 172quota_handle_cmd(struct mount *mp, struct lwp *l, 173 struct quotactl_args *args) 174{ 175 int error = 0; 176 177 switch (args->qc_op) { 178 case QUOTACTL_STAT: 179 error = quota_handle_cmd_stat(mp, l, args); 180 break; 181 case QUOTACTL_IDTYPESTAT: 182 error = quota_handle_cmd_idtypestat(mp, l, args); 183 break; 184 case QUOTACTL_OBJTYPESTAT: 185 error = quota_handle_cmd_objtypestat(mp, l, args); 186 break; 187 case QUOTACTL_QUOTAON: 188 error = quota_handle_cmd_quotaon(mp, l, args); 189 break; 190 case QUOTACTL_QUOTAOFF: 191 error = quota_handle_cmd_quotaoff(mp, l, args); 192 break; 193 case QUOTACTL_GET: 194 error = quota_handle_cmd_get(mp, l, args); 195 break; 196 case QUOTACTL_PUT: 197 error = quota_handle_cmd_put(mp, l, args); 198 break; 199 case QUOTACTL_CURSORGET: 200 error = quota_handle_cmd_cursorget(mp, l, args); 201 break; 202 case QUOTACTL_DELETE: 203 error = quota_handle_cmd_delete(mp, l, args); 204 break; 205 case QUOTACTL_CURSOROPEN: 206 error = quota_handle_cmd_cursoropen(mp, l, args); 207 break; 208 case QUOTACTL_CURSORCLOSE: 209 error = quota_handle_cmd_cursorclose(mp, l, args); 210 break; 211 case QUOTACTL_CURSORSKIPIDTYPE: 212 error = quota_handle_cmd_cursorskipidtype(mp, l, args); 213 break; 214 case QUOTACTL_CURSORATEND: 215 error = quota_handle_cmd_cursoratend(mp, l, args); 216 break; 217 case QUOTACTL_CURSORREWIND: 218 error = quota_handle_cmd_cursorrewind(mp, l, args); 219 break; 220 default: 221 panic("Invalid quotactl operation %d\n", args->qc_op); 222 } 223 224 return error; 225} 226 227static int 228quota_handle_cmd_stat(struct mount *mp, struct lwp *l, 229 struct quotactl_args *args) 230{ 231 struct ufsmount *ump = VFSTOUFS(mp); 232 struct quotastat *info; 233 234 KASSERT(args->qc_op == QUOTACTL_STAT); 235 info = args->u.stat.qc_info; 236 237 if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) 238 return EOPNOTSUPP; 239 240#ifdef QUOTA 241 if (ump->um_flags & UFS_QUOTA) { 242 strcpy(info->qs_implname, "ufs/ffs quota v1"); 243 info->qs_numidtypes = MAXQUOTAS; 244 /* XXX no define for this */ 245 info->qs_numobjtypes = 2; 246 info->qs_restrictions = 0; 247 info->qs_restrictions |= QUOTA_RESTRICT_NEEDSQUOTACHECK; 248 info->qs_restrictions |= QUOTA_RESTRICT_UNIFORMGRACE; 249 info->qs_restrictions |= QUOTA_RESTRICT_32BIT; 250 } else 251#endif 252#ifdef QUOTA2 253 if (ump->um_flags & UFS_QUOTA2) { 254 strcpy(info->qs_implname, "ufs/ffs quota v2"); 255 info->qs_numidtypes = MAXQUOTAS; 256 info->qs_numobjtypes = N_QL; 257 info->qs_restrictions = 0; 258 } else 259#endif 260 return EOPNOTSUPP; 261 262 return 0; 263} 264 265static int 266quota_handle_cmd_idtypestat(struct mount *mp, struct lwp *l, 267 struct quotactl_args *args) 268{ 269 struct ufsmount *ump = VFSTOUFS(mp); 270 int idtype; 271 struct quotaidtypestat *info; 272 const char *name; 273 274 KASSERT(args->qc_op == QUOTACTL_IDTYPESTAT); 275 idtype = args->u.idtypestat.qc_idtype; 276 info = args->u.idtypestat.qc_info; 277 278 if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) 279 return EOPNOTSUPP; 280 281 /* 282 * These are the same for both QUOTA and QUOTA2. 283 */ 284 switch (idtype) { 285 case QUOTA_IDTYPE_USER: 286 name = "user"; 287 break; 288 case QUOTA_IDTYPE_GROUP: 289 name = "group"; 290 break; 291 default: 292 return EINVAL; 293 } 294 strlcpy(info->qis_name, name, sizeof(info->qis_name)); 295 return 0; 296} 297 298static int 299quota_handle_cmd_objtypestat(struct mount *mp, struct lwp *l, 300 struct quotactl_args *args) 301{ 302 struct ufsmount *ump = VFSTOUFS(mp); 303 int objtype; 304 struct quotaobjtypestat *info; 305 const char *name; 306 int isbytes; 307 308 KASSERT(args->qc_op == QUOTACTL_OBJTYPESTAT); 309 objtype = args->u.objtypestat.qc_objtype; 310 info = args->u.objtypestat.qc_info; 311 312 if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) 313 return EOPNOTSUPP; 314 315 /* 316 * These are the same for both QUOTA and QUOTA2. 317 */ 318 switch (objtype) { 319 case QUOTA_OBJTYPE_BLOCKS: 320 name = "block"; 321 isbytes = 1; 322 break; 323 case QUOTA_OBJTYPE_FILES: 324 name = "file"; 325 isbytes = 0; 326 break; 327 default: 328 return EINVAL; 329 } 330 strlcpy(info->qos_name, name, sizeof(info->qos_name)); 331 info->qos_isbytes = isbytes; 332 return 0; 333} 334 335/* XXX shouldn't all this be in kauth ? */ 336static int 337quota_get_auth(struct mount *mp, struct lwp *l, uid_t id) { 338 /* The user can always query about his own quota. */ 339 if (id == kauth_cred_geteuid(l->l_cred)) 340 return 0; 341 return kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, 342 KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, KAUTH_ARG(id), NULL); 343} 344 345static int 346quota_handle_cmd_get(struct mount *mp, struct lwp *l, 347 struct quotactl_args *args) 348{ 349 struct ufsmount *ump = VFSTOUFS(mp); 350 int error; 351 const struct quotakey *qk; 352 struct quotaval *qv; 353 354 KASSERT(args->qc_op == QUOTACTL_GET); 355 qk = args->u.get.qc_key; 356 qv = args->u.get.qc_val; 357 358 if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) 359 return EOPNOTSUPP; 360 361 error = quota_get_auth(mp, l, qk->qk_id); 362 if (error != 0) 363 return error; 364#ifdef QUOTA 365 if (ump->um_flags & UFS_QUOTA) { 366 error = quota1_handle_cmd_get(ump, qk, qv); 367 } else 368#endif 369#ifdef QUOTA2 370 if (ump->um_flags & UFS_QUOTA2) { 371 error = quota2_handle_cmd_get(ump, qk, qv); 372 } else 373#endif 374 panic("quota_handle_cmd_get: no support ?"); 375 376 if (error != 0) 377 return error; 378 379 return error; 380} 381 382static int 383quota_handle_cmd_put(struct mount *mp, struct lwp *l, 384 struct quotactl_args *args) 385{ 386 struct ufsmount *ump = VFSTOUFS(mp); 387 const struct quotakey *qk; 388 const struct quotaval *qv; 389 id_t kauth_id; 390 int error; 391 392 KASSERT(args->qc_op == QUOTACTL_PUT); 393 qk = args->u.put.qc_key; 394 qv = args->u.put.qc_val; 395 396 if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) 397 return EOPNOTSUPP; 398 399 kauth_id = qk->qk_id; 400 if (kauth_id == QUOTA_DEFAULTID) { 401 kauth_id = 0; 402 } 403 404 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, 405 KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(kauth_id), 406 NULL); 407 if (error != 0) { 408 return error; 409 } 410 411#ifdef QUOTA 412 if (ump->um_flags & UFS_QUOTA) 413 error = quota1_handle_cmd_put(ump, qk, qv); 414 else 415#endif 416#ifdef QUOTA2 417 if (ump->um_flags & UFS_QUOTA2) { 418 error = quota2_handle_cmd_put(ump, qk, qv); 419 } else 420#endif 421 panic("quota_handle_cmd_get: no support ?"); 422 423 if (error == ENOENT) { 424 error = 0; 425 } 426 427 return error; 428} 429 430static int 431quota_handle_cmd_delete(struct mount *mp, struct lwp *l, 432 struct quotactl_args *args) 433{ 434 struct ufsmount *ump = VFSTOUFS(mp); 435 const struct quotakey *qk; 436 id_t kauth_id; 437 int error; 438 439 KASSERT(args->qc_op == QUOTACTL_DELETE); 440 qk = args->u.delete.qc_key; 441 442 kauth_id = qk->qk_id; 443 if (kauth_id == QUOTA_DEFAULTID) { 444 kauth_id = 0; 445 } 446 447 if ((ump->um_flags & UFS_QUOTA2) == 0) 448 return EOPNOTSUPP; 449 450 /* avoid whitespace changes */ 451 { 452 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, 453 KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(kauth_id), 454 NULL); 455 if (error != 0) 456 goto err; 457#ifdef QUOTA2 458 if (ump->um_flags & UFS_QUOTA2) { 459 error = quota2_handle_cmd_delete(ump, qk); 460 } else 461#endif 462 panic("quota_handle_cmd_get: no support ?"); 463 464 if (error && error != ENOENT) 465 goto err; 466 } 467 468 return 0; 469 err: 470 return error; 471} 472 473static int 474quota_handle_cmd_cursorget(struct mount *mp, struct lwp *l, 475 struct quotactl_args *args) 476{ 477 struct ufsmount *ump = VFSTOUFS(mp); 478 struct quotakcursor *cursor; 479 struct quotakey *keys; 480 struct quotaval *vals; 481 unsigned maxnum; 482 unsigned *ret; 483 int error; 484 485 KASSERT(args->qc_op == QUOTACTL_CURSORGET); 486 cursor = args->u.cursorget.qc_cursor; 487 keys = args->u.cursorget.qc_keys; 488 vals = args->u.cursorget.qc_vals; 489 maxnum = args->u.cursorget.qc_maxnum; 490 ret = args->u.cursorget.qc_ret; 491 492 if ((ump->um_flags & UFS_QUOTA2) == 0) 493 return EOPNOTSUPP; 494 495 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, 496 KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL); 497 if (error) 498 return error; 499 500#ifdef QUOTA2 501 if (ump->um_flags & UFS_QUOTA2) { 502 error = quota2_handle_cmd_cursorget(ump, cursor, keys, vals, 503 maxnum, ret); 504 } else 505#endif 506 panic("quota_handle_cmd_cursorget: no support ?"); 507 508 return error; 509} 510 511static int 512quota_handle_cmd_cursoropen(struct mount *mp, struct lwp *l, 513 struct quotactl_args *args) 514{ 515#ifdef QUOTA2 516 struct ufsmount *ump = VFSTOUFS(mp); 517#endif 518 struct quotakcursor *cursor; 519 int error; 520 521 KASSERT(args->qc_op == QUOTACTL_CURSOROPEN); 522 cursor = args->u.cursoropen.qc_cursor; 523 524 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, 525 KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL); 526 if (error) 527 return error; 528 529#ifdef QUOTA2 530 if (ump->um_flags & UFS_QUOTA2) { 531 error = quota2_handle_cmd_cursoropen(ump, cursor); 532 } else 533#endif 534 error = EOPNOTSUPP; 535 536 return error; 537} 538 539static int 540quota_handle_cmd_cursorclose(struct mount *mp, struct lwp *l, 541 struct quotactl_args *args) 542{ 543#ifdef QUOTA2 544 struct ufsmount *ump = VFSTOUFS(mp); 545#endif 546 struct quotakcursor *cursor; 547 int error; 548 549 KASSERT(args->qc_op == QUOTACTL_CURSORCLOSE); 550 cursor = args->u.cursorclose.qc_cursor; 551 552 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, 553 KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL); 554 if (error) 555 return error; 556 557#ifdef QUOTA2 558 if (ump->um_flags & UFS_QUOTA2) { 559 error = quota2_handle_cmd_cursorclose(ump, cursor); 560 } else 561#endif 562 error = EOPNOTSUPP; 563 564 return error; 565} 566 567static int 568quota_handle_cmd_cursorskipidtype(struct mount *mp, struct lwp *l, 569 struct quotactl_args *args) 570{ 571#ifdef QUOTA2 572 struct ufsmount *ump = VFSTOUFS(mp); 573#endif 574 struct quotakcursor *cursor; 575 int idtype; 576 int error; 577 578 KASSERT(args->qc_op == QUOTACTL_CURSORSKIPIDTYPE); 579 cursor = args->u.cursorskipidtype.qc_cursor; 580 idtype = args->u.cursorskipidtype.qc_idtype; 581 582#ifdef QUOTA2 583 if (ump->um_flags & UFS_QUOTA2) { 584 error = quota2_handle_cmd_cursorskipidtype(ump, cursor, idtype); 585 } else 586#endif 587 error = EOPNOTSUPP; 588 589 return error; 590} 591 592static int 593quota_handle_cmd_cursoratend(struct mount *mp, struct lwp *l, 594 struct quotactl_args *args) 595{ 596#ifdef QUOTA2 597 struct ufsmount *ump = VFSTOUFS(mp); 598#endif 599 struct quotakcursor *cursor; 600 int *ret; 601 int error; 602 603 KASSERT(args->qc_op == QUOTACTL_CURSORATEND); 604 cursor = args->u.cursoratend.qc_cursor; 605 ret = args->u.cursoratend.qc_ret; 606 607#ifdef QUOTA2 608 if (ump->um_flags & UFS_QUOTA2) { 609 error = quota2_handle_cmd_cursoratend(ump, cursor, ret); 610 } else 611#endif 612 error = EOPNOTSUPP; 613 614 return error; 615} 616 617static int 618quota_handle_cmd_cursorrewind(struct mount *mp, struct lwp *l, 619 struct quotactl_args *args) 620{ 621#ifdef QUOTA2 622 struct ufsmount *ump = VFSTOUFS(mp); 623#endif 624 struct quotakcursor *cursor; 625 int error; 626 627 KASSERT(args->qc_op == QUOTACTL_CURSORREWIND); 628 cursor = args->u.cursorrewind.qc_cursor; 629 630#ifdef QUOTA2 631 if (ump->um_flags & UFS_QUOTA2) { 632 error = quota2_handle_cmd_cursorrewind(ump, cursor); 633 } else 634#endif 635 error = EOPNOTSUPP; 636 637 return error; 638} 639 640static int 641quota_handle_cmd_quotaon(struct mount *mp, struct lwp *l, 642 struct quotactl_args *args) 643{ 644 struct ufsmount *ump = VFSTOUFS(mp); 645 int idtype; 646 const char *qfile; 647 int error; 648 649 KASSERT(args->qc_op == QUOTACTL_QUOTAON); 650 idtype = args->u.quotaon.qc_idtype; 651 qfile = args->u.quotaon.qc_quotafile; 652 653 if ((ump->um_flags & UFS_QUOTA2) != 0) 654 return EBUSY; 655 656 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, 657 KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL); 658 if (error != 0) { 659 return error; 660 } 661#ifdef QUOTA 662 error = quota1_handle_cmd_quotaon(l, ump, idtype, qfile); 663#else 664 error = EOPNOTSUPP; 665#endif 666 667 return error; 668} 669 670static int 671quota_handle_cmd_quotaoff(struct mount *mp, struct lwp *l, 672 struct quotactl_args *args) 673{ 674 struct ufsmount *ump = VFSTOUFS(mp); 675 int idtype; 676 int error; 677 678 KASSERT(args->qc_op == QUOTACTL_QUOTAOFF); 679 idtype = args->u.quotaoff.qc_idtype; 680 681 if ((ump->um_flags & UFS_QUOTA2) != 0) 682 return EOPNOTSUPP; 683 684 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, 685 KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL); 686 if (error != 0) { 687 return error; 688 } 689#ifdef QUOTA 690 error = quota1_handle_cmd_quotaoff(l, ump, idtype); 691#else 692 error = EOPNOTSUPP; 693#endif 694 695 return error; 696} 697 698/* 699 * Initialize the quota system. 700 */ 701void 702dqinit(void) 703{ 704 705 mutex_init(&dqlock, MUTEX_DEFAULT, IPL_NONE); 706 cv_init(&dqcv, "quota"); 707 dqhashtbl = hashinit(desiredvnodes, HASH_LIST, true, &dqhash); 708 dquot_cache = pool_cache_init(sizeof(struct dquot), 0, 0, 0, "ufsdq", 709 NULL, IPL_NONE, NULL, NULL, NULL); 710} 711 712void 713dqreinit(void) 714{ 715 struct dquot *dq; 716 struct dqhashhead *oldhash, *hash; 717 struct vnode *dqvp; 718 u_long oldmask, mask, hashval; 719 int i; 720 721 hash = hashinit(desiredvnodes, HASH_LIST, true, &mask); 722 mutex_enter(&dqlock); 723 oldhash = dqhashtbl; 724 oldmask = dqhash; 725 dqhashtbl = hash; 726 dqhash = mask; 727 for (i = 0; i <= oldmask; i++) { 728 while ((dq = LIST_FIRST(&oldhash[i])) != NULL) { 729 dqvp = dq->dq_ump->um_quotas[dq->dq_type]; 730 LIST_REMOVE(dq, dq_hash); 731 hashval = DQHASH(dqvp, dq->dq_id); 732 LIST_INSERT_HEAD(&dqhashtbl[hashval], dq, dq_hash); 733 } 734 } 735 mutex_exit(&dqlock); 736 hashdone(oldhash, HASH_LIST, oldmask); 737} 738 739/* 740 * Free resources held by quota system. 741 */ 742void 743dqdone(void) 744{ 745 746 pool_cache_destroy(dquot_cache); 747 hashdone(dqhashtbl, HASH_LIST, dqhash); 748 cv_destroy(&dqcv); 749 mutex_destroy(&dqlock); 750} 751 752/* 753 * Set up the quotas for an inode. 754 * 755 * This routine completely defines the semantics of quotas. 756 * If other criterion want to be used to establish quotas, the 757 * MAXQUOTAS value in quotas.h should be increased, and the 758 * additional dquots set up here. 759 */ 760int 761getinoquota(struct inode *ip) 762{ 763 struct ufsmount *ump = ip->i_ump; 764 struct vnode *vp = ITOV(ip); 765 int i, error; 766 u_int32_t ino_ids[MAXQUOTAS]; 767 768 /* 769 * To avoid deadlocks never update quotas for quota files 770 * on the same file system 771 */ 772 for (i = 0; i < MAXQUOTAS; i++) 773 if (vp == ump->um_quotas[i]) 774 return 0; 775 776 ino_ids[USRQUOTA] = ip->i_uid; 777 ino_ids[GRPQUOTA] = ip->i_gid; 778 for (i = 0; i < MAXQUOTAS; i++) { 779 /* 780 * If the file id changed the quota needs update. 781 */ 782 if (ip->i_dquot[i] != NODQUOT && 783 ip->i_dquot[i]->dq_id != ino_ids[i]) { 784 dqrele(ITOV(ip), ip->i_dquot[i]); 785 ip->i_dquot[i] = NODQUOT; 786 } 787 /* 788 * Set up the quota based on file id. 789 * ENODEV means that quotas are not enabled. 790 */ 791 if (ip->i_dquot[i] == NODQUOT && 792 (error = dqget(vp, ino_ids[i], ump, i, &ip->i_dquot[i])) && 793 error != ENODEV) 794 return (error); 795 } 796 return 0; 797} 798 799/* 800 * Obtain a dquot structure for the specified identifier and quota file 801 * reading the information from the file if necessary. 802 */ 803int 804dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type, 805 struct dquot **dqp) 806{ 807 struct dquot *dq, *ndq; 808 struct dqhashhead *dqh; 809 struct vnode *dqvp; 810 int error = 0; /* XXX gcc */ 811 812 /* Lock to see an up to date value for QTF_CLOSING. */ 813 mutex_enter(&dqlock); 814 if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) { 815 mutex_exit(&dqlock); 816 *dqp = NODQUOT; 817 return (ENODEV); 818 } 819 dqvp = ump->um_quotas[type]; 820#ifdef QUOTA 821 if (ump->um_flags & UFS_QUOTA) { 822 if (dqvp == NULLVP || (ump->umq1_qflags[type] & QTF_CLOSING)) { 823 mutex_exit(&dqlock); 824 *dqp = NODQUOT; 825 return (ENODEV); 826 } 827 } 828#endif 829#ifdef QUOTA2 830 if (ump->um_flags & UFS_QUOTA2) { 831 if (dqvp == NULLVP) { 832 mutex_exit(&dqlock); 833 *dqp = NODQUOT; 834 return (ENODEV); 835 } 836 } 837#endif 838 KASSERT(dqvp != vp); 839 /* 840 * Check the cache first. 841 */ 842 dqh = &dqhashtbl[DQHASH(dqvp, id)]; 843 LIST_FOREACH(dq, dqh, dq_hash) { 844 if (dq->dq_id != id || 845 dq->dq_ump->um_quotas[dq->dq_type] != dqvp) 846 continue; 847 KASSERT(dq->dq_cnt > 0); 848 dqref(dq); 849 mutex_exit(&dqlock); 850 *dqp = dq; 851 return (0); 852 } 853 /* 854 * Not in cache, allocate a new one. 855 */ 856 mutex_exit(&dqlock); 857 ndq = pool_cache_get(dquot_cache, PR_WAITOK); 858 /* 859 * Initialize the contents of the dquot structure. 860 */ 861 memset((char *)ndq, 0, sizeof *ndq); 862 ndq->dq_flags = 0; 863 ndq->dq_id = id; 864 ndq->dq_ump = ump; 865 ndq->dq_type = type; 866 mutex_init(&ndq->dq_interlock, MUTEX_DEFAULT, IPL_NONE); 867 mutex_enter(&dqlock); 868 dqh = &dqhashtbl[DQHASH(dqvp, id)]; 869 LIST_FOREACH(dq, dqh, dq_hash) { 870 if (dq->dq_id != id || 871 dq->dq_ump->um_quotas[dq->dq_type] != dqvp) 872 continue; 873 /* 874 * Another thread beat us allocating this dquot. 875 */ 876 KASSERT(dq->dq_cnt > 0); 877 dqref(dq); 878 mutex_exit(&dqlock); 879 mutex_destroy(&ndq->dq_interlock); 880 pool_cache_put(dquot_cache, ndq); 881 *dqp = dq; 882 return 0; 883 } 884 dq = ndq; 885 LIST_INSERT_HEAD(dqh, dq, dq_hash); 886 dqref(dq); 887 mutex_enter(&dq->dq_interlock); 888 mutex_exit(&dqlock); 889#ifdef QUOTA 890 if (ump->um_flags & UFS_QUOTA) 891 error = dq1get(dqvp, id, ump, type, dq); 892#endif 893#ifdef QUOTA2 894 if (ump->um_flags & UFS_QUOTA2) 895 error = dq2get(dqvp, id, ump, type, dq); 896#endif 897 /* 898 * I/O error in reading quota file, release 899 * quota structure and reflect problem to caller. 900 */ 901 if (error) { 902 mutex_enter(&dqlock); 903 LIST_REMOVE(dq, dq_hash); 904 mutex_exit(&dqlock); 905 mutex_exit(&dq->dq_interlock); 906 dqrele(vp, dq); 907 *dqp = NODQUOT; 908 return (error); 909 } 910 mutex_exit(&dq->dq_interlock); 911 *dqp = dq; 912 return (0); 913} 914 915/* 916 * Obtain a reference to a dquot. 917 */ 918void 919dqref(struct dquot *dq) 920{ 921 922 KASSERT(mutex_owned(&dqlock)); 923 dq->dq_cnt++; 924 KASSERT(dq->dq_cnt > 0); 925} 926 927/* 928 * Release a reference to a dquot. 929 */ 930void 931dqrele(struct vnode *vp, struct dquot *dq) 932{ 933 934 if (dq == NODQUOT) 935 return; 936 mutex_enter(&dq->dq_interlock); 937 for (;;) { 938 mutex_enter(&dqlock); 939 if (dq->dq_cnt > 1) { 940 dq->dq_cnt--; 941 mutex_exit(&dqlock); 942 mutex_exit(&dq->dq_interlock); 943 return; 944 } 945 if ((dq->dq_flags & DQ_MOD) == 0) 946 break; 947 mutex_exit(&dqlock); 948#ifdef QUOTA 949 if (dq->dq_ump->um_flags & UFS_QUOTA) 950 (void) dq1sync(vp, dq); 951#endif 952#ifdef QUOTA2 953 if (dq->dq_ump->um_flags & UFS_QUOTA2) 954 (void) dq2sync(vp, dq); 955#endif 956 } 957 KASSERT(dq->dq_cnt == 1 && (dq->dq_flags & DQ_MOD) == 0); 958 LIST_REMOVE(dq, dq_hash); 959 mutex_exit(&dqlock); 960 mutex_exit(&dq->dq_interlock); 961 mutex_destroy(&dq->dq_interlock); 962 pool_cache_put(dquot_cache, dq); 963} 964 965int 966qsync(struct mount *mp) 967{ 968 struct ufsmount *ump = VFSTOUFS(mp); 969#ifdef QUOTA 970 if (ump->um_flags & UFS_QUOTA) 971 return q1sync(mp); 972#endif 973#ifdef QUOTA2 974 if (ump->um_flags & UFS_QUOTA2) 975 return q2sync(mp); 976#endif 977 return 0; 978} 979 980#ifdef DIAGNOSTIC 981/* 982 * Check the hash chains for stray dquot's. 983 */ 984void 985dqflush(struct vnode *vp) 986{ 987 struct dquot *dq; 988 int i; 989 990 mutex_enter(&dqlock); 991 for (i = 0; i <= dqhash; i++) 992 LIST_FOREACH(dq, &dqhashtbl[i], dq_hash) 993 KASSERT(dq->dq_ump->um_quotas[dq->dq_type] != vp); 994 mutex_exit(&dqlock); 995} 996#endif 997