162306a36Sopenharmony_ci/* AFS superblock handling 262306a36Sopenharmony_ci * 362306a36Sopenharmony_ci * Copyright (c) 2002, 2007, 2018 Red Hat, Inc. All rights reserved. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This software may be freely redistributed under the terms of the 662306a36Sopenharmony_ci * GNU General Public License. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * You should have received a copy of the GNU General Public License 962306a36Sopenharmony_ci * along with this program; if not, write to the Free Software 1062306a36Sopenharmony_ci * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Authors: David Howells <dhowells@redhat.com> 1362306a36Sopenharmony_ci * David Woodhouse <dwmw2@infradead.org> 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/kernel.h> 1862306a36Sopenharmony_ci#include <linux/module.h> 1962306a36Sopenharmony_ci#include <linux/mount.h> 2062306a36Sopenharmony_ci#include <linux/init.h> 2162306a36Sopenharmony_ci#include <linux/slab.h> 2262306a36Sopenharmony_ci#include <linux/fs.h> 2362306a36Sopenharmony_ci#include <linux/pagemap.h> 2462306a36Sopenharmony_ci#include <linux/fs_parser.h> 2562306a36Sopenharmony_ci#include <linux/statfs.h> 2662306a36Sopenharmony_ci#include <linux/sched.h> 2762306a36Sopenharmony_ci#include <linux/nsproxy.h> 2862306a36Sopenharmony_ci#include <linux/magic.h> 2962306a36Sopenharmony_ci#include <net/net_namespace.h> 3062306a36Sopenharmony_ci#include "internal.h" 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic void afs_i_init_once(void *foo); 3362306a36Sopenharmony_cistatic void afs_kill_super(struct super_block *sb); 3462306a36Sopenharmony_cistatic struct inode *afs_alloc_inode(struct super_block *sb); 3562306a36Sopenharmony_cistatic void afs_destroy_inode(struct inode *inode); 3662306a36Sopenharmony_cistatic void afs_free_inode(struct inode *inode); 3762306a36Sopenharmony_cistatic int afs_statfs(struct dentry *dentry, struct kstatfs *buf); 3862306a36Sopenharmony_cistatic int afs_show_devname(struct seq_file *m, struct dentry *root); 3962306a36Sopenharmony_cistatic int afs_show_options(struct seq_file *m, struct dentry *root); 4062306a36Sopenharmony_cistatic int afs_init_fs_context(struct fs_context *fc); 4162306a36Sopenharmony_cistatic const struct fs_parameter_spec afs_fs_parameters[]; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistruct file_system_type afs_fs_type = { 4462306a36Sopenharmony_ci .owner = THIS_MODULE, 4562306a36Sopenharmony_ci .name = "afs", 4662306a36Sopenharmony_ci .init_fs_context = afs_init_fs_context, 4762306a36Sopenharmony_ci .parameters = afs_fs_parameters, 4862306a36Sopenharmony_ci .kill_sb = afs_kill_super, 4962306a36Sopenharmony_ci .fs_flags = FS_RENAME_DOES_D_MOVE, 5062306a36Sopenharmony_ci}; 5162306a36Sopenharmony_ciMODULE_ALIAS_FS("afs"); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ciint afs_net_id; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic const struct super_operations afs_super_ops = { 5662306a36Sopenharmony_ci .statfs = afs_statfs, 5762306a36Sopenharmony_ci .alloc_inode = afs_alloc_inode, 5862306a36Sopenharmony_ci .write_inode = afs_write_inode, 5962306a36Sopenharmony_ci .drop_inode = afs_drop_inode, 6062306a36Sopenharmony_ci .destroy_inode = afs_destroy_inode, 6162306a36Sopenharmony_ci .free_inode = afs_free_inode, 6262306a36Sopenharmony_ci .evict_inode = afs_evict_inode, 6362306a36Sopenharmony_ci .show_devname = afs_show_devname, 6462306a36Sopenharmony_ci .show_options = afs_show_options, 6562306a36Sopenharmony_ci}; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic struct kmem_cache *afs_inode_cachep; 6862306a36Sopenharmony_cistatic atomic_t afs_count_active_inodes; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cienum afs_param { 7162306a36Sopenharmony_ci Opt_autocell, 7262306a36Sopenharmony_ci Opt_dyn, 7362306a36Sopenharmony_ci Opt_flock, 7462306a36Sopenharmony_ci Opt_source, 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic const struct constant_table afs_param_flock[] = { 7862306a36Sopenharmony_ci {"local", afs_flock_mode_local }, 7962306a36Sopenharmony_ci {"openafs", afs_flock_mode_openafs }, 8062306a36Sopenharmony_ci {"strict", afs_flock_mode_strict }, 8162306a36Sopenharmony_ci {"write", afs_flock_mode_write }, 8262306a36Sopenharmony_ci {} 8362306a36Sopenharmony_ci}; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic const struct fs_parameter_spec afs_fs_parameters[] = { 8662306a36Sopenharmony_ci fsparam_flag ("autocell", Opt_autocell), 8762306a36Sopenharmony_ci fsparam_flag ("dyn", Opt_dyn), 8862306a36Sopenharmony_ci fsparam_enum ("flock", Opt_flock, afs_param_flock), 8962306a36Sopenharmony_ci fsparam_string("source", Opt_source), 9062306a36Sopenharmony_ci {} 9162306a36Sopenharmony_ci}; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci/* 9462306a36Sopenharmony_ci * initialise the filesystem 9562306a36Sopenharmony_ci */ 9662306a36Sopenharmony_ciint __init afs_fs_init(void) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci int ret; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci _enter(""); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci /* create ourselves an inode cache */ 10362306a36Sopenharmony_ci atomic_set(&afs_count_active_inodes, 0); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci ret = -ENOMEM; 10662306a36Sopenharmony_ci afs_inode_cachep = kmem_cache_create("afs_inode_cache", 10762306a36Sopenharmony_ci sizeof(struct afs_vnode), 10862306a36Sopenharmony_ci 0, 10962306a36Sopenharmony_ci SLAB_HWCACHE_ALIGN|SLAB_ACCOUNT, 11062306a36Sopenharmony_ci afs_i_init_once); 11162306a36Sopenharmony_ci if (!afs_inode_cachep) { 11262306a36Sopenharmony_ci printk(KERN_NOTICE "kAFS: Failed to allocate inode cache\n"); 11362306a36Sopenharmony_ci return ret; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci /* now export our filesystem to lesser mortals */ 11762306a36Sopenharmony_ci ret = register_filesystem(&afs_fs_type); 11862306a36Sopenharmony_ci if (ret < 0) { 11962306a36Sopenharmony_ci kmem_cache_destroy(afs_inode_cachep); 12062306a36Sopenharmony_ci _leave(" = %d", ret); 12162306a36Sopenharmony_ci return ret; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci _leave(" = 0"); 12562306a36Sopenharmony_ci return 0; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci/* 12962306a36Sopenharmony_ci * clean up the filesystem 13062306a36Sopenharmony_ci */ 13162306a36Sopenharmony_civoid afs_fs_exit(void) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci _enter(""); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci afs_mntpt_kill_timer(); 13662306a36Sopenharmony_ci unregister_filesystem(&afs_fs_type); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci if (atomic_read(&afs_count_active_inodes) != 0) { 13962306a36Sopenharmony_ci printk("kAFS: %d active inode objects still present\n", 14062306a36Sopenharmony_ci atomic_read(&afs_count_active_inodes)); 14162306a36Sopenharmony_ci BUG(); 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci /* 14562306a36Sopenharmony_ci * Make sure all delayed rcu free inodes are flushed before we 14662306a36Sopenharmony_ci * destroy cache. 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_ci rcu_barrier(); 14962306a36Sopenharmony_ci kmem_cache_destroy(afs_inode_cachep); 15062306a36Sopenharmony_ci _leave(""); 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci/* 15462306a36Sopenharmony_ci * Display the mount device name in /proc/mounts. 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_cistatic int afs_show_devname(struct seq_file *m, struct dentry *root) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci struct afs_super_info *as = AFS_FS_S(root->d_sb); 15962306a36Sopenharmony_ci struct afs_volume *volume = as->volume; 16062306a36Sopenharmony_ci struct afs_cell *cell = as->cell; 16162306a36Sopenharmony_ci const char *suf = ""; 16262306a36Sopenharmony_ci char pref = '%'; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci if (as->dyn_root) { 16562306a36Sopenharmony_ci seq_puts(m, "none"); 16662306a36Sopenharmony_ci return 0; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci switch (volume->type) { 17062306a36Sopenharmony_ci case AFSVL_RWVOL: 17162306a36Sopenharmony_ci break; 17262306a36Sopenharmony_ci case AFSVL_ROVOL: 17362306a36Sopenharmony_ci pref = '#'; 17462306a36Sopenharmony_ci if (volume->type_force) 17562306a36Sopenharmony_ci suf = ".readonly"; 17662306a36Sopenharmony_ci break; 17762306a36Sopenharmony_ci case AFSVL_BACKVOL: 17862306a36Sopenharmony_ci pref = '#'; 17962306a36Sopenharmony_ci suf = ".backup"; 18062306a36Sopenharmony_ci break; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci seq_printf(m, "%c%s:%s%s", pref, cell->name, volume->name, suf); 18462306a36Sopenharmony_ci return 0; 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci/* 18862306a36Sopenharmony_ci * Display the mount options in /proc/mounts. 18962306a36Sopenharmony_ci */ 19062306a36Sopenharmony_cistatic int afs_show_options(struct seq_file *m, struct dentry *root) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci struct afs_super_info *as = AFS_FS_S(root->d_sb); 19362306a36Sopenharmony_ci const char *p = NULL; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci if (as->dyn_root) 19662306a36Sopenharmony_ci seq_puts(m, ",dyn"); 19762306a36Sopenharmony_ci if (test_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(d_inode(root))->flags)) 19862306a36Sopenharmony_ci seq_puts(m, ",autocell"); 19962306a36Sopenharmony_ci switch (as->flock_mode) { 20062306a36Sopenharmony_ci case afs_flock_mode_unset: break; 20162306a36Sopenharmony_ci case afs_flock_mode_local: p = "local"; break; 20262306a36Sopenharmony_ci case afs_flock_mode_openafs: p = "openafs"; break; 20362306a36Sopenharmony_ci case afs_flock_mode_strict: p = "strict"; break; 20462306a36Sopenharmony_ci case afs_flock_mode_write: p = "write"; break; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci if (p) 20762306a36Sopenharmony_ci seq_printf(m, ",flock=%s", p); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci return 0; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci/* 21362306a36Sopenharmony_ci * Parse the source name to get cell name, volume name, volume type and R/W 21462306a36Sopenharmony_ci * selector. 21562306a36Sopenharmony_ci * 21662306a36Sopenharmony_ci * This can be one of the following: 21762306a36Sopenharmony_ci * "%[cell:]volume[.]" R/W volume 21862306a36Sopenharmony_ci * "#[cell:]volume[.]" R/O or R/W volume (R/O parent), 21962306a36Sopenharmony_ci * or R/W (R/W parent) volume 22062306a36Sopenharmony_ci * "%[cell:]volume.readonly" R/O volume 22162306a36Sopenharmony_ci * "#[cell:]volume.readonly" R/O volume 22262306a36Sopenharmony_ci * "%[cell:]volume.backup" Backup volume 22362306a36Sopenharmony_ci * "#[cell:]volume.backup" Backup volume 22462306a36Sopenharmony_ci */ 22562306a36Sopenharmony_cistatic int afs_parse_source(struct fs_context *fc, struct fs_parameter *param) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci struct afs_fs_context *ctx = fc->fs_private; 22862306a36Sopenharmony_ci struct afs_cell *cell; 22962306a36Sopenharmony_ci const char *cellname, *suffix, *name = param->string; 23062306a36Sopenharmony_ci int cellnamesz; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci _enter(",%s", name); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (fc->source) 23562306a36Sopenharmony_ci return invalf(fc, "kAFS: Multiple sources not supported"); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci if (!name) { 23862306a36Sopenharmony_ci printk(KERN_ERR "kAFS: no volume name specified\n"); 23962306a36Sopenharmony_ci return -EINVAL; 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci if ((name[0] != '%' && name[0] != '#') || !name[1]) { 24362306a36Sopenharmony_ci /* To use dynroot, we don't want to have to provide a source */ 24462306a36Sopenharmony_ci if (strcmp(name, "none") == 0) { 24562306a36Sopenharmony_ci ctx->no_cell = true; 24662306a36Sopenharmony_ci return 0; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci printk(KERN_ERR "kAFS: unparsable volume name\n"); 24962306a36Sopenharmony_ci return -EINVAL; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci /* determine the type of volume we're looking for */ 25362306a36Sopenharmony_ci if (name[0] == '%') { 25462306a36Sopenharmony_ci ctx->type = AFSVL_RWVOL; 25562306a36Sopenharmony_ci ctx->force = true; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci name++; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci /* split the cell name out if there is one */ 26062306a36Sopenharmony_ci ctx->volname = strchr(name, ':'); 26162306a36Sopenharmony_ci if (ctx->volname) { 26262306a36Sopenharmony_ci cellname = name; 26362306a36Sopenharmony_ci cellnamesz = ctx->volname - name; 26462306a36Sopenharmony_ci ctx->volname++; 26562306a36Sopenharmony_ci } else { 26662306a36Sopenharmony_ci ctx->volname = name; 26762306a36Sopenharmony_ci cellname = NULL; 26862306a36Sopenharmony_ci cellnamesz = 0; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci /* the volume type is further affected by a possible suffix */ 27262306a36Sopenharmony_ci suffix = strrchr(ctx->volname, '.'); 27362306a36Sopenharmony_ci if (suffix) { 27462306a36Sopenharmony_ci if (strcmp(suffix, ".readonly") == 0) { 27562306a36Sopenharmony_ci ctx->type = AFSVL_ROVOL; 27662306a36Sopenharmony_ci ctx->force = true; 27762306a36Sopenharmony_ci } else if (strcmp(suffix, ".backup") == 0) { 27862306a36Sopenharmony_ci ctx->type = AFSVL_BACKVOL; 27962306a36Sopenharmony_ci ctx->force = true; 28062306a36Sopenharmony_ci } else if (suffix[1] == 0) { 28162306a36Sopenharmony_ci } else { 28262306a36Sopenharmony_ci suffix = NULL; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci ctx->volnamesz = suffix ? 28762306a36Sopenharmony_ci suffix - ctx->volname : strlen(ctx->volname); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci _debug("cell %*.*s [%p]", 29062306a36Sopenharmony_ci cellnamesz, cellnamesz, cellname ?: "", ctx->cell); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci /* lookup the cell record */ 29362306a36Sopenharmony_ci if (cellname) { 29462306a36Sopenharmony_ci cell = afs_lookup_cell(ctx->net, cellname, cellnamesz, 29562306a36Sopenharmony_ci NULL, false); 29662306a36Sopenharmony_ci if (IS_ERR(cell)) { 29762306a36Sopenharmony_ci pr_err("kAFS: unable to lookup cell '%*.*s'\n", 29862306a36Sopenharmony_ci cellnamesz, cellnamesz, cellname ?: ""); 29962306a36Sopenharmony_ci return PTR_ERR(cell); 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci afs_unuse_cell(ctx->net, ctx->cell, afs_cell_trace_unuse_parse); 30262306a36Sopenharmony_ci afs_see_cell(cell, afs_cell_trace_see_source); 30362306a36Sopenharmony_ci ctx->cell = cell; 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci _debug("CELL:%s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s", 30762306a36Sopenharmony_ci ctx->cell->name, ctx->cell, 30862306a36Sopenharmony_ci ctx->volnamesz, ctx->volnamesz, ctx->volname, 30962306a36Sopenharmony_ci suffix ?: "-", ctx->type, ctx->force ? " FORCE" : ""); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci fc->source = param->string; 31262306a36Sopenharmony_ci param->string = NULL; 31362306a36Sopenharmony_ci return 0; 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci/* 31762306a36Sopenharmony_ci * Parse a single mount parameter. 31862306a36Sopenharmony_ci */ 31962306a36Sopenharmony_cistatic int afs_parse_param(struct fs_context *fc, struct fs_parameter *param) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci struct fs_parse_result result; 32262306a36Sopenharmony_ci struct afs_fs_context *ctx = fc->fs_private; 32362306a36Sopenharmony_ci int opt; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci opt = fs_parse(fc, afs_fs_parameters, param, &result); 32662306a36Sopenharmony_ci if (opt < 0) 32762306a36Sopenharmony_ci return opt; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci switch (opt) { 33062306a36Sopenharmony_ci case Opt_source: 33162306a36Sopenharmony_ci return afs_parse_source(fc, param); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci case Opt_autocell: 33462306a36Sopenharmony_ci ctx->autocell = true; 33562306a36Sopenharmony_ci break; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci case Opt_dyn: 33862306a36Sopenharmony_ci ctx->dyn_root = true; 33962306a36Sopenharmony_ci break; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci case Opt_flock: 34262306a36Sopenharmony_ci ctx->flock_mode = result.uint_32; 34362306a36Sopenharmony_ci break; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci default: 34662306a36Sopenharmony_ci return -EINVAL; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci _leave(" = 0"); 35062306a36Sopenharmony_ci return 0; 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci/* 35462306a36Sopenharmony_ci * Validate the options, get the cell key and look up the volume. 35562306a36Sopenharmony_ci */ 35662306a36Sopenharmony_cistatic int afs_validate_fc(struct fs_context *fc) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci struct afs_fs_context *ctx = fc->fs_private; 35962306a36Sopenharmony_ci struct afs_volume *volume; 36062306a36Sopenharmony_ci struct afs_cell *cell; 36162306a36Sopenharmony_ci struct key *key; 36262306a36Sopenharmony_ci int ret; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (!ctx->dyn_root) { 36562306a36Sopenharmony_ci if (ctx->no_cell) { 36662306a36Sopenharmony_ci pr_warn("kAFS: Can only specify source 'none' with -o dyn\n"); 36762306a36Sopenharmony_ci return -EINVAL; 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci if (!ctx->cell) { 37162306a36Sopenharmony_ci pr_warn("kAFS: No cell specified\n"); 37262306a36Sopenharmony_ci return -EDESTADDRREQ; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci reget_key: 37662306a36Sopenharmony_ci /* We try to do the mount securely. */ 37762306a36Sopenharmony_ci key = afs_request_key(ctx->cell); 37862306a36Sopenharmony_ci if (IS_ERR(key)) 37962306a36Sopenharmony_ci return PTR_ERR(key); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci ctx->key = key; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci if (ctx->volume) { 38462306a36Sopenharmony_ci afs_put_volume(ctx->net, ctx->volume, 38562306a36Sopenharmony_ci afs_volume_trace_put_validate_fc); 38662306a36Sopenharmony_ci ctx->volume = NULL; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci if (test_bit(AFS_CELL_FL_CHECK_ALIAS, &ctx->cell->flags)) { 39062306a36Sopenharmony_ci ret = afs_cell_detect_alias(ctx->cell, key); 39162306a36Sopenharmony_ci if (ret < 0) 39262306a36Sopenharmony_ci return ret; 39362306a36Sopenharmony_ci if (ret == 1) { 39462306a36Sopenharmony_ci _debug("switch to alias"); 39562306a36Sopenharmony_ci key_put(ctx->key); 39662306a36Sopenharmony_ci ctx->key = NULL; 39762306a36Sopenharmony_ci cell = afs_use_cell(ctx->cell->alias_of, 39862306a36Sopenharmony_ci afs_cell_trace_use_fc_alias); 39962306a36Sopenharmony_ci afs_unuse_cell(ctx->net, ctx->cell, afs_cell_trace_unuse_fc); 40062306a36Sopenharmony_ci ctx->cell = cell; 40162306a36Sopenharmony_ci goto reget_key; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci volume = afs_create_volume(ctx); 40662306a36Sopenharmony_ci if (IS_ERR(volume)) 40762306a36Sopenharmony_ci return PTR_ERR(volume); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci ctx->volume = volume; 41062306a36Sopenharmony_ci if (volume->type != AFSVL_RWVOL) 41162306a36Sopenharmony_ci ctx->flock_mode = afs_flock_mode_local; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci return 0; 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci/* 41862306a36Sopenharmony_ci * check a superblock to see if it's the one we're looking for 41962306a36Sopenharmony_ci */ 42062306a36Sopenharmony_cistatic int afs_test_super(struct super_block *sb, struct fs_context *fc) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci struct afs_fs_context *ctx = fc->fs_private; 42362306a36Sopenharmony_ci struct afs_super_info *as = AFS_FS_S(sb); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci return (as->net_ns == fc->net_ns && 42662306a36Sopenharmony_ci as->volume && 42762306a36Sopenharmony_ci as->volume->vid == ctx->volume->vid && 42862306a36Sopenharmony_ci as->cell == ctx->cell && 42962306a36Sopenharmony_ci !as->dyn_root); 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cistatic int afs_dynroot_test_super(struct super_block *sb, struct fs_context *fc) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci struct afs_super_info *as = AFS_FS_S(sb); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci return (as->net_ns == fc->net_ns && 43762306a36Sopenharmony_ci as->dyn_root); 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cistatic int afs_set_super(struct super_block *sb, struct fs_context *fc) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci return set_anon_super(sb, NULL); 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci/* 44662306a36Sopenharmony_ci * fill in the superblock 44762306a36Sopenharmony_ci */ 44862306a36Sopenharmony_cistatic int afs_fill_super(struct super_block *sb, struct afs_fs_context *ctx) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci struct afs_super_info *as = AFS_FS_S(sb); 45162306a36Sopenharmony_ci struct inode *inode = NULL; 45262306a36Sopenharmony_ci int ret; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci _enter(""); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci /* fill in the superblock */ 45762306a36Sopenharmony_ci sb->s_blocksize = PAGE_SIZE; 45862306a36Sopenharmony_ci sb->s_blocksize_bits = PAGE_SHIFT; 45962306a36Sopenharmony_ci sb->s_maxbytes = MAX_LFS_FILESIZE; 46062306a36Sopenharmony_ci sb->s_magic = AFS_FS_MAGIC; 46162306a36Sopenharmony_ci sb->s_op = &afs_super_ops; 46262306a36Sopenharmony_ci if (!as->dyn_root) 46362306a36Sopenharmony_ci sb->s_xattr = afs_xattr_handlers; 46462306a36Sopenharmony_ci ret = super_setup_bdi(sb); 46562306a36Sopenharmony_ci if (ret) 46662306a36Sopenharmony_ci return ret; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci /* allocate the root inode and dentry */ 46962306a36Sopenharmony_ci if (as->dyn_root) { 47062306a36Sopenharmony_ci inode = afs_iget_pseudo_dir(sb, true); 47162306a36Sopenharmony_ci } else { 47262306a36Sopenharmony_ci sprintf(sb->s_id, "%llu", as->volume->vid); 47362306a36Sopenharmony_ci afs_activate_volume(as->volume); 47462306a36Sopenharmony_ci inode = afs_root_iget(sb, ctx->key); 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci if (IS_ERR(inode)) 47862306a36Sopenharmony_ci return PTR_ERR(inode); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci if (ctx->autocell || as->dyn_root) 48162306a36Sopenharmony_ci set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci ret = -ENOMEM; 48462306a36Sopenharmony_ci sb->s_root = d_make_root(inode); 48562306a36Sopenharmony_ci if (!sb->s_root) 48662306a36Sopenharmony_ci goto error; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci if (as->dyn_root) { 48962306a36Sopenharmony_ci sb->s_d_op = &afs_dynroot_dentry_operations; 49062306a36Sopenharmony_ci ret = afs_dynroot_populate(sb); 49162306a36Sopenharmony_ci if (ret < 0) 49262306a36Sopenharmony_ci goto error; 49362306a36Sopenharmony_ci } else { 49462306a36Sopenharmony_ci sb->s_d_op = &afs_fs_dentry_operations; 49562306a36Sopenharmony_ci rcu_assign_pointer(as->volume->sb, sb); 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci _leave(" = 0"); 49962306a36Sopenharmony_ci return 0; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cierror: 50262306a36Sopenharmony_ci _leave(" = %d", ret); 50362306a36Sopenharmony_ci return ret; 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_cistatic struct afs_super_info *afs_alloc_sbi(struct fs_context *fc) 50762306a36Sopenharmony_ci{ 50862306a36Sopenharmony_ci struct afs_fs_context *ctx = fc->fs_private; 50962306a36Sopenharmony_ci struct afs_super_info *as; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL); 51262306a36Sopenharmony_ci if (as) { 51362306a36Sopenharmony_ci as->net_ns = get_net(fc->net_ns); 51462306a36Sopenharmony_ci as->flock_mode = ctx->flock_mode; 51562306a36Sopenharmony_ci if (ctx->dyn_root) { 51662306a36Sopenharmony_ci as->dyn_root = true; 51762306a36Sopenharmony_ci } else { 51862306a36Sopenharmony_ci as->cell = afs_use_cell(ctx->cell, afs_cell_trace_use_sbi); 51962306a36Sopenharmony_ci as->volume = afs_get_volume(ctx->volume, 52062306a36Sopenharmony_ci afs_volume_trace_get_alloc_sbi); 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci return as; 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_cistatic void afs_destroy_sbi(struct afs_super_info *as) 52762306a36Sopenharmony_ci{ 52862306a36Sopenharmony_ci if (as) { 52962306a36Sopenharmony_ci struct afs_net *net = afs_net(as->net_ns); 53062306a36Sopenharmony_ci afs_put_volume(net, as->volume, afs_volume_trace_put_destroy_sbi); 53162306a36Sopenharmony_ci afs_unuse_cell(net, as->cell, afs_cell_trace_unuse_sbi); 53262306a36Sopenharmony_ci put_net(as->net_ns); 53362306a36Sopenharmony_ci kfree(as); 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cistatic void afs_kill_super(struct super_block *sb) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci struct afs_super_info *as = AFS_FS_S(sb); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci if (as->dyn_root) 54262306a36Sopenharmony_ci afs_dynroot_depopulate(sb); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci /* Clear the callback interests (which will do ilookup5) before 54562306a36Sopenharmony_ci * deactivating the superblock. 54662306a36Sopenharmony_ci */ 54762306a36Sopenharmony_ci if (as->volume) 54862306a36Sopenharmony_ci rcu_assign_pointer(as->volume->sb, NULL); 54962306a36Sopenharmony_ci kill_anon_super(sb); 55062306a36Sopenharmony_ci if (as->volume) 55162306a36Sopenharmony_ci afs_deactivate_volume(as->volume); 55262306a36Sopenharmony_ci afs_destroy_sbi(as); 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci/* 55662306a36Sopenharmony_ci * Get an AFS superblock and root directory. 55762306a36Sopenharmony_ci */ 55862306a36Sopenharmony_cistatic int afs_get_tree(struct fs_context *fc) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci struct afs_fs_context *ctx = fc->fs_private; 56162306a36Sopenharmony_ci struct super_block *sb; 56262306a36Sopenharmony_ci struct afs_super_info *as; 56362306a36Sopenharmony_ci int ret; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci ret = afs_validate_fc(fc); 56662306a36Sopenharmony_ci if (ret) 56762306a36Sopenharmony_ci goto error; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci _enter(""); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci /* allocate a superblock info record */ 57262306a36Sopenharmony_ci ret = -ENOMEM; 57362306a36Sopenharmony_ci as = afs_alloc_sbi(fc); 57462306a36Sopenharmony_ci if (!as) 57562306a36Sopenharmony_ci goto error; 57662306a36Sopenharmony_ci fc->s_fs_info = as; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci /* allocate a deviceless superblock */ 57962306a36Sopenharmony_ci sb = sget_fc(fc, 58062306a36Sopenharmony_ci as->dyn_root ? afs_dynroot_test_super : afs_test_super, 58162306a36Sopenharmony_ci afs_set_super); 58262306a36Sopenharmony_ci if (IS_ERR(sb)) { 58362306a36Sopenharmony_ci ret = PTR_ERR(sb); 58462306a36Sopenharmony_ci goto error; 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci if (!sb->s_root) { 58862306a36Sopenharmony_ci /* initial superblock/root creation */ 58962306a36Sopenharmony_ci _debug("create"); 59062306a36Sopenharmony_ci ret = afs_fill_super(sb, ctx); 59162306a36Sopenharmony_ci if (ret < 0) 59262306a36Sopenharmony_ci goto error_sb; 59362306a36Sopenharmony_ci sb->s_flags |= SB_ACTIVE; 59462306a36Sopenharmony_ci } else { 59562306a36Sopenharmony_ci _debug("reuse"); 59662306a36Sopenharmony_ci ASSERTCMP(sb->s_flags, &, SB_ACTIVE); 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci fc->root = dget(sb->s_root); 60062306a36Sopenharmony_ci trace_afs_get_tree(as->cell, as->volume); 60162306a36Sopenharmony_ci _leave(" = 0 [%p]", sb); 60262306a36Sopenharmony_ci return 0; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_cierror_sb: 60562306a36Sopenharmony_ci deactivate_locked_super(sb); 60662306a36Sopenharmony_cierror: 60762306a36Sopenharmony_ci _leave(" = %d", ret); 60862306a36Sopenharmony_ci return ret; 60962306a36Sopenharmony_ci} 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_cistatic void afs_free_fc(struct fs_context *fc) 61262306a36Sopenharmony_ci{ 61362306a36Sopenharmony_ci struct afs_fs_context *ctx = fc->fs_private; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci afs_destroy_sbi(fc->s_fs_info); 61662306a36Sopenharmony_ci afs_put_volume(ctx->net, ctx->volume, afs_volume_trace_put_free_fc); 61762306a36Sopenharmony_ci afs_unuse_cell(ctx->net, ctx->cell, afs_cell_trace_unuse_fc); 61862306a36Sopenharmony_ci key_put(ctx->key); 61962306a36Sopenharmony_ci kfree(ctx); 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic const struct fs_context_operations afs_context_ops = { 62362306a36Sopenharmony_ci .free = afs_free_fc, 62462306a36Sopenharmony_ci .parse_param = afs_parse_param, 62562306a36Sopenharmony_ci .get_tree = afs_get_tree, 62662306a36Sopenharmony_ci}; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci/* 62962306a36Sopenharmony_ci * Set up the filesystem mount context. 63062306a36Sopenharmony_ci */ 63162306a36Sopenharmony_cistatic int afs_init_fs_context(struct fs_context *fc) 63262306a36Sopenharmony_ci{ 63362306a36Sopenharmony_ci struct afs_fs_context *ctx; 63462306a36Sopenharmony_ci struct afs_cell *cell; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci ctx = kzalloc(sizeof(struct afs_fs_context), GFP_KERNEL); 63762306a36Sopenharmony_ci if (!ctx) 63862306a36Sopenharmony_ci return -ENOMEM; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci ctx->type = AFSVL_ROVOL; 64162306a36Sopenharmony_ci ctx->net = afs_net(fc->net_ns); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci /* Default to the workstation cell. */ 64462306a36Sopenharmony_ci cell = afs_find_cell(ctx->net, NULL, 0, afs_cell_trace_use_fc); 64562306a36Sopenharmony_ci if (IS_ERR(cell)) 64662306a36Sopenharmony_ci cell = NULL; 64762306a36Sopenharmony_ci ctx->cell = cell; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci fc->fs_private = ctx; 65062306a36Sopenharmony_ci fc->ops = &afs_context_ops; 65162306a36Sopenharmony_ci return 0; 65262306a36Sopenharmony_ci} 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci/* 65562306a36Sopenharmony_ci * Initialise an inode cache slab element prior to any use. Note that 65662306a36Sopenharmony_ci * afs_alloc_inode() *must* reset anything that could incorrectly leak from one 65762306a36Sopenharmony_ci * inode to another. 65862306a36Sopenharmony_ci */ 65962306a36Sopenharmony_cistatic void afs_i_init_once(void *_vnode) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci struct afs_vnode *vnode = _vnode; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci memset(vnode, 0, sizeof(*vnode)); 66462306a36Sopenharmony_ci inode_init_once(&vnode->netfs.inode); 66562306a36Sopenharmony_ci mutex_init(&vnode->io_lock); 66662306a36Sopenharmony_ci init_rwsem(&vnode->validate_lock); 66762306a36Sopenharmony_ci spin_lock_init(&vnode->wb_lock); 66862306a36Sopenharmony_ci spin_lock_init(&vnode->lock); 66962306a36Sopenharmony_ci INIT_LIST_HEAD(&vnode->wb_keys); 67062306a36Sopenharmony_ci INIT_LIST_HEAD(&vnode->pending_locks); 67162306a36Sopenharmony_ci INIT_LIST_HEAD(&vnode->granted_locks); 67262306a36Sopenharmony_ci INIT_DELAYED_WORK(&vnode->lock_work, afs_lock_work); 67362306a36Sopenharmony_ci INIT_LIST_HEAD(&vnode->cb_mmap_link); 67462306a36Sopenharmony_ci seqlock_init(&vnode->cb_lock); 67562306a36Sopenharmony_ci} 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci/* 67862306a36Sopenharmony_ci * allocate an AFS inode struct from our slab cache 67962306a36Sopenharmony_ci */ 68062306a36Sopenharmony_cistatic struct inode *afs_alloc_inode(struct super_block *sb) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci struct afs_vnode *vnode; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci vnode = alloc_inode_sb(sb, afs_inode_cachep, GFP_KERNEL); 68562306a36Sopenharmony_ci if (!vnode) 68662306a36Sopenharmony_ci return NULL; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci atomic_inc(&afs_count_active_inodes); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci /* Reset anything that shouldn't leak from one inode to the next. */ 69162306a36Sopenharmony_ci memset(&vnode->fid, 0, sizeof(vnode->fid)); 69262306a36Sopenharmony_ci memset(&vnode->status, 0, sizeof(vnode->status)); 69362306a36Sopenharmony_ci afs_vnode_set_cache(vnode, NULL); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci vnode->volume = NULL; 69662306a36Sopenharmony_ci vnode->lock_key = NULL; 69762306a36Sopenharmony_ci vnode->permit_cache = NULL; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci vnode->flags = 1 << AFS_VNODE_UNSET; 70062306a36Sopenharmony_ci vnode->lock_state = AFS_VNODE_LOCK_NONE; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci init_rwsem(&vnode->rmdir_lock); 70362306a36Sopenharmony_ci INIT_WORK(&vnode->cb_work, afs_invalidate_mmap_work); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci _leave(" = %p", &vnode->netfs.inode); 70662306a36Sopenharmony_ci return &vnode->netfs.inode; 70762306a36Sopenharmony_ci} 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_cistatic void afs_free_inode(struct inode *inode) 71062306a36Sopenharmony_ci{ 71162306a36Sopenharmony_ci kmem_cache_free(afs_inode_cachep, AFS_FS_I(inode)); 71262306a36Sopenharmony_ci} 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci/* 71562306a36Sopenharmony_ci * destroy an AFS inode struct 71662306a36Sopenharmony_ci */ 71762306a36Sopenharmony_cistatic void afs_destroy_inode(struct inode *inode) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci struct afs_vnode *vnode = AFS_FS_I(inode); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci _enter("%p{%llx:%llu}", inode, vnode->fid.vid, vnode->fid.vnode); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci _debug("DESTROY INODE %p", inode); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci atomic_dec(&afs_count_active_inodes); 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_cistatic void afs_get_volume_status_success(struct afs_operation *op) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci struct afs_volume_status *vs = &op->volstatus.vs; 73162306a36Sopenharmony_ci struct kstatfs *buf = op->volstatus.buf; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci if (vs->max_quota == 0) 73462306a36Sopenharmony_ci buf->f_blocks = vs->part_max_blocks; 73562306a36Sopenharmony_ci else 73662306a36Sopenharmony_ci buf->f_blocks = vs->max_quota; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci if (buf->f_blocks > vs->blocks_in_use) 73962306a36Sopenharmony_ci buf->f_bavail = buf->f_bfree = 74062306a36Sopenharmony_ci buf->f_blocks - vs->blocks_in_use; 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_cistatic const struct afs_operation_ops afs_get_volume_status_operation = { 74462306a36Sopenharmony_ci .issue_afs_rpc = afs_fs_get_volume_status, 74562306a36Sopenharmony_ci .issue_yfs_rpc = yfs_fs_get_volume_status, 74662306a36Sopenharmony_ci .success = afs_get_volume_status_success, 74762306a36Sopenharmony_ci}; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci/* 75062306a36Sopenharmony_ci * return information about an AFS volume 75162306a36Sopenharmony_ci */ 75262306a36Sopenharmony_cistatic int afs_statfs(struct dentry *dentry, struct kstatfs *buf) 75362306a36Sopenharmony_ci{ 75462306a36Sopenharmony_ci struct afs_super_info *as = AFS_FS_S(dentry->d_sb); 75562306a36Sopenharmony_ci struct afs_operation *op; 75662306a36Sopenharmony_ci struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry)); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci buf->f_type = dentry->d_sb->s_magic; 75962306a36Sopenharmony_ci buf->f_bsize = AFS_BLOCK_SIZE; 76062306a36Sopenharmony_ci buf->f_namelen = AFSNAMEMAX - 1; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci if (as->dyn_root) { 76362306a36Sopenharmony_ci buf->f_blocks = 1; 76462306a36Sopenharmony_ci buf->f_bavail = 0; 76562306a36Sopenharmony_ci buf->f_bfree = 0; 76662306a36Sopenharmony_ci return 0; 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci op = afs_alloc_operation(NULL, as->volume); 77062306a36Sopenharmony_ci if (IS_ERR(op)) 77162306a36Sopenharmony_ci return PTR_ERR(op); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci afs_op_set_vnode(op, 0, vnode); 77462306a36Sopenharmony_ci op->nr_files = 1; 77562306a36Sopenharmony_ci op->volstatus.buf = buf; 77662306a36Sopenharmony_ci op->ops = &afs_get_volume_status_operation; 77762306a36Sopenharmony_ci return afs_do_sync_operation(op); 77862306a36Sopenharmony_ci} 779