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_maxbytes = MAX_LFS_FILESIZE; 439 sb->s_magic = AFS_FS_MAGIC; 440 sb->s_op = &afs_super_ops; 441 if (!as->dyn_root) 442 sb->s_xattr = afs_xattr_handlers; 443 ret = super_setup_bdi(sb); 444 if (ret) 445 return ret; 446 sb->s_bdi->ra_pages = VM_READAHEAD_PAGES; 447 448 /* allocate the root inode and dentry */ 449 if (as->dyn_root) { 450 inode = afs_iget_pseudo_dir(sb, true); 451 sb->s_flags |= SB_RDONLY; 452 } else { 453 sprintf(sb->s_id, "%llu", as->volume->vid); 454 afs_activate_volume(as->volume); 455 iget_data.fid.vid = as->volume->vid; 456 iget_data.fid.vnode = 1; 457 iget_data.fid.vnode_hi = 0; 458 iget_data.fid.unique = 1; 459 iget_data.cb_v_break = as->volume->cb_v_break; 460 iget_data.cb_s_break = 0; 461 inode = afs_iget(sb, ctx->key, &iget_data, NULL, NULL, NULL); 462 } 463 464 if (IS_ERR(inode)) 465 return PTR_ERR(inode); 466 467 if (ctx->autocell || as->dyn_root) 468 set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags); 469 470 ret = -ENOMEM; 471 sb->s_root = d_make_root(inode); 472 if (!sb->s_root) 473 goto error; 474 475 if (as->dyn_root) { 476 sb->s_d_op = &afs_dynroot_dentry_operations; 477 ret = afs_dynroot_populate(sb); 478 if (ret < 0) 479 goto error; 480 } else { 481 sb->s_d_op = &afs_fs_dentry_operations; 482 } 483 484 _leave(" = 0"); 485 return 0; 486 487 error: 488 _leave(" = %d", ret); 489 return ret; 490 } 491 492 static struct afs_super_info *afs_alloc_sbi(struct fs_context *fc) 493 { 494 struct afs_fs_context *ctx = fc->fs_private; 495 struct afs_super_info *as; 496 497 as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL); 498 if (as) { 499 as->net_ns = get_net(fc->net_ns); 500 as->flock_mode = ctx->flock_mode; 501 if (ctx->dyn_root) { 502 as->dyn_root = true; 503 } else { 504 as->cell = afs_get_cell(ctx->cell); 505 as->volume = __afs_get_volume(ctx->volume); 506 } 507 } 508 return as; 509 } 510 511 static void afs_destroy_sbi(struct afs_super_info *as) 512 { 513 if (as) { 514 afs_put_volume(as->cell, as->volume); 515 afs_put_cell(afs_net(as->net_ns), as->cell); 516 put_net(as->net_ns); 517 kfree(as); 518 } 519 } 520 521 static void afs_kill_super(struct super_block *sb) 522 { 523 struct afs_super_info *as = AFS_FS_S(sb); 524 struct afs_net *net = afs_net(as->net_ns); 525 526 if (as->dyn_root) 527 afs_dynroot_depopulate(sb); 528 529 /* Clear the callback interests (which will do ilookup5) before 530 * deactivating the superblock. 531 */ 532 if (as->volume) 533 afs_clear_callback_interests(net, as->volume->servers); 534 kill_anon_super(sb); 535 if (as->volume) 536 afs_deactivate_volume(as->volume); 537 afs_destroy_sbi(as); 538 } 539 540 /* 541 * Get an AFS superblock and root directory. 542 */ 543 static int afs_get_tree(struct fs_context *fc) 544 { 545 struct afs_fs_context *ctx = fc->fs_private; 546 struct super_block *sb; 547 struct afs_super_info *as; 548 int ret; 549 550 ret = afs_validate_fc(fc); 551 if (ret) 552 goto error; 553 554 _enter(""); 555 556 /* allocate a superblock info record */ 557 ret = -ENOMEM; 558 as = afs_alloc_sbi(fc); 559 if (!as) 560 goto error; 561 fc->s_fs_info = as; 562 563 /* allocate a deviceless superblock */ 564 sb = sget_fc(fc, 565 as->dyn_root ? afs_dynroot_test_super : afs_test_super, 566 afs_set_super); 567 if (IS_ERR(sb)) { 568 ret = PTR_ERR(sb); 569 goto error; 570 } 571 572 if (!sb->s_root) { 573 /* initial superblock/root creation */ 574 _debug("create"); 575 ret = afs_fill_super(sb, ctx); 576 if (ret < 0) 577 goto error_sb; 578 sb->s_flags |= SB_ACTIVE; 579 } else { 580 _debug("reuse"); 581 ASSERTCMP(sb->s_flags, &, SB_ACTIVE); 582 } 583 584 fc->root = dget(sb->s_root); 585 trace_afs_get_tree(as->cell, as->volume); 586 _leave(" = 0 [%p]", sb); 587 return 0; 588 589 error_sb: 590 deactivate_locked_super(sb); 591 error: 592 _leave(" = %d", ret); 593 return ret; 594 } 595 596 static void afs_free_fc(struct fs_context *fc) 597 { 598 struct afs_fs_context *ctx = fc->fs_private; 599 600 afs_destroy_sbi(fc->s_fs_info); 601 afs_put_volume(ctx->cell, ctx->volume); 602 afs_put_cell(ctx->net, ctx->cell); 603 key_put(ctx->key); 604 kfree(ctx); 605 } 606 607 static const struct fs_context_operations afs_context_ops = { 608 .free = afs_free_fc, 609 .parse_param = afs_parse_param, 610 .get_tree = afs_get_tree, 611 }; 612 613 /* 614 * Set up the filesystem mount context. 615 */ 616 static int afs_init_fs_context(struct fs_context *fc) 617 { 618 struct afs_fs_context *ctx; 619 struct afs_cell *cell; 620 621 ctx = kzalloc(sizeof(struct afs_fs_context), GFP_KERNEL); 622 if (!ctx) 623 return -ENOMEM; 624 625 ctx->type = AFSVL_ROVOL; 626 ctx->net = afs_net(fc->net_ns); 627 628 /* Default to the workstation cell. */ 629 rcu_read_lock(); 630 cell = afs_lookup_cell_rcu(ctx->net, NULL, 0); 631 rcu_read_unlock(); 632 if (IS_ERR(cell)) 633 cell = NULL; 634 ctx->cell = cell; 635 636 fc->fs_private = ctx; 637 fc->ops = &afs_context_ops; 638 return 0; 639 } 640 641 /* 642 * Initialise an inode cache slab element prior to any use. Note that 643 * afs_alloc_inode() *must* reset anything that could incorrectly leak from one 644 * inode to another. 645 */ 646 static void afs_i_init_once(void *_vnode) 647 { 648 struct afs_vnode *vnode = _vnode; 649 650 memset(vnode, 0, sizeof(*vnode)); 651 inode_init_once(&vnode->vfs_inode); 652 mutex_init(&vnode->io_lock); 653 init_rwsem(&vnode->validate_lock); 654 spin_lock_init(&vnode->wb_lock); 655 spin_lock_init(&vnode->lock); 656 INIT_LIST_HEAD(&vnode->wb_keys); 657 INIT_LIST_HEAD(&vnode->pending_locks); 658 INIT_LIST_HEAD(&vnode->granted_locks); 659 INIT_DELAYED_WORK(&vnode->lock_work, afs_lock_work); 660 seqlock_init(&vnode->cb_lock); 661 } 662 663 /* 664 * allocate an AFS inode struct from our slab cache 665 */ 666 static struct inode *afs_alloc_inode(struct super_block *sb) 667 { 668 struct afs_vnode *vnode; 669 670 vnode = kmem_cache_alloc(afs_inode_cachep, GFP_KERNEL); 671 if (!vnode) 672 return NULL; 673 674 atomic_inc(&afs_count_active_inodes); 675 676 /* Reset anything that shouldn't leak from one inode to the next. */ 677 memset(&vnode->fid, 0, sizeof(vnode->fid)); 678 memset(&vnode->status, 0, sizeof(vnode->status)); 679 680 vnode->volume = NULL; 681 vnode->lock_key = NULL; 682 vnode->permit_cache = NULL; 683 RCU_INIT_POINTER(vnode->cb_interest, NULL); 684 #ifdef CONFIG_AFS_FSCACHE 685 vnode->cache = NULL; 686 #endif 687 688 vnode->flags = 1 << AFS_VNODE_UNSET; 689 vnode->lock_state = AFS_VNODE_LOCK_NONE; 690 691 init_rwsem(&vnode->rmdir_lock); 692 693 _leave(" = %p", &vnode->vfs_inode); 694 return &vnode->vfs_inode; 695 } 696 697 static void afs_free_inode(struct inode *inode) 698 { 699 kmem_cache_free(afs_inode_cachep, AFS_FS_I(inode)); 700 } 701 702 /* 703 * destroy an AFS inode struct 704 */ 705 static void afs_destroy_inode(struct inode *inode) 706 { 707 struct afs_vnode *vnode = AFS_FS_I(inode); 708 709 _enter("%p{%llx:%llu}", inode, vnode->fid.vid, vnode->fid.vnode); 710 711 _debug("DESTROY INODE %p", inode); 712 713 ASSERTCMP(rcu_access_pointer(vnode->cb_interest), ==, NULL); 714 715 atomic_dec(&afs_count_active_inodes); 716 } 717 718 /* 719 * return information about an AFS volume 720 */ 721 static int afs_statfs(struct dentry *dentry, struct kstatfs *buf) 722 { 723 struct afs_super_info *as = AFS_FS_S(dentry->d_sb); 724 struct afs_fs_cursor fc; 725 struct afs_volume_status vs; 726 struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry)); 727 struct key *key; 728 int ret; 729 730 buf->f_type = dentry->d_sb->s_magic; 731 buf->f_bsize = AFS_BLOCK_SIZE; 732 buf->f_namelen = AFSNAMEMAX - 1; 733 734 if (as->dyn_root) { 735 buf->f_blocks = 1; 736 buf->f_bavail = 0; 737 buf->f_bfree = 0; 738 return 0; 739 } 740 741 key = afs_request_key(vnode->volume->cell); 742 if (IS_ERR(key)) 743 return PTR_ERR(key); 744 745 ret = -ERESTARTSYS; 746 if (afs_begin_vnode_operation(&fc, vnode, key, true)) { 747 fc.flags |= AFS_FS_CURSOR_NO_VSLEEP; 748 while (afs_select_fileserver(&fc)) { 749 fc.cb_break = afs_calc_vnode_cb_break(vnode); 750 afs_fs_get_volume_status(&fc, &vs); 751 } 752 753 afs_check_for_remote_deletion(&fc, fc.vnode); 754 ret = afs_end_vnode_operation(&fc); 755 } 756 757 key_put(key); 758 759 if (ret == 0) { 760 if (vs.max_quota == 0) 761 buf->f_blocks = vs.part_max_blocks; 762 else 763 buf->f_blocks = vs.max_quota; 764 buf->f_bavail = buf->f_bfree = buf->f_blocks - vs.blocks_in_use; 765 } 766 767 return ret; 768 } 769