18c2ecf20Sopenharmony_ci/* AFS superblock handling 28c2ecf20Sopenharmony_ci * 38c2ecf20Sopenharmony_ci * Copyright (c) 2002, 2007, 2018 Red Hat, Inc. All rights reserved. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This software may be freely redistributed under the terms of the 68c2ecf20Sopenharmony_ci * GNU General Public License. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * You should have received a copy of the GNU General Public License 98c2ecf20Sopenharmony_ci * along with this program; if not, write to the Free Software 108c2ecf20Sopenharmony_ci * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Authors: David Howells <dhowells@redhat.com> 138c2ecf20Sopenharmony_ci * David Woodhouse <dwmw2@infradead.org> 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/kernel.h> 188c2ecf20Sopenharmony_ci#include <linux/module.h> 198c2ecf20Sopenharmony_ci#include <linux/mount.h> 208c2ecf20Sopenharmony_ci#include <linux/init.h> 218c2ecf20Sopenharmony_ci#include <linux/slab.h> 228c2ecf20Sopenharmony_ci#include <linux/fs.h> 238c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 248c2ecf20Sopenharmony_ci#include <linux/fs_parser.h> 258c2ecf20Sopenharmony_ci#include <linux/statfs.h> 268c2ecf20Sopenharmony_ci#include <linux/sched.h> 278c2ecf20Sopenharmony_ci#include <linux/nsproxy.h> 288c2ecf20Sopenharmony_ci#include <linux/magic.h> 298c2ecf20Sopenharmony_ci#include <net/net_namespace.h> 308c2ecf20Sopenharmony_ci#include "internal.h" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic void afs_i_init_once(void *foo); 338c2ecf20Sopenharmony_cistatic void afs_kill_super(struct super_block *sb); 348c2ecf20Sopenharmony_cistatic struct inode *afs_alloc_inode(struct super_block *sb); 358c2ecf20Sopenharmony_cistatic void afs_destroy_inode(struct inode *inode); 368c2ecf20Sopenharmony_cistatic void afs_free_inode(struct inode *inode); 378c2ecf20Sopenharmony_cistatic int afs_statfs(struct dentry *dentry, struct kstatfs *buf); 388c2ecf20Sopenharmony_cistatic int afs_show_devname(struct seq_file *m, struct dentry *root); 398c2ecf20Sopenharmony_cistatic int afs_show_options(struct seq_file *m, struct dentry *root); 408c2ecf20Sopenharmony_cistatic int afs_init_fs_context(struct fs_context *fc); 418c2ecf20Sopenharmony_cistatic const struct fs_parameter_spec afs_fs_parameters[]; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct file_system_type afs_fs_type = { 448c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 458c2ecf20Sopenharmony_ci .name = "afs", 468c2ecf20Sopenharmony_ci .init_fs_context = afs_init_fs_context, 478c2ecf20Sopenharmony_ci .parameters = afs_fs_parameters, 488c2ecf20Sopenharmony_ci .kill_sb = afs_kill_super, 498c2ecf20Sopenharmony_ci .fs_flags = FS_RENAME_DOES_D_MOVE, 508c2ecf20Sopenharmony_ci}; 518c2ecf20Sopenharmony_ciMODULE_ALIAS_FS("afs"); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ciint afs_net_id; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic const struct super_operations afs_super_ops = { 568c2ecf20Sopenharmony_ci .statfs = afs_statfs, 578c2ecf20Sopenharmony_ci .alloc_inode = afs_alloc_inode, 588c2ecf20Sopenharmony_ci .drop_inode = afs_drop_inode, 598c2ecf20Sopenharmony_ci .destroy_inode = afs_destroy_inode, 608c2ecf20Sopenharmony_ci .free_inode = afs_free_inode, 618c2ecf20Sopenharmony_ci .evict_inode = afs_evict_inode, 628c2ecf20Sopenharmony_ci .show_devname = afs_show_devname, 638c2ecf20Sopenharmony_ci .show_options = afs_show_options, 648c2ecf20Sopenharmony_ci}; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic struct kmem_cache *afs_inode_cachep; 678c2ecf20Sopenharmony_cistatic atomic_t afs_count_active_inodes; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cienum afs_param { 708c2ecf20Sopenharmony_ci Opt_autocell, 718c2ecf20Sopenharmony_ci Opt_dyn, 728c2ecf20Sopenharmony_ci Opt_flock, 738c2ecf20Sopenharmony_ci Opt_source, 748c2ecf20Sopenharmony_ci}; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic const struct constant_table afs_param_flock[] = { 778c2ecf20Sopenharmony_ci {"local", afs_flock_mode_local }, 788c2ecf20Sopenharmony_ci {"openafs", afs_flock_mode_openafs }, 798c2ecf20Sopenharmony_ci {"strict", afs_flock_mode_strict }, 808c2ecf20Sopenharmony_ci {"write", afs_flock_mode_write }, 818c2ecf20Sopenharmony_ci {} 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic const struct fs_parameter_spec afs_fs_parameters[] = { 858c2ecf20Sopenharmony_ci fsparam_flag ("autocell", Opt_autocell), 868c2ecf20Sopenharmony_ci fsparam_flag ("dyn", Opt_dyn), 878c2ecf20Sopenharmony_ci fsparam_enum ("flock", Opt_flock, afs_param_flock), 888c2ecf20Sopenharmony_ci fsparam_string("source", Opt_source), 898c2ecf20Sopenharmony_ci {} 908c2ecf20Sopenharmony_ci}; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/* 938c2ecf20Sopenharmony_ci * initialise the filesystem 948c2ecf20Sopenharmony_ci */ 958c2ecf20Sopenharmony_ciint __init afs_fs_init(void) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci int ret; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci _enter(""); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* create ourselves an inode cache */ 1028c2ecf20Sopenharmony_ci atomic_set(&afs_count_active_inodes, 0); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci ret = -ENOMEM; 1058c2ecf20Sopenharmony_ci afs_inode_cachep = kmem_cache_create("afs_inode_cache", 1068c2ecf20Sopenharmony_ci sizeof(struct afs_vnode), 1078c2ecf20Sopenharmony_ci 0, 1088c2ecf20Sopenharmony_ci SLAB_HWCACHE_ALIGN|SLAB_ACCOUNT, 1098c2ecf20Sopenharmony_ci afs_i_init_once); 1108c2ecf20Sopenharmony_ci if (!afs_inode_cachep) { 1118c2ecf20Sopenharmony_ci printk(KERN_NOTICE "kAFS: Failed to allocate inode cache\n"); 1128c2ecf20Sopenharmony_ci return ret; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci /* now export our filesystem to lesser mortals */ 1168c2ecf20Sopenharmony_ci ret = register_filesystem(&afs_fs_type); 1178c2ecf20Sopenharmony_ci if (ret < 0) { 1188c2ecf20Sopenharmony_ci kmem_cache_destroy(afs_inode_cachep); 1198c2ecf20Sopenharmony_ci _leave(" = %d", ret); 1208c2ecf20Sopenharmony_ci return ret; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci _leave(" = 0"); 1248c2ecf20Sopenharmony_ci return 0; 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci/* 1288c2ecf20Sopenharmony_ci * clean up the filesystem 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_civoid afs_fs_exit(void) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci _enter(""); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci afs_mntpt_kill_timer(); 1358c2ecf20Sopenharmony_ci unregister_filesystem(&afs_fs_type); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (atomic_read(&afs_count_active_inodes) != 0) { 1388c2ecf20Sopenharmony_ci printk("kAFS: %d active inode objects still present\n", 1398c2ecf20Sopenharmony_ci atomic_read(&afs_count_active_inodes)); 1408c2ecf20Sopenharmony_ci BUG(); 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci /* 1448c2ecf20Sopenharmony_ci * Make sure all delayed rcu free inodes are flushed before we 1458c2ecf20Sopenharmony_ci * destroy cache. 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ci rcu_barrier(); 1488c2ecf20Sopenharmony_ci kmem_cache_destroy(afs_inode_cachep); 1498c2ecf20Sopenharmony_ci _leave(""); 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci/* 1538c2ecf20Sopenharmony_ci * Display the mount device name in /proc/mounts. 1548c2ecf20Sopenharmony_ci */ 1558c2ecf20Sopenharmony_cistatic int afs_show_devname(struct seq_file *m, struct dentry *root) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci struct afs_super_info *as = AFS_FS_S(root->d_sb); 1588c2ecf20Sopenharmony_ci struct afs_volume *volume = as->volume; 1598c2ecf20Sopenharmony_ci struct afs_cell *cell = as->cell; 1608c2ecf20Sopenharmony_ci const char *suf = ""; 1618c2ecf20Sopenharmony_ci char pref = '%'; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if (as->dyn_root) { 1648c2ecf20Sopenharmony_ci seq_puts(m, "none"); 1658c2ecf20Sopenharmony_ci return 0; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci switch (volume->type) { 1698c2ecf20Sopenharmony_ci case AFSVL_RWVOL: 1708c2ecf20Sopenharmony_ci break; 1718c2ecf20Sopenharmony_ci case AFSVL_ROVOL: 1728c2ecf20Sopenharmony_ci pref = '#'; 1738c2ecf20Sopenharmony_ci if (volume->type_force) 1748c2ecf20Sopenharmony_ci suf = ".readonly"; 1758c2ecf20Sopenharmony_ci break; 1768c2ecf20Sopenharmony_ci case AFSVL_BACKVOL: 1778c2ecf20Sopenharmony_ci pref = '#'; 1788c2ecf20Sopenharmony_ci suf = ".backup"; 1798c2ecf20Sopenharmony_ci break; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci seq_printf(m, "%c%s:%s%s", pref, cell->name, volume->name, suf); 1838c2ecf20Sopenharmony_ci return 0; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci/* 1878c2ecf20Sopenharmony_ci * Display the mount options in /proc/mounts. 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_cistatic int afs_show_options(struct seq_file *m, struct dentry *root) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci struct afs_super_info *as = AFS_FS_S(root->d_sb); 1928c2ecf20Sopenharmony_ci const char *p = NULL; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (as->dyn_root) 1958c2ecf20Sopenharmony_ci seq_puts(m, ",dyn"); 1968c2ecf20Sopenharmony_ci if (test_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(d_inode(root))->flags)) 1978c2ecf20Sopenharmony_ci seq_puts(m, ",autocell"); 1988c2ecf20Sopenharmony_ci switch (as->flock_mode) { 1998c2ecf20Sopenharmony_ci case afs_flock_mode_unset: break; 2008c2ecf20Sopenharmony_ci case afs_flock_mode_local: p = "local"; break; 2018c2ecf20Sopenharmony_ci case afs_flock_mode_openafs: p = "openafs"; break; 2028c2ecf20Sopenharmony_ci case afs_flock_mode_strict: p = "strict"; break; 2038c2ecf20Sopenharmony_ci case afs_flock_mode_write: p = "write"; break; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci if (p) 2068c2ecf20Sopenharmony_ci seq_printf(m, ",flock=%s", p); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci return 0; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci/* 2128c2ecf20Sopenharmony_ci * Parse the source name to get cell name, volume name, volume type and R/W 2138c2ecf20Sopenharmony_ci * selector. 2148c2ecf20Sopenharmony_ci * 2158c2ecf20Sopenharmony_ci * This can be one of the following: 2168c2ecf20Sopenharmony_ci * "%[cell:]volume[.]" R/W volume 2178c2ecf20Sopenharmony_ci * "#[cell:]volume[.]" R/O or R/W volume (R/O parent), 2188c2ecf20Sopenharmony_ci * or R/W (R/W parent) volume 2198c2ecf20Sopenharmony_ci * "%[cell:]volume.readonly" R/O volume 2208c2ecf20Sopenharmony_ci * "#[cell:]volume.readonly" R/O volume 2218c2ecf20Sopenharmony_ci * "%[cell:]volume.backup" Backup volume 2228c2ecf20Sopenharmony_ci * "#[cell:]volume.backup" Backup volume 2238c2ecf20Sopenharmony_ci */ 2248c2ecf20Sopenharmony_cistatic int afs_parse_source(struct fs_context *fc, struct fs_parameter *param) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci struct afs_fs_context *ctx = fc->fs_private; 2278c2ecf20Sopenharmony_ci struct afs_cell *cell; 2288c2ecf20Sopenharmony_ci const char *cellname, *suffix, *name = param->string; 2298c2ecf20Sopenharmony_ci int cellnamesz; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci _enter(",%s", name); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci if (fc->source) 2348c2ecf20Sopenharmony_ci return invalf(fc, "kAFS: Multiple sources not supported"); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci if (!name) { 2378c2ecf20Sopenharmony_ci printk(KERN_ERR "kAFS: no volume name specified\n"); 2388c2ecf20Sopenharmony_ci return -EINVAL; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if ((name[0] != '%' && name[0] != '#') || !name[1]) { 2428c2ecf20Sopenharmony_ci /* To use dynroot, we don't want to have to provide a source */ 2438c2ecf20Sopenharmony_ci if (strcmp(name, "none") == 0) { 2448c2ecf20Sopenharmony_ci ctx->no_cell = true; 2458c2ecf20Sopenharmony_ci return 0; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci printk(KERN_ERR "kAFS: unparsable volume name\n"); 2488c2ecf20Sopenharmony_ci return -EINVAL; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci /* determine the type of volume we're looking for */ 2528c2ecf20Sopenharmony_ci if (name[0] == '%') { 2538c2ecf20Sopenharmony_ci ctx->type = AFSVL_RWVOL; 2548c2ecf20Sopenharmony_ci ctx->force = true; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci name++; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci /* split the cell name out if there is one */ 2598c2ecf20Sopenharmony_ci ctx->volname = strchr(name, ':'); 2608c2ecf20Sopenharmony_ci if (ctx->volname) { 2618c2ecf20Sopenharmony_ci cellname = name; 2628c2ecf20Sopenharmony_ci cellnamesz = ctx->volname - name; 2638c2ecf20Sopenharmony_ci ctx->volname++; 2648c2ecf20Sopenharmony_ci } else { 2658c2ecf20Sopenharmony_ci ctx->volname = name; 2668c2ecf20Sopenharmony_ci cellname = NULL; 2678c2ecf20Sopenharmony_ci cellnamesz = 0; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci /* the volume type is further affected by a possible suffix */ 2718c2ecf20Sopenharmony_ci suffix = strrchr(ctx->volname, '.'); 2728c2ecf20Sopenharmony_ci if (suffix) { 2738c2ecf20Sopenharmony_ci if (strcmp(suffix, ".readonly") == 0) { 2748c2ecf20Sopenharmony_ci ctx->type = AFSVL_ROVOL; 2758c2ecf20Sopenharmony_ci ctx->force = true; 2768c2ecf20Sopenharmony_ci } else if (strcmp(suffix, ".backup") == 0) { 2778c2ecf20Sopenharmony_ci ctx->type = AFSVL_BACKVOL; 2788c2ecf20Sopenharmony_ci ctx->force = true; 2798c2ecf20Sopenharmony_ci } else if (suffix[1] == 0) { 2808c2ecf20Sopenharmony_ci } else { 2818c2ecf20Sopenharmony_ci suffix = NULL; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci ctx->volnamesz = suffix ? 2868c2ecf20Sopenharmony_ci suffix - ctx->volname : strlen(ctx->volname); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci _debug("cell %*.*s [%p]", 2898c2ecf20Sopenharmony_ci cellnamesz, cellnamesz, cellname ?: "", ctx->cell); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci /* lookup the cell record */ 2928c2ecf20Sopenharmony_ci if (cellname) { 2938c2ecf20Sopenharmony_ci cell = afs_lookup_cell(ctx->net, cellname, cellnamesz, 2948c2ecf20Sopenharmony_ci NULL, false); 2958c2ecf20Sopenharmony_ci if (IS_ERR(cell)) { 2968c2ecf20Sopenharmony_ci pr_err("kAFS: unable to lookup cell '%*.*s'\n", 2978c2ecf20Sopenharmony_ci cellnamesz, cellnamesz, cellname ?: ""); 2988c2ecf20Sopenharmony_ci return PTR_ERR(cell); 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci afs_unuse_cell(ctx->net, ctx->cell, afs_cell_trace_unuse_parse); 3018c2ecf20Sopenharmony_ci afs_see_cell(cell, afs_cell_trace_see_source); 3028c2ecf20Sopenharmony_ci ctx->cell = cell; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci _debug("CELL:%s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s", 3068c2ecf20Sopenharmony_ci ctx->cell->name, ctx->cell, 3078c2ecf20Sopenharmony_ci ctx->volnamesz, ctx->volnamesz, ctx->volname, 3088c2ecf20Sopenharmony_ci suffix ?: "-", ctx->type, ctx->force ? " FORCE" : ""); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci fc->source = param->string; 3118c2ecf20Sopenharmony_ci param->string = NULL; 3128c2ecf20Sopenharmony_ci return 0; 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci/* 3168c2ecf20Sopenharmony_ci * Parse a single mount parameter. 3178c2ecf20Sopenharmony_ci */ 3188c2ecf20Sopenharmony_cistatic int afs_parse_param(struct fs_context *fc, struct fs_parameter *param) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci struct fs_parse_result result; 3218c2ecf20Sopenharmony_ci struct afs_fs_context *ctx = fc->fs_private; 3228c2ecf20Sopenharmony_ci int opt; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci opt = fs_parse(fc, afs_fs_parameters, param, &result); 3258c2ecf20Sopenharmony_ci if (opt < 0) 3268c2ecf20Sopenharmony_ci return opt; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci switch (opt) { 3298c2ecf20Sopenharmony_ci case Opt_source: 3308c2ecf20Sopenharmony_ci return afs_parse_source(fc, param); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci case Opt_autocell: 3338c2ecf20Sopenharmony_ci ctx->autocell = true; 3348c2ecf20Sopenharmony_ci break; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci case Opt_dyn: 3378c2ecf20Sopenharmony_ci ctx->dyn_root = true; 3388c2ecf20Sopenharmony_ci break; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci case Opt_flock: 3418c2ecf20Sopenharmony_ci ctx->flock_mode = result.uint_32; 3428c2ecf20Sopenharmony_ci break; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci default: 3458c2ecf20Sopenharmony_ci return -EINVAL; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci _leave(" = 0"); 3498c2ecf20Sopenharmony_ci return 0; 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci/* 3538c2ecf20Sopenharmony_ci * Validate the options, get the cell key and look up the volume. 3548c2ecf20Sopenharmony_ci */ 3558c2ecf20Sopenharmony_cistatic int afs_validate_fc(struct fs_context *fc) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci struct afs_fs_context *ctx = fc->fs_private; 3588c2ecf20Sopenharmony_ci struct afs_volume *volume; 3598c2ecf20Sopenharmony_ci struct afs_cell *cell; 3608c2ecf20Sopenharmony_ci struct key *key; 3618c2ecf20Sopenharmony_ci int ret; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci if (!ctx->dyn_root) { 3648c2ecf20Sopenharmony_ci if (ctx->no_cell) { 3658c2ecf20Sopenharmony_ci pr_warn("kAFS: Can only specify source 'none' with -o dyn\n"); 3668c2ecf20Sopenharmony_ci return -EINVAL; 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci if (!ctx->cell) { 3708c2ecf20Sopenharmony_ci pr_warn("kAFS: No cell specified\n"); 3718c2ecf20Sopenharmony_ci return -EDESTADDRREQ; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci reget_key: 3758c2ecf20Sopenharmony_ci /* We try to do the mount securely. */ 3768c2ecf20Sopenharmony_ci key = afs_request_key(ctx->cell); 3778c2ecf20Sopenharmony_ci if (IS_ERR(key)) 3788c2ecf20Sopenharmony_ci return PTR_ERR(key); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci ctx->key = key; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci if (ctx->volume) { 3838c2ecf20Sopenharmony_ci afs_put_volume(ctx->net, ctx->volume, 3848c2ecf20Sopenharmony_ci afs_volume_trace_put_validate_fc); 3858c2ecf20Sopenharmony_ci ctx->volume = NULL; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci if (test_bit(AFS_CELL_FL_CHECK_ALIAS, &ctx->cell->flags)) { 3898c2ecf20Sopenharmony_ci ret = afs_cell_detect_alias(ctx->cell, key); 3908c2ecf20Sopenharmony_ci if (ret < 0) 3918c2ecf20Sopenharmony_ci return ret; 3928c2ecf20Sopenharmony_ci if (ret == 1) { 3938c2ecf20Sopenharmony_ci _debug("switch to alias"); 3948c2ecf20Sopenharmony_ci key_put(ctx->key); 3958c2ecf20Sopenharmony_ci ctx->key = NULL; 3968c2ecf20Sopenharmony_ci cell = afs_use_cell(ctx->cell->alias_of, 3978c2ecf20Sopenharmony_ci afs_cell_trace_use_fc_alias); 3988c2ecf20Sopenharmony_ci afs_unuse_cell(ctx->net, ctx->cell, afs_cell_trace_unuse_fc); 3998c2ecf20Sopenharmony_ci ctx->cell = cell; 4008c2ecf20Sopenharmony_ci goto reget_key; 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci volume = afs_create_volume(ctx); 4058c2ecf20Sopenharmony_ci if (IS_ERR(volume)) 4068c2ecf20Sopenharmony_ci return PTR_ERR(volume); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci ctx->volume = volume; 4098c2ecf20Sopenharmony_ci if (volume->type != AFSVL_RWVOL) 4108c2ecf20Sopenharmony_ci ctx->flock_mode = afs_flock_mode_local; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci return 0; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci/* 4178c2ecf20Sopenharmony_ci * check a superblock to see if it's the one we're looking for 4188c2ecf20Sopenharmony_ci */ 4198c2ecf20Sopenharmony_cistatic int afs_test_super(struct super_block *sb, struct fs_context *fc) 4208c2ecf20Sopenharmony_ci{ 4218c2ecf20Sopenharmony_ci struct afs_fs_context *ctx = fc->fs_private; 4228c2ecf20Sopenharmony_ci struct afs_super_info *as = AFS_FS_S(sb); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci return (as->net_ns == fc->net_ns && 4258c2ecf20Sopenharmony_ci as->volume && 4268c2ecf20Sopenharmony_ci as->volume->vid == ctx->volume->vid && 4278c2ecf20Sopenharmony_ci as->cell == ctx->cell && 4288c2ecf20Sopenharmony_ci !as->dyn_root); 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cistatic int afs_dynroot_test_super(struct super_block *sb, struct fs_context *fc) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci struct afs_super_info *as = AFS_FS_S(sb); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci return (as->net_ns == fc->net_ns && 4368c2ecf20Sopenharmony_ci as->dyn_root); 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic int afs_set_super(struct super_block *sb, struct fs_context *fc) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci return set_anon_super(sb, NULL); 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci/* 4458c2ecf20Sopenharmony_ci * fill in the superblock 4468c2ecf20Sopenharmony_ci */ 4478c2ecf20Sopenharmony_cistatic int afs_fill_super(struct super_block *sb, struct afs_fs_context *ctx) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci struct afs_super_info *as = AFS_FS_S(sb); 4508c2ecf20Sopenharmony_ci struct inode *inode = NULL; 4518c2ecf20Sopenharmony_ci int ret; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci _enter(""); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci /* fill in the superblock */ 4568c2ecf20Sopenharmony_ci sb->s_blocksize = PAGE_SIZE; 4578c2ecf20Sopenharmony_ci sb->s_blocksize_bits = PAGE_SHIFT; 4588c2ecf20Sopenharmony_ci sb->s_maxbytes = MAX_LFS_FILESIZE; 4598c2ecf20Sopenharmony_ci sb->s_magic = AFS_FS_MAGIC; 4608c2ecf20Sopenharmony_ci sb->s_op = &afs_super_ops; 4618c2ecf20Sopenharmony_ci if (!as->dyn_root) 4628c2ecf20Sopenharmony_ci sb->s_xattr = afs_xattr_handlers; 4638c2ecf20Sopenharmony_ci ret = super_setup_bdi(sb); 4648c2ecf20Sopenharmony_ci if (ret) 4658c2ecf20Sopenharmony_ci return ret; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci /* allocate the root inode and dentry */ 4688c2ecf20Sopenharmony_ci if (as->dyn_root) { 4698c2ecf20Sopenharmony_ci inode = afs_iget_pseudo_dir(sb, true); 4708c2ecf20Sopenharmony_ci } else { 4718c2ecf20Sopenharmony_ci sprintf(sb->s_id, "%llu", as->volume->vid); 4728c2ecf20Sopenharmony_ci afs_activate_volume(as->volume); 4738c2ecf20Sopenharmony_ci inode = afs_root_iget(sb, ctx->key); 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci if (IS_ERR(inode)) 4778c2ecf20Sopenharmony_ci return PTR_ERR(inode); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci if (ctx->autocell || as->dyn_root) 4808c2ecf20Sopenharmony_ci set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci ret = -ENOMEM; 4838c2ecf20Sopenharmony_ci sb->s_root = d_make_root(inode); 4848c2ecf20Sopenharmony_ci if (!sb->s_root) 4858c2ecf20Sopenharmony_ci goto error; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci if (as->dyn_root) { 4888c2ecf20Sopenharmony_ci sb->s_d_op = &afs_dynroot_dentry_operations; 4898c2ecf20Sopenharmony_ci ret = afs_dynroot_populate(sb); 4908c2ecf20Sopenharmony_ci if (ret < 0) 4918c2ecf20Sopenharmony_ci goto error; 4928c2ecf20Sopenharmony_ci } else { 4938c2ecf20Sopenharmony_ci sb->s_d_op = &afs_fs_dentry_operations; 4948c2ecf20Sopenharmony_ci rcu_assign_pointer(as->volume->sb, sb); 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci _leave(" = 0"); 4988c2ecf20Sopenharmony_ci return 0; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_cierror: 5018c2ecf20Sopenharmony_ci _leave(" = %d", ret); 5028c2ecf20Sopenharmony_ci return ret; 5038c2ecf20Sopenharmony_ci} 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_cistatic struct afs_super_info *afs_alloc_sbi(struct fs_context *fc) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci struct afs_fs_context *ctx = fc->fs_private; 5088c2ecf20Sopenharmony_ci struct afs_super_info *as; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL); 5118c2ecf20Sopenharmony_ci if (as) { 5128c2ecf20Sopenharmony_ci as->net_ns = get_net(fc->net_ns); 5138c2ecf20Sopenharmony_ci as->flock_mode = ctx->flock_mode; 5148c2ecf20Sopenharmony_ci if (ctx->dyn_root) { 5158c2ecf20Sopenharmony_ci as->dyn_root = true; 5168c2ecf20Sopenharmony_ci } else { 5178c2ecf20Sopenharmony_ci as->cell = afs_use_cell(ctx->cell, afs_cell_trace_use_sbi); 5188c2ecf20Sopenharmony_ci as->volume = afs_get_volume(ctx->volume, 5198c2ecf20Sopenharmony_ci afs_volume_trace_get_alloc_sbi); 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci return as; 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic void afs_destroy_sbi(struct afs_super_info *as) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci if (as) { 5288c2ecf20Sopenharmony_ci struct afs_net *net = afs_net(as->net_ns); 5298c2ecf20Sopenharmony_ci afs_put_volume(net, as->volume, afs_volume_trace_put_destroy_sbi); 5308c2ecf20Sopenharmony_ci afs_unuse_cell(net, as->cell, afs_cell_trace_unuse_sbi); 5318c2ecf20Sopenharmony_ci put_net(as->net_ns); 5328c2ecf20Sopenharmony_ci kfree(as); 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cistatic void afs_kill_super(struct super_block *sb) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci struct afs_super_info *as = AFS_FS_S(sb); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci if (as->dyn_root) 5418c2ecf20Sopenharmony_ci afs_dynroot_depopulate(sb); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci /* Clear the callback interests (which will do ilookup5) before 5448c2ecf20Sopenharmony_ci * deactivating the superblock. 5458c2ecf20Sopenharmony_ci */ 5468c2ecf20Sopenharmony_ci if (as->volume) 5478c2ecf20Sopenharmony_ci rcu_assign_pointer(as->volume->sb, NULL); 5488c2ecf20Sopenharmony_ci kill_anon_super(sb); 5498c2ecf20Sopenharmony_ci if (as->volume) 5508c2ecf20Sopenharmony_ci afs_deactivate_volume(as->volume); 5518c2ecf20Sopenharmony_ci afs_destroy_sbi(as); 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci/* 5558c2ecf20Sopenharmony_ci * Get an AFS superblock and root directory. 5568c2ecf20Sopenharmony_ci */ 5578c2ecf20Sopenharmony_cistatic int afs_get_tree(struct fs_context *fc) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci struct afs_fs_context *ctx = fc->fs_private; 5608c2ecf20Sopenharmony_ci struct super_block *sb; 5618c2ecf20Sopenharmony_ci struct afs_super_info *as; 5628c2ecf20Sopenharmony_ci int ret; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci ret = afs_validate_fc(fc); 5658c2ecf20Sopenharmony_ci if (ret) 5668c2ecf20Sopenharmony_ci goto error; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci _enter(""); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci /* allocate a superblock info record */ 5718c2ecf20Sopenharmony_ci ret = -ENOMEM; 5728c2ecf20Sopenharmony_ci as = afs_alloc_sbi(fc); 5738c2ecf20Sopenharmony_ci if (!as) 5748c2ecf20Sopenharmony_ci goto error; 5758c2ecf20Sopenharmony_ci fc->s_fs_info = as; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci /* allocate a deviceless superblock */ 5788c2ecf20Sopenharmony_ci sb = sget_fc(fc, 5798c2ecf20Sopenharmony_ci as->dyn_root ? afs_dynroot_test_super : afs_test_super, 5808c2ecf20Sopenharmony_ci afs_set_super); 5818c2ecf20Sopenharmony_ci if (IS_ERR(sb)) { 5828c2ecf20Sopenharmony_ci ret = PTR_ERR(sb); 5838c2ecf20Sopenharmony_ci goto error; 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (!sb->s_root) { 5878c2ecf20Sopenharmony_ci /* initial superblock/root creation */ 5888c2ecf20Sopenharmony_ci _debug("create"); 5898c2ecf20Sopenharmony_ci ret = afs_fill_super(sb, ctx); 5908c2ecf20Sopenharmony_ci if (ret < 0) 5918c2ecf20Sopenharmony_ci goto error_sb; 5928c2ecf20Sopenharmony_ci sb->s_flags |= SB_ACTIVE; 5938c2ecf20Sopenharmony_ci } else { 5948c2ecf20Sopenharmony_ci _debug("reuse"); 5958c2ecf20Sopenharmony_ci ASSERTCMP(sb->s_flags, &, SB_ACTIVE); 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci fc->root = dget(sb->s_root); 5998c2ecf20Sopenharmony_ci trace_afs_get_tree(as->cell, as->volume); 6008c2ecf20Sopenharmony_ci _leave(" = 0 [%p]", sb); 6018c2ecf20Sopenharmony_ci return 0; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_cierror_sb: 6048c2ecf20Sopenharmony_ci deactivate_locked_super(sb); 6058c2ecf20Sopenharmony_cierror: 6068c2ecf20Sopenharmony_ci _leave(" = %d", ret); 6078c2ecf20Sopenharmony_ci return ret; 6088c2ecf20Sopenharmony_ci} 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_cistatic void afs_free_fc(struct fs_context *fc) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci struct afs_fs_context *ctx = fc->fs_private; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci afs_destroy_sbi(fc->s_fs_info); 6158c2ecf20Sopenharmony_ci afs_put_volume(ctx->net, ctx->volume, afs_volume_trace_put_free_fc); 6168c2ecf20Sopenharmony_ci afs_unuse_cell(ctx->net, ctx->cell, afs_cell_trace_unuse_fc); 6178c2ecf20Sopenharmony_ci key_put(ctx->key); 6188c2ecf20Sopenharmony_ci kfree(ctx); 6198c2ecf20Sopenharmony_ci} 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_cistatic const struct fs_context_operations afs_context_ops = { 6228c2ecf20Sopenharmony_ci .free = afs_free_fc, 6238c2ecf20Sopenharmony_ci .parse_param = afs_parse_param, 6248c2ecf20Sopenharmony_ci .get_tree = afs_get_tree, 6258c2ecf20Sopenharmony_ci}; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci/* 6288c2ecf20Sopenharmony_ci * Set up the filesystem mount context. 6298c2ecf20Sopenharmony_ci */ 6308c2ecf20Sopenharmony_cistatic int afs_init_fs_context(struct fs_context *fc) 6318c2ecf20Sopenharmony_ci{ 6328c2ecf20Sopenharmony_ci struct afs_fs_context *ctx; 6338c2ecf20Sopenharmony_ci struct afs_cell *cell; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci ctx = kzalloc(sizeof(struct afs_fs_context), GFP_KERNEL); 6368c2ecf20Sopenharmony_ci if (!ctx) 6378c2ecf20Sopenharmony_ci return -ENOMEM; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci ctx->type = AFSVL_ROVOL; 6408c2ecf20Sopenharmony_ci ctx->net = afs_net(fc->net_ns); 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci /* Default to the workstation cell. */ 6438c2ecf20Sopenharmony_ci cell = afs_find_cell(ctx->net, NULL, 0, afs_cell_trace_use_fc); 6448c2ecf20Sopenharmony_ci if (IS_ERR(cell)) 6458c2ecf20Sopenharmony_ci cell = NULL; 6468c2ecf20Sopenharmony_ci ctx->cell = cell; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci fc->fs_private = ctx; 6498c2ecf20Sopenharmony_ci fc->ops = &afs_context_ops; 6508c2ecf20Sopenharmony_ci return 0; 6518c2ecf20Sopenharmony_ci} 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci/* 6548c2ecf20Sopenharmony_ci * Initialise an inode cache slab element prior to any use. Note that 6558c2ecf20Sopenharmony_ci * afs_alloc_inode() *must* reset anything that could incorrectly leak from one 6568c2ecf20Sopenharmony_ci * inode to another. 6578c2ecf20Sopenharmony_ci */ 6588c2ecf20Sopenharmony_cistatic void afs_i_init_once(void *_vnode) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci struct afs_vnode *vnode = _vnode; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci memset(vnode, 0, sizeof(*vnode)); 6638c2ecf20Sopenharmony_ci inode_init_once(&vnode->vfs_inode); 6648c2ecf20Sopenharmony_ci mutex_init(&vnode->io_lock); 6658c2ecf20Sopenharmony_ci init_rwsem(&vnode->validate_lock); 6668c2ecf20Sopenharmony_ci spin_lock_init(&vnode->wb_lock); 6678c2ecf20Sopenharmony_ci spin_lock_init(&vnode->lock); 6688c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&vnode->wb_keys); 6698c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&vnode->pending_locks); 6708c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&vnode->granted_locks); 6718c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&vnode->lock_work, afs_lock_work); 6728c2ecf20Sopenharmony_ci seqlock_init(&vnode->cb_lock); 6738c2ecf20Sopenharmony_ci} 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci/* 6768c2ecf20Sopenharmony_ci * allocate an AFS inode struct from our slab cache 6778c2ecf20Sopenharmony_ci */ 6788c2ecf20Sopenharmony_cistatic struct inode *afs_alloc_inode(struct super_block *sb) 6798c2ecf20Sopenharmony_ci{ 6808c2ecf20Sopenharmony_ci struct afs_vnode *vnode; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci vnode = kmem_cache_alloc(afs_inode_cachep, GFP_KERNEL); 6838c2ecf20Sopenharmony_ci if (!vnode) 6848c2ecf20Sopenharmony_ci return NULL; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci atomic_inc(&afs_count_active_inodes); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci /* Reset anything that shouldn't leak from one inode to the next. */ 6898c2ecf20Sopenharmony_ci memset(&vnode->fid, 0, sizeof(vnode->fid)); 6908c2ecf20Sopenharmony_ci memset(&vnode->status, 0, sizeof(vnode->status)); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci vnode->volume = NULL; 6938c2ecf20Sopenharmony_ci vnode->lock_key = NULL; 6948c2ecf20Sopenharmony_ci vnode->permit_cache = NULL; 6958c2ecf20Sopenharmony_ci#ifdef CONFIG_AFS_FSCACHE 6968c2ecf20Sopenharmony_ci vnode->cache = NULL; 6978c2ecf20Sopenharmony_ci#endif 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci vnode->flags = 1 << AFS_VNODE_UNSET; 7008c2ecf20Sopenharmony_ci vnode->lock_state = AFS_VNODE_LOCK_NONE; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci init_rwsem(&vnode->rmdir_lock); 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci _leave(" = %p", &vnode->vfs_inode); 7058c2ecf20Sopenharmony_ci return &vnode->vfs_inode; 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cistatic void afs_free_inode(struct inode *inode) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci kmem_cache_free(afs_inode_cachep, AFS_FS_I(inode)); 7118c2ecf20Sopenharmony_ci} 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci/* 7148c2ecf20Sopenharmony_ci * destroy an AFS inode struct 7158c2ecf20Sopenharmony_ci */ 7168c2ecf20Sopenharmony_cistatic void afs_destroy_inode(struct inode *inode) 7178c2ecf20Sopenharmony_ci{ 7188c2ecf20Sopenharmony_ci struct afs_vnode *vnode = AFS_FS_I(inode); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci _enter("%p{%llx:%llu}", inode, vnode->fid.vid, vnode->fid.vnode); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci _debug("DESTROY INODE %p", inode); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci atomic_dec(&afs_count_active_inodes); 7258c2ecf20Sopenharmony_ci} 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_cistatic void afs_get_volume_status_success(struct afs_operation *op) 7288c2ecf20Sopenharmony_ci{ 7298c2ecf20Sopenharmony_ci struct afs_volume_status *vs = &op->volstatus.vs; 7308c2ecf20Sopenharmony_ci struct kstatfs *buf = op->volstatus.buf; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci if (vs->max_quota == 0) 7338c2ecf20Sopenharmony_ci buf->f_blocks = vs->part_max_blocks; 7348c2ecf20Sopenharmony_ci else 7358c2ecf20Sopenharmony_ci buf->f_blocks = vs->max_quota; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci if (buf->f_blocks > vs->blocks_in_use) 7388c2ecf20Sopenharmony_ci buf->f_bavail = buf->f_bfree = 7398c2ecf20Sopenharmony_ci buf->f_blocks - vs->blocks_in_use; 7408c2ecf20Sopenharmony_ci} 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_cistatic const struct afs_operation_ops afs_get_volume_status_operation = { 7438c2ecf20Sopenharmony_ci .issue_afs_rpc = afs_fs_get_volume_status, 7448c2ecf20Sopenharmony_ci .issue_yfs_rpc = yfs_fs_get_volume_status, 7458c2ecf20Sopenharmony_ci .success = afs_get_volume_status_success, 7468c2ecf20Sopenharmony_ci}; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci/* 7498c2ecf20Sopenharmony_ci * return information about an AFS volume 7508c2ecf20Sopenharmony_ci */ 7518c2ecf20Sopenharmony_cistatic int afs_statfs(struct dentry *dentry, struct kstatfs *buf) 7528c2ecf20Sopenharmony_ci{ 7538c2ecf20Sopenharmony_ci struct afs_super_info *as = AFS_FS_S(dentry->d_sb); 7548c2ecf20Sopenharmony_ci struct afs_operation *op; 7558c2ecf20Sopenharmony_ci struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry)); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci buf->f_type = dentry->d_sb->s_magic; 7588c2ecf20Sopenharmony_ci buf->f_bsize = AFS_BLOCK_SIZE; 7598c2ecf20Sopenharmony_ci buf->f_namelen = AFSNAMEMAX - 1; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (as->dyn_root) { 7628c2ecf20Sopenharmony_ci buf->f_blocks = 1; 7638c2ecf20Sopenharmony_ci buf->f_bavail = 0; 7648c2ecf20Sopenharmony_ci buf->f_bfree = 0; 7658c2ecf20Sopenharmony_ci return 0; 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci op = afs_alloc_operation(NULL, as->volume); 7698c2ecf20Sopenharmony_ci if (IS_ERR(op)) 7708c2ecf20Sopenharmony_ci return PTR_ERR(op); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci afs_op_set_vnode(op, 0, vnode); 7738c2ecf20Sopenharmony_ci op->nr_files = 1; 7748c2ecf20Sopenharmony_ci op->volstatus.buf = buf; 7758c2ecf20Sopenharmony_ci op->ops = &afs_get_volume_status_operation; 7768c2ecf20Sopenharmony_ci return afs_do_sync_operation(op); 7778c2ecf20Sopenharmony_ci} 778