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