1 /* AFS superblock handling 2 * 3 * Copyright (c) 2002, 2007, 2018 Red Hat, Inc. All rights reserved. 4 * 5 * This software may be freely redistributed under the terms of the 6 * GNU General Public License. 7 * 8 * You should have received a copy of the GNU General Public License 9 * along with this program; if not, write to the Free Software 10 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 11 * 12 * Authors: David Howells <dhowells@redhat.com> 13 * David Woodhouse <dwmw2@infradead.org> 14 * 15 */ 16 17 #include <linux/kernel.h> 18 #include <linux/module.h> 19 #include <linux/mount.h> 20 #include <linux/init.h> 21 #include <linux/slab.h> 22 #include <linux/fs.h> 23 #include <linux/pagemap.h> 24 #include <linux/fs_parser.h> 25 #include <linux/statfs.h> 26 #include <linux/sched.h> 27 #include <linux/nsproxy.h> 28 #include <linux/magic.h> 29 #include <net/net_namespace.h> 30 #include "internal.h" 31 32 static void afs_i_init_once(void *foo); 33 static void afs_kill_super(struct super_block *sb); 34 static struct inode *afs_alloc_inode(struct super_block *sb); 35 static void afs_destroy_inode(struct inode *inode); 36 static void afs_free_inode(struct inode *inode); 37 static int afs_statfs(struct dentry *dentry, struct kstatfs *buf); 38 static int afs_show_devname(struct seq_file *m, struct dentry *root); 39 static int afs_show_options(struct seq_file *m, struct dentry *root); 40 static int afs_init_fs_context(struct fs_context *fc); 41 static const struct fs_parameter_description afs_fs_parameters; 42 43 struct file_system_type afs_fs_type = { 44 .owner = THIS_MODULE, 45 .name = "afs", 46 .init_fs_context = afs_init_fs_context, 47 .parameters = &afs_fs_parameters, 48 .kill_sb = afs_kill_super, 49 .fs_flags = FS_RENAME_DOES_D_MOVE, 50 }; 51 MODULE_ALIAS_FS("afs"); 52 53 int afs_net_id; 54 55 static const struct super_operations afs_super_ops = { 56 .statfs = afs_statfs, 57 .alloc_inode = afs_alloc_inode, 58 .drop_inode = afs_drop_inode, 59 .destroy_inode = afs_destroy_inode, 60 .free_inode = afs_free_inode, 61 .evict_inode = afs_evict_inode, 62 .show_devname = afs_show_devname, 63 .show_options = afs_show_options, 64 }; 65 66 static struct kmem_cache *afs_inode_cachep; 67 static atomic_t afs_count_active_inodes; 68 69 enum afs_param { 70 Opt_autocell, 71 Opt_dyn, 72 Opt_flock, 73 Opt_source, 74 }; 75 76 static const struct fs_parameter_spec afs_param_specs[] = { 77 fsparam_flag ("autocell", Opt_autocell), 78 fsparam_flag ("dyn", Opt_dyn), 79 fsparam_enum ("flock", Opt_flock), 80 fsparam_string("source", Opt_source), 81 {} 82 }; 83 84 static const struct fs_parameter_enum afs_param_enums[] = { 85 { Opt_flock, "local", afs_flock_mode_local }, 86 { Opt_flock, "openafs", afs_flock_mode_openafs }, 87 { Opt_flock, "strict", afs_flock_mode_strict }, 88 { Opt_flock, "write", afs_flock_mode_write }, 89 {} 90 }; 91 92 static const struct fs_parameter_description afs_fs_parameters = { 93 .name = "kAFS", 94 .specs = afs_param_specs, 95 .enums = afs_param_enums, 96 }; 97 98 /* 99 * initialise the filesystem 100 */ 101 int __init afs_fs_init(void) 102 { 103 int ret; 104 105 _enter(""); 106 107 /* create ourselves an inode cache */ 108 atomic_set(&afs_count_active_inodes, 0); 109 110 ret = -ENOMEM; 111 afs_inode_cachep = kmem_cache_create("afs_inode_cache", 112 sizeof(struct afs_vnode), 113 0, 114 SLAB_HWCACHE_ALIGN|SLAB_ACCOUNT, 115 afs_i_init_once); 116 if (!afs_inode_cachep) { 117 printk(KERN_NOTICE "kAFS: Failed to allocate inode cache\n"); 118 return ret; 119 } 120 121 /* now export our filesystem to lesser mortals */ 122 ret = register_filesystem(&afs_fs_type); 123 if (ret < 0) { 124 kmem_cache_destroy(afs_inode_cachep); 125 _leave(" = %d", ret); 126 return ret; 127 } 128 129 _leave(" = 0"); 130 return 0; 131 } 132 133 /* 134 * clean up the filesystem 135 */ 136 void afs_fs_exit(void) 137 { 138 _enter(""); 139 140 afs_mntpt_kill_timer(); 141 unregister_filesystem(&afs_fs_type); 142 143 if (atomic_read(&afs_count_active_inodes) != 0) { 144 printk("kAFS: %d active inode objects still present\n", 145 atomic_read(&afs_count_active_inodes)); 146 BUG(); 147 } 148 149 /* 150 * Make sure all delayed rcu free inodes are flushed before we 151 * destroy cache. 152 */ 153 rcu_barrier(); 154 kmem_cache_destroy(afs_inode_cachep); 155 _leave(""); 156 } 157 158 /* 159 * Display the mount device name in /proc/mounts. 160 */ 161 static int afs_show_devname(struct seq_file *m, struct dentry *root) 162 { 163 struct afs_super_info *as = AFS_FS_S(root->d_sb); 164 struct afs_volume *volume = as->volume; 165 struct afs_cell *cell = as->cell; 166 const char *suf = ""; 167 char pref = '%'; 168 169 if (as->dyn_root) { 170 seq_puts(m, "none"); 171 return 0; 172 } 173 174 switch (volume->type) { 175 case AFSVL_RWVOL: 176 break; 177 case AFSVL_ROVOL: 178 pref = '#'; 179 if (volume->type_force) 180 suf = ".readonly"; 181 break; 182 case AFSVL_BACKVOL: 183 pref = '#'; 184 suf = ".backup"; 185 break; 186 } 187 188 seq_printf(m, "%c%s:%s%s", pref, cell->name, volume->name, suf); 189 return 0; 190 } 191 192 /* 193 * Display the mount options in /proc/mounts. 194 */ 195 static int afs_show_options(struct seq_file *m, struct dentry *root) 196 { 197 struct afs_super_info *as = AFS_FS_S(root->d_sb); 198 const char *p = NULL; 199 200 if (as->dyn_root) 201 seq_puts(m, ",dyn"); 202 if (test_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(d_inode(root))->flags)) 203 seq_puts(m, ",autocell"); 204 switch (as->flock_mode) { 205 case afs_flock_mode_unset: break; 206 case afs_flock_mode_local: p = "local"; break; 207 case afs_flock_mode_openafs: p = "openafs"; break; 208 case afs_flock_mode_strict: p = "strict"; break; 209 case afs_flock_mode_write: p = "write"; break; 210 } 211 if (p) 212 seq_printf(m, ",flock=%s", p); 213 214 return 0; 215 } 216 217 /* 218 * Parse the source name to get cell name, volume name, volume type and R/W 219 * selector. 220 * 221 * This can be one of the following: 222 * "%[cell:]volume[.]" R/W volume 223 * "#[cell:]volume[.]" R/O or R/W volume (R/O parent), 224 * or R/W (R/W parent) volume 225 * "%[cell:]volume.readonly" R/O volume 226 * "#[cell:]volume.readonly" R/O volume 227 * "%[cell:]volume.backup" Backup volume 228 * "#[cell:]volume.backup" Backup volume 229 */ 230 static int afs_parse_source(struct fs_context *fc, struct fs_parameter *param) 231 { 232 struct afs_fs_context *ctx = fc->fs_private; 233 struct afs_cell *cell; 234 const char *cellname, *suffix, *name = param->string; 235 int cellnamesz; 236 237 _enter(",%s", name); 238 239 if (!name) { 240 printk(KERN_ERR "kAFS: no volume name specified\n"); 241 return -EINVAL; 242 } 243 244 if ((name[0] != '%' && name[0] != '#') || !name[1]) { 245 /* To use dynroot, we don't want to have to provide a source */ 246 if (strcmp(name, "none") == 0) { 247 ctx->no_cell = true; 248 return 0; 249 } 250 printk(KERN_ERR "kAFS: unparsable volume name\n"); 251 return -EINVAL; 252 } 253 254 /* determine the type of volume we're looking for */ 255 if (name[0] == '%') { 256 ctx->type = AFSVL_RWVOL; 257 ctx->force = true; 258 } 259 name++; 260 261 /* split the cell name out if there is one */ 262 ctx->volname = strchr(name, ':'); 263 if (ctx->volname) { 264 cellname = name; 265 cellnamesz = ctx->volname - name; 266 ctx->volname++; 267 } else { 268 ctx->volname = name; 269 cellname = NULL; 270 cellnamesz = 0; 271 } 272 273 /* the volume type is further affected by a possible suffix */ 274 suffix = strrchr(ctx->volname, '.'); 275 if (suffix) { 276 if (strcmp(suffix, ".readonly") == 0) { 277 ctx->type = AFSVL_ROVOL; 278 ctx->force = true; 279 } else if (strcmp(suffix, ".backup") == 0) { 280 ctx->type = AFSVL_BACKVOL; 281 ctx->force = true; 282 } else if (suffix[1] == 0) { 283 } else { 284 suffix = NULL; 285 } 286 } 287 288 ctx->volnamesz = suffix ? 289 suffix - ctx->volname : strlen(ctx->volname); 290 291 _debug("cell %*.*s [%p]", 292 cellnamesz, cellnamesz, cellname ?: "", ctx->cell); 293 294 /* lookup the cell record */ 295 if (cellname) { 296 cell = afs_lookup_cell(ctx->net, cellname, cellnamesz, 297 NULL, false); 298 if (IS_ERR(cell)) { 299 pr_err("kAFS: unable to lookup cell '%*.*s'\n", 300 cellnamesz, cellnamesz, cellname ?: ""); 301 return PTR_ERR(cell); 302 } 303 afs_put_cell(ctx->net, ctx->cell); 304 ctx->cell = cell; 305 } 306 307 _debug("CELL:%s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s", 308 ctx->cell->name, ctx->cell, 309 ctx->volnamesz, ctx->volnamesz, ctx->volname, 310 suffix ?: "-", ctx->type, ctx->force ? " FORCE" : ""); 311 312 fc->source = param->string; 313 param->string = NULL; 314 return 0; 315 } 316 317 /* 318 * Parse a single mount parameter. 319 */ 320 static int afs_parse_param(struct fs_context *fc, struct fs_parameter *param) 321 { 322 struct fs_parse_result result; 323 struct afs_fs_context *ctx = fc->fs_private; 324 int opt; 325 326 opt = fs_parse(fc, &afs_fs_parameters, param, &result); 327 if (opt < 0) 328 return opt; 329 330 switch (opt) { 331 case Opt_source: 332 return afs_parse_source(fc, param); 333 334 case Opt_autocell: 335 ctx->autocell = true; 336 break; 337 338 case Opt_dyn: 339 ctx->dyn_root = true; 340 break; 341 342 case Opt_flock: 343 ctx->flock_mode = result.uint_32; 344 break; 345 346 default: 347 return -EINVAL; 348 } 349 350 _leave(" = 0"); 351 return 0; 352 } 353 354 /* 355 * Validate the options, get the cell key and look up the volume. 356 */ 357 static int afs_validate_fc(struct fs_context *fc) 358 { 359 struct afs_fs_context *ctx = fc->fs_private; 360 struct afs_volume *volume; 361 struct key *key; 362 363 if (!ctx->dyn_root) { 364 if (ctx->no_cell) { 365 pr_warn("kAFS: Can only specify source 'none' with -o dyn\n"); 366 return -EINVAL; 367 } 368 369 if (!ctx->cell) { 370 pr_warn("kAFS: No cell specified\n"); 371 return -EDESTADDRREQ; 372 } 373 374 /* We try to do the mount securely. */ 375 key = afs_request_key(ctx->cell); 376 if (IS_ERR(key)) 377 return PTR_ERR(key); 378 379 ctx->key = key; 380 381 if (ctx->volume) { 382 afs_put_volume(ctx->cell, ctx->volume); 383 ctx->volume = NULL; 384 } 385 386 volume = afs_create_volume(ctx); 387 if (IS_ERR(volume)) 388 return PTR_ERR(volume); 389 390 ctx->volume = volume; 391 } 392 393 return 0; 394 } 395 396 /* 397 * check a superblock to see if it's the one we're looking for 398 */ 399 static int afs_test_super(struct super_block *sb, struct fs_context *fc) 400 { 401 struct afs_fs_context *ctx = fc->fs_private; 402 struct afs_super_info *as = AFS_FS_S(sb); 403 404 return (as->net_ns == fc->net_ns && 405 as->volume && 406 as->volume->vid == ctx->volume->vid && 407 !as->dyn_root); 408 } 409 410 static int afs_dynroot_test_super(struct super_block *sb, struct fs_context *fc) 411 { 412 struct afs_super_info *as = AFS_FS_S(sb); 413 414 return (as->net_ns == fc->net_ns && 415 as->dyn_root); 416 } 417 418 static int afs_set_super(struct super_block *sb, struct fs_context *fc) 419 { 420 return set_anon_super(sb, NULL); 421 } 422 423 /* 424 * fill in the superblock 425 */ 426 static int afs_fill_super(struct super_block *sb, struct afs_fs_context *ctx) 427 { 428 struct afs_super_info *as = AFS_FS_S(sb); 429 struct afs_iget_data iget_data; 430 struct inode *inode = NULL; 431 int ret; 432 433 _enter(""); 434 435 /* fill in the superblock */ 436 sb->s_blocksize = PAGE_SIZE; 437 sb->s_blocksize_bits = PAGE_SHIFT; 438 sb->s_magic = AFS_FS_MAGIC; 439 sb->s_op = &afs_super_ops; 440 if (!as->dyn_root) 441 sb->s_xattr = afs_xattr_handlers; 442 ret = super_setup_bdi(sb); 443 if (ret) 444 return ret; 445 sb->s_bdi->ra_pages = VM_READAHEAD_PAGES; 446 447 /* allocate the root inode and dentry */ 448 if (as->dyn_root) { 449 inode = afs_iget_pseudo_dir(sb, true); 450 sb->s_flags |= SB_RDONLY; 451 } else { 452 sprintf(sb->s_id, "%llu", as->volume->vid); 453 afs_activate_volume(as->volume); 454 iget_data.fid.vid = as->volume->vid; 455 iget_data.fid.vnode = 1; 456 iget_data.fid.vnode_hi = 0; 457 iget_data.fid.unique = 1; 458 iget_data.cb_v_break = as->volume->cb_v_break; 459 iget_data.cb_s_break = 0; 460 inode = afs_iget(sb, ctx->key, &iget_data, NULL, NULL, NULL); 461 } 462 463 if (IS_ERR(inode)) 464 return PTR_ERR(inode); 465 466 if (ctx->autocell || as->dyn_root) 467 set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags); 468 469 ret = -ENOMEM; 470 sb->s_root = d_make_root(inode); 471 if (!sb->s_root) 472 goto error; 473 474 if (as->dyn_root) { 475 sb->s_d_op = &afs_dynroot_dentry_operations; 476 ret = afs_dynroot_populate(sb); 477 if (ret < 0) 478 goto error; 479 } else { 480 sb->s_d_op = &afs_fs_dentry_operations; 481 } 482 483 _leave(" = 0"); 484 return 0; 485 486 error: 487 _leave(" = %d", ret); 488 return ret; 489 } 490 491 static struct afs_super_info *afs_alloc_sbi(struct fs_context *fc) 492 { 493 struct afs_fs_context *ctx = fc->fs_private; 494 struct afs_super_info *as; 495 496 as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL); 497 if (as) { 498 as->net_ns = get_net(fc->net_ns); 499 as->flock_mode = ctx->flock_mode; 500 if (ctx->dyn_root) { 501 as->dyn_root = true; 502 } else { 503 as->cell = afs_get_cell(ctx->cell); 504 as->volume = __afs_get_volume(ctx->volume); 505 } 506 } 507 return as; 508 } 509 510 static void afs_destroy_sbi(struct afs_super_info *as) 511 { 512 if (as) { 513 afs_put_volume(as->cell, as->volume); 514 afs_put_cell(afs_net(as->net_ns), as->cell); 515 put_net(as->net_ns); 516 kfree(as); 517 } 518 } 519 520 static void afs_kill_super(struct super_block *sb) 521 { 522 struct afs_super_info *as = AFS_FS_S(sb); 523 struct afs_net *net = afs_net(as->net_ns); 524 525 if (as->dyn_root) 526 afs_dynroot_depopulate(sb); 527 528 /* Clear the callback interests (which will do ilookup5) before 529 * deactivating the superblock. 530 */ 531 if (as->volume) 532 afs_clear_callback_interests(net, as->volume->servers); 533 kill_anon_super(sb); 534 if (as->volume) 535 afs_deactivate_volume(as->volume); 536 afs_destroy_sbi(as); 537 } 538 539 /* 540 * Get an AFS superblock and root directory. 541 */ 542 static int afs_get_tree(struct fs_context *fc) 543 { 544 struct afs_fs_context *ctx = fc->fs_private; 545 struct super_block *sb; 546 struct afs_super_info *as; 547 int ret; 548 549 ret = afs_validate_fc(fc); 550 if (ret) 551 goto error; 552 553 _enter(""); 554 555 /* allocate a superblock info record */ 556 ret = -ENOMEM; 557 as = afs_alloc_sbi(fc); 558 if (!as) 559 goto error; 560 fc->s_fs_info = as; 561 562 /* allocate a deviceless superblock */ 563 sb = sget_fc(fc, 564 as->dyn_root ? afs_dynroot_test_super : afs_test_super, 565 afs_set_super); 566 if (IS_ERR(sb)) { 567 ret = PTR_ERR(sb); 568 goto error; 569 } 570 571 if (!sb->s_root) { 572 /* initial superblock/root creation */ 573 _debug("create"); 574 ret = afs_fill_super(sb, ctx); 575 if (ret < 0) 576 goto error_sb; 577 sb->s_flags |= SB_ACTIVE; 578 } else { 579 _debug("reuse"); 580 ASSERTCMP(sb->s_flags, &, SB_ACTIVE); 581 } 582 583 fc->root = dget(sb->s_root); 584 trace_afs_get_tree(as->cell, as->volume); 585 _leave(" = 0 [%p]", sb); 586 return 0; 587 588 error_sb: 589 deactivate_locked_super(sb); 590 error: 591 _leave(" = %d", ret); 592 return ret; 593 } 594 595 static void afs_free_fc(struct fs_context *fc) 596 { 597 struct afs_fs_context *ctx = fc->fs_private; 598 599 afs_destroy_sbi(fc->s_fs_info); 600 afs_put_volume(ctx->cell, ctx->volume); 601 afs_put_cell(ctx->net, ctx->cell); 602 key_put(ctx->key); 603 kfree(ctx); 604 } 605 606 static const struct fs_context_operations afs_context_ops = { 607 .free = afs_free_fc, 608 .parse_param = afs_parse_param, 609 .get_tree = afs_get_tree, 610 }; 611 612 /* 613 * Set up the filesystem mount context. 614 */ 615 static int afs_init_fs_context(struct fs_context *fc) 616 { 617 struct afs_fs_context *ctx; 618 struct afs_cell *cell; 619 620 ctx = kzalloc(sizeof(struct afs_fs_context), GFP_KERNEL); 621 if (!ctx) 622 return -ENOMEM; 623 624 ctx->type = AFSVL_ROVOL; 625 ctx->net = afs_net(fc->net_ns); 626 627 /* Default to the workstation cell. */ 628 rcu_read_lock(); 629 cell = afs_lookup_cell_rcu(ctx->net, NULL, 0); 630 rcu_read_unlock(); 631 if (IS_ERR(cell)) 632 cell = NULL; 633 ctx->cell = cell; 634 635 fc->fs_private = ctx; 636 fc->ops = &afs_context_ops; 637 return 0; 638 } 639 640 /* 641 * Initialise an inode cache slab element prior to any use. Note that 642 * afs_alloc_inode() *must* reset anything that could incorrectly leak from one 643 * inode to another. 644 */ 645 static void afs_i_init_once(void *_vnode) 646 { 647 struct afs_vnode *vnode = _vnode; 648 649 memset(vnode, 0, sizeof(*vnode)); 650 inode_init_once(&vnode->vfs_inode); 651 mutex_init(&vnode->io_lock); 652 init_rwsem(&vnode->validate_lock); 653 spin_lock_init(&vnode->wb_lock); 654 spin_lock_init(&vnode->lock); 655 INIT_LIST_HEAD(&vnode->wb_keys); 656 INIT_LIST_HEAD(&vnode->pending_locks); 657 INIT_LIST_HEAD(&vnode->granted_locks); 658 INIT_DELAYED_WORK(&vnode->lock_work, afs_lock_work); 659 seqlock_init(&vnode->cb_lock); 660 } 661 662 /* 663 * allocate an AFS inode struct from our slab cache 664 */ 665 static struct inode *afs_alloc_inode(struct super_block *sb) 666 { 667 struct afs_vnode *vnode; 668 669 vnode = kmem_cache_alloc(afs_inode_cachep, GFP_KERNEL); 670 if (!vnode) 671 return NULL; 672 673 atomic_inc(&afs_count_active_inodes); 674 675 /* Reset anything that shouldn't leak from one inode to the next. */ 676 memset(&vnode->fid, 0, sizeof(vnode->fid)); 677 memset(&vnode->status, 0, sizeof(vnode->status)); 678 679 vnode->volume = NULL; 680 vnode->lock_key = NULL; 681 vnode->permit_cache = NULL; 682 RCU_INIT_POINTER(vnode->cb_interest, NULL); 683 #ifdef CONFIG_AFS_FSCACHE 684 vnode->cache = NULL; 685 #endif 686 687 vnode->flags = 1 << AFS_VNODE_UNSET; 688 vnode->lock_state = AFS_VNODE_LOCK_NONE; 689 690 init_rwsem(&vnode->rmdir_lock); 691 692 _leave(" = %p", &vnode->vfs_inode); 693 return &vnode->vfs_inode; 694 } 695 696 static void afs_free_inode(struct inode *inode) 697 { 698 kmem_cache_free(afs_inode_cachep, AFS_FS_I(inode)); 699 } 700 701 /* 702 * destroy an AFS inode struct 703 */ 704 static void afs_destroy_inode(struct inode *inode) 705 { 706 struct afs_vnode *vnode = AFS_FS_I(inode); 707 708 _enter("%p{%llx:%llu}", inode, vnode->fid.vid, vnode->fid.vnode); 709 710 _debug("DESTROY INODE %p", inode); 711 712 ASSERTCMP(rcu_access_pointer(vnode->cb_interest), ==, NULL); 713 714 atomic_dec(&afs_count_active_inodes); 715 } 716 717 /* 718 * return information about an AFS volume 719 */ 720 static int afs_statfs(struct dentry *dentry, struct kstatfs *buf) 721 { 722 struct afs_super_info *as = AFS_FS_S(dentry->d_sb); 723 struct afs_fs_cursor fc; 724 struct afs_volume_status vs; 725 struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry)); 726 struct key *key; 727 int ret; 728 729 buf->f_type = dentry->d_sb->s_magic; 730 buf->f_bsize = AFS_BLOCK_SIZE; 731 buf->f_namelen = AFSNAMEMAX - 1; 732 733 if (as->dyn_root) { 734 buf->f_blocks = 1; 735 buf->f_bavail = 0; 736 buf->f_bfree = 0; 737 return 0; 738 } 739 740 key = afs_request_key(vnode->volume->cell); 741 if (IS_ERR(key)) 742 return PTR_ERR(key); 743 744 ret = -ERESTARTSYS; 745 if (afs_begin_vnode_operation(&fc, vnode, key, true)) { 746 fc.flags |= AFS_FS_CURSOR_NO_VSLEEP; 747 while (afs_select_fileserver(&fc)) { 748 fc.cb_break = afs_calc_vnode_cb_break(vnode); 749 afs_fs_get_volume_status(&fc, &vs); 750 } 751 752 afs_check_for_remote_deletion(&fc, fc.vnode); 753 ret = afs_end_vnode_operation(&fc); 754 } 755 756 key_put(key); 757 758 if (ret == 0) { 759 if (vs.max_quota == 0) 760 buf->f_blocks = vs.part_max_blocks; 761 else 762 buf->f_blocks = vs.max_quota; 763 buf->f_bavail = buf->f_bfree = buf->f_blocks - vs.blocks_in_use; 764 } 765 766 return ret; 767 } 768