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