1ec26815aSDavid Howells /* AFS superblock handling 2ec26815aSDavid Howells * 313fcc683SDavid Howells * Copyright (c) 2002, 2007, 2018 Red Hat, Inc. All rights reserved. 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * This software may be freely redistributed under the terms of the 61da177e4SLinus Torvalds * GNU General Public License. 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 91da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 101da177e4SLinus Torvalds * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * Authors: David Howells <dhowells@redhat.com> 1344d1b980SDavid Woodhouse * David Woodhouse <dwmw2@infradead.org> 141da177e4SLinus Torvalds * 151da177e4SLinus Torvalds */ 161da177e4SLinus Torvalds 171da177e4SLinus Torvalds #include <linux/kernel.h> 181da177e4SLinus Torvalds #include <linux/module.h> 19bec5eb61Swanglei #include <linux/mount.h> 201da177e4SLinus Torvalds #include <linux/init.h> 211da177e4SLinus Torvalds #include <linux/slab.h> 221da177e4SLinus Torvalds #include <linux/fs.h> 231da177e4SLinus Torvalds #include <linux/pagemap.h> 2413fcc683SDavid Howells #include <linux/fs_parser.h> 2545222b9eSDavid Howells #include <linux/statfs.h> 26e8edc6e0SAlexey Dobriyan #include <linux/sched.h> 27f74f70f8SEric W. Biederman #include <linux/nsproxy.h> 28f044c884SDavid Howells #include <linux/magic.h> 29f74f70f8SEric W. Biederman #include <net/net_namespace.h> 301da177e4SLinus Torvalds #include "internal.h" 311da177e4SLinus Torvalds 3251cc5068SAlexey Dobriyan static void afs_i_init_once(void *foo); 33dde194a6SAl Viro static void afs_kill_super(struct super_block *sb); 341da177e4SLinus Torvalds static struct inode *afs_alloc_inode(struct super_block *sb); 351da177e4SLinus Torvalds static void afs_destroy_inode(struct inode *inode); 3645222b9eSDavid Howells static int afs_statfs(struct dentry *dentry, struct kstatfs *buf); 37677018a6SDavid Howells static int afs_show_devname(struct seq_file *m, struct dentry *root); 38677018a6SDavid Howells static int afs_show_options(struct seq_file *m, struct dentry *root); 3913fcc683SDavid Howells static int afs_init_fs_context(struct fs_context *fc); 4013fcc683SDavid Howells static const struct fs_parameter_description afs_fs_parameters; 411da177e4SLinus Torvalds 421f5ce9e9STrond Myklebust struct file_system_type afs_fs_type = { 431da177e4SLinus Torvalds .owner = THIS_MODULE, 441da177e4SLinus Torvalds .name = "afs", 4513fcc683SDavid Howells .init_fs_context = afs_init_fs_context, 4613fcc683SDavid Howells .parameters = &afs_fs_parameters, 47dde194a6SAl Viro .kill_sb = afs_kill_super, 4879ddbfa5SDavid Howells .fs_flags = FS_RENAME_DOES_D_MOVE, 491da177e4SLinus Torvalds }; 507f78e035SEric W. Biederman MODULE_ALIAS_FS("afs"); 511da177e4SLinus Torvalds 525b86d4ffSDavid Howells int afs_net_id; 535b86d4ffSDavid Howells 54ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations afs_super_ops = { 5545222b9eSDavid Howells .statfs = afs_statfs, 561da177e4SLinus Torvalds .alloc_inode = afs_alloc_inode, 57bec5eb61Swanglei .drop_inode = afs_drop_inode, 581da177e4SLinus Torvalds .destroy_inode = afs_destroy_inode, 59b57922d9SAl Viro .evict_inode = afs_evict_inode, 60677018a6SDavid Howells .show_devname = afs_show_devname, 61677018a6SDavid Howells .show_options = afs_show_options, 621da177e4SLinus Torvalds }; 631da177e4SLinus Torvalds 64e18b890bSChristoph Lameter static struct kmem_cache *afs_inode_cachep; 651da177e4SLinus Torvalds static atomic_t afs_count_active_inodes; 661da177e4SLinus Torvalds 6713fcc683SDavid Howells enum afs_param { 6813fcc683SDavid Howells Opt_autocell, 6913fcc683SDavid Howells Opt_dyn, 70*6c6c1d63SDavid Howells Opt_flock, 7113fcc683SDavid Howells Opt_source, 7280c72fe4SDavid Howells }; 7380c72fe4SDavid Howells 7413fcc683SDavid Howells static const struct fs_parameter_spec afs_param_specs[] = { 7513fcc683SDavid Howells fsparam_flag ("autocell", Opt_autocell), 7613fcc683SDavid Howells fsparam_flag ("dyn", Opt_dyn), 77*6c6c1d63SDavid Howells fsparam_enum ("flock", Opt_flock), 7813fcc683SDavid Howells fsparam_string("source", Opt_source), 7913fcc683SDavid Howells {} 8013fcc683SDavid Howells }; 8113fcc683SDavid Howells 82*6c6c1d63SDavid Howells static const struct fs_parameter_enum afs_param_enums[] = { 83*6c6c1d63SDavid Howells { Opt_flock, "local", afs_flock_mode_local }, 84*6c6c1d63SDavid Howells { Opt_flock, "openafs", afs_flock_mode_openafs }, 85*6c6c1d63SDavid Howells { Opt_flock, "strict", afs_flock_mode_strict }, 86*6c6c1d63SDavid Howells { Opt_flock, "write", afs_flock_mode_write }, 87*6c6c1d63SDavid Howells {} 88*6c6c1d63SDavid Howells }; 89*6c6c1d63SDavid Howells 9013fcc683SDavid Howells static const struct fs_parameter_description afs_fs_parameters = { 9113fcc683SDavid Howells .name = "kAFS", 9213fcc683SDavid Howells .specs = afs_param_specs, 93*6c6c1d63SDavid Howells .enums = afs_param_enums, 9480c72fe4SDavid Howells }; 9580c72fe4SDavid Howells 961da177e4SLinus Torvalds /* 971da177e4SLinus Torvalds * initialise the filesystem 981da177e4SLinus Torvalds */ 991da177e4SLinus Torvalds int __init afs_fs_init(void) 1001da177e4SLinus Torvalds { 1011da177e4SLinus Torvalds int ret; 1021da177e4SLinus Torvalds 1031da177e4SLinus Torvalds _enter(""); 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds /* create ourselves an inode cache */ 1061da177e4SLinus Torvalds atomic_set(&afs_count_active_inodes, 0); 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds ret = -ENOMEM; 1091da177e4SLinus Torvalds afs_inode_cachep = kmem_cache_create("afs_inode_cache", 1101da177e4SLinus Torvalds sizeof(struct afs_vnode), 1111da177e4SLinus Torvalds 0, 1125d097056SVladimir Davydov SLAB_HWCACHE_ALIGN|SLAB_ACCOUNT, 11320c2df83SPaul Mundt afs_i_init_once); 1141da177e4SLinus Torvalds if (!afs_inode_cachep) { 1151da177e4SLinus Torvalds printk(KERN_NOTICE "kAFS: Failed to allocate inode cache\n"); 1161da177e4SLinus Torvalds return ret; 1171da177e4SLinus Torvalds } 1181da177e4SLinus Torvalds 1191da177e4SLinus Torvalds /* now export our filesystem to lesser mortals */ 1201da177e4SLinus Torvalds ret = register_filesystem(&afs_fs_type); 1211da177e4SLinus Torvalds if (ret < 0) { 1221da177e4SLinus Torvalds kmem_cache_destroy(afs_inode_cachep); 12308e0e7c8SDavid Howells _leave(" = %d", ret); 1241da177e4SLinus Torvalds return ret; 1251da177e4SLinus Torvalds } 1261da177e4SLinus Torvalds 12708e0e7c8SDavid Howells _leave(" = 0"); 1281da177e4SLinus Torvalds return 0; 129ec26815aSDavid Howells } 1301da177e4SLinus Torvalds 1311da177e4SLinus Torvalds /* 1321da177e4SLinus Torvalds * clean up the filesystem 1331da177e4SLinus Torvalds */ 1345b86d4ffSDavid Howells void afs_fs_exit(void) 1351da177e4SLinus Torvalds { 13608e0e7c8SDavid Howells _enter(""); 13708e0e7c8SDavid Howells 13808e0e7c8SDavid Howells afs_mntpt_kill_timer(); 1391da177e4SLinus Torvalds unregister_filesystem(&afs_fs_type); 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds if (atomic_read(&afs_count_active_inodes) != 0) { 1421da177e4SLinus Torvalds printk("kAFS: %d active inode objects still present\n", 1431da177e4SLinus Torvalds atomic_read(&afs_count_active_inodes)); 1441da177e4SLinus Torvalds BUG(); 1451da177e4SLinus Torvalds } 1461da177e4SLinus Torvalds 1478c0a8537SKirill A. Shutemov /* 1488c0a8537SKirill A. Shutemov * Make sure all delayed rcu free inodes are flushed before we 1498c0a8537SKirill A. Shutemov * destroy cache. 1508c0a8537SKirill A. Shutemov */ 1518c0a8537SKirill A. Shutemov rcu_barrier(); 1521da177e4SLinus Torvalds kmem_cache_destroy(afs_inode_cachep); 15308e0e7c8SDavid Howells _leave(""); 154ec26815aSDavid Howells } 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds /* 157677018a6SDavid Howells * Display the mount device name in /proc/mounts. 158677018a6SDavid Howells */ 159677018a6SDavid Howells static int afs_show_devname(struct seq_file *m, struct dentry *root) 160677018a6SDavid Howells { 161d2ddc776SDavid Howells struct afs_super_info *as = AFS_FS_S(root->d_sb); 162677018a6SDavid Howells struct afs_volume *volume = as->volume; 163d2ddc776SDavid Howells struct afs_cell *cell = as->cell; 164677018a6SDavid Howells const char *suf = ""; 165677018a6SDavid Howells char pref = '%'; 166677018a6SDavid Howells 1674d673da1SDavid Howells if (as->dyn_root) { 1684d673da1SDavid Howells seq_puts(m, "none"); 1694d673da1SDavid Howells return 0; 1704d673da1SDavid Howells } 1714d673da1SDavid Howells 172677018a6SDavid Howells switch (volume->type) { 173677018a6SDavid Howells case AFSVL_RWVOL: 174677018a6SDavid Howells break; 175677018a6SDavid Howells case AFSVL_ROVOL: 176677018a6SDavid Howells pref = '#'; 177677018a6SDavid Howells if (volume->type_force) 178677018a6SDavid Howells suf = ".readonly"; 179677018a6SDavid Howells break; 180677018a6SDavid Howells case AFSVL_BACKVOL: 181677018a6SDavid Howells pref = '#'; 182677018a6SDavid Howells suf = ".backup"; 183677018a6SDavid Howells break; 184677018a6SDavid Howells } 185677018a6SDavid Howells 186d2ddc776SDavid Howells seq_printf(m, "%c%s:%s%s", pref, cell->name, volume->name, suf); 187677018a6SDavid Howells return 0; 188677018a6SDavid Howells } 189677018a6SDavid Howells 190677018a6SDavid Howells /* 191677018a6SDavid Howells * Display the mount options in /proc/mounts. 192677018a6SDavid Howells */ 193677018a6SDavid Howells static int afs_show_options(struct seq_file *m, struct dentry *root) 194677018a6SDavid Howells { 1954d673da1SDavid Howells struct afs_super_info *as = AFS_FS_S(root->d_sb); 196*6c6c1d63SDavid Howells const char *p = NULL; 1974d673da1SDavid Howells 1984d673da1SDavid Howells if (as->dyn_root) 1994d673da1SDavid Howells seq_puts(m, ",dyn"); 200677018a6SDavid Howells if (test_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(d_inode(root))->flags)) 2014d673da1SDavid Howells seq_puts(m, ",autocell"); 202*6c6c1d63SDavid Howells switch (as->flock_mode) { 203*6c6c1d63SDavid Howells case afs_flock_mode_unset: break; 204*6c6c1d63SDavid Howells case afs_flock_mode_local: p = "local"; break; 205*6c6c1d63SDavid Howells case afs_flock_mode_openafs: p = "openafs"; break; 206*6c6c1d63SDavid Howells case afs_flock_mode_strict: p = "strict"; break; 207*6c6c1d63SDavid Howells case afs_flock_mode_write: p = "write"; break; 208*6c6c1d63SDavid Howells } 209*6c6c1d63SDavid Howells if (p) 210*6c6c1d63SDavid Howells seq_printf(m, ",flock=%s", p); 211*6c6c1d63SDavid Howells 212677018a6SDavid Howells return 0; 213677018a6SDavid Howells } 214677018a6SDavid Howells 215677018a6SDavid Howells /* 21613fcc683SDavid Howells * Parse the source name to get cell name, volume name, volume type and R/W 21713fcc683SDavid Howells * selector. 21813fcc683SDavid Howells * 21913fcc683SDavid Howells * This can be one of the following: 22000d3b7a4SDavid Howells * "%[cell:]volume[.]" R/W volume 221c99c2171SDavid Howells * "#[cell:]volume[.]" R/O or R/W volume (R/O parent), 222c99c2171SDavid Howells * or R/W (R/W parent) volume 22300d3b7a4SDavid Howells * "%[cell:]volume.readonly" R/O volume 22400d3b7a4SDavid Howells * "#[cell:]volume.readonly" R/O volume 22500d3b7a4SDavid Howells * "%[cell:]volume.backup" Backup volume 22600d3b7a4SDavid Howells * "#[cell:]volume.backup" Backup volume 22700d3b7a4SDavid Howells */ 22813fcc683SDavid Howells static int afs_parse_source(struct fs_context *fc, struct fs_parameter *param) 22900d3b7a4SDavid Howells { 23013fcc683SDavid Howells struct afs_fs_context *ctx = fc->fs_private; 23100d3b7a4SDavid Howells struct afs_cell *cell; 23213fcc683SDavid Howells const char *cellname, *suffix, *name = param->string; 23300d3b7a4SDavid Howells int cellnamesz; 23400d3b7a4SDavid Howells 23500d3b7a4SDavid Howells _enter(",%s", name); 23600d3b7a4SDavid Howells 23700d3b7a4SDavid Howells if (!name) { 23800d3b7a4SDavid Howells printk(KERN_ERR "kAFS: no volume name specified\n"); 23900d3b7a4SDavid Howells return -EINVAL; 24000d3b7a4SDavid Howells } 24100d3b7a4SDavid Howells 24200d3b7a4SDavid Howells if ((name[0] != '%' && name[0] != '#') || !name[1]) { 24313fcc683SDavid Howells /* To use dynroot, we don't want to have to provide a source */ 24413fcc683SDavid Howells if (strcmp(name, "none") == 0) { 24513fcc683SDavid Howells ctx->no_cell = true; 24613fcc683SDavid Howells return 0; 24713fcc683SDavid Howells } 24800d3b7a4SDavid Howells printk(KERN_ERR "kAFS: unparsable volume name\n"); 24900d3b7a4SDavid Howells return -EINVAL; 25000d3b7a4SDavid Howells } 25100d3b7a4SDavid Howells 25200d3b7a4SDavid Howells /* determine the type of volume we're looking for */ 253c99c2171SDavid Howells if (name[0] == '%') { 25413fcc683SDavid Howells ctx->type = AFSVL_RWVOL; 25513fcc683SDavid Howells ctx->force = true; 25600d3b7a4SDavid Howells } 25700d3b7a4SDavid Howells name++; 25800d3b7a4SDavid Howells 25900d3b7a4SDavid Howells /* split the cell name out if there is one */ 26013fcc683SDavid Howells ctx->volname = strchr(name, ':'); 26113fcc683SDavid Howells if (ctx->volname) { 26200d3b7a4SDavid Howells cellname = name; 26313fcc683SDavid Howells cellnamesz = ctx->volname - name; 26413fcc683SDavid Howells ctx->volname++; 26500d3b7a4SDavid Howells } else { 26613fcc683SDavid Howells ctx->volname = name; 26700d3b7a4SDavid Howells cellname = NULL; 26800d3b7a4SDavid Howells cellnamesz = 0; 26900d3b7a4SDavid Howells } 27000d3b7a4SDavid Howells 27100d3b7a4SDavid Howells /* the volume type is further affected by a possible suffix */ 27213fcc683SDavid Howells suffix = strrchr(ctx->volname, '.'); 27300d3b7a4SDavid Howells if (suffix) { 27400d3b7a4SDavid Howells if (strcmp(suffix, ".readonly") == 0) { 27513fcc683SDavid Howells ctx->type = AFSVL_ROVOL; 27613fcc683SDavid Howells ctx->force = true; 27700d3b7a4SDavid Howells } else if (strcmp(suffix, ".backup") == 0) { 27813fcc683SDavid Howells ctx->type = AFSVL_BACKVOL; 27913fcc683SDavid Howells ctx->force = true; 28000d3b7a4SDavid Howells } else if (suffix[1] == 0) { 28100d3b7a4SDavid Howells } else { 28200d3b7a4SDavid Howells suffix = NULL; 28300d3b7a4SDavid Howells } 28400d3b7a4SDavid Howells } 28500d3b7a4SDavid Howells 28613fcc683SDavid Howells ctx->volnamesz = suffix ? 28713fcc683SDavid Howells suffix - ctx->volname : strlen(ctx->volname); 28800d3b7a4SDavid Howells 28900d3b7a4SDavid Howells _debug("cell %*.*s [%p]", 29013fcc683SDavid Howells cellnamesz, cellnamesz, cellname ?: "", ctx->cell); 29100d3b7a4SDavid Howells 29200d3b7a4SDavid Howells /* lookup the cell record */ 29313fcc683SDavid Howells if (cellname) { 29413fcc683SDavid Howells cell = afs_lookup_cell(ctx->net, cellname, cellnamesz, 295989782dcSDavid Howells NULL, false); 29600d3b7a4SDavid Howells if (IS_ERR(cell)) { 29713fcc683SDavid Howells pr_err("kAFS: unable to lookup cell '%*.*s'\n", 298bec5eb61Swanglei cellnamesz, cellnamesz, cellname ?: ""); 29900d3b7a4SDavid Howells return PTR_ERR(cell); 30000d3b7a4SDavid Howells } 30113fcc683SDavid Howells afs_put_cell(ctx->net, ctx->cell); 30213fcc683SDavid Howells ctx->cell = cell; 30300d3b7a4SDavid Howells } 30400d3b7a4SDavid Howells 30500d3b7a4SDavid Howells _debug("CELL:%s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s", 30613fcc683SDavid Howells ctx->cell->name, ctx->cell, 30713fcc683SDavid Howells ctx->volnamesz, ctx->volnamesz, ctx->volname, 30813fcc683SDavid Howells suffix ?: "-", ctx->type, ctx->force ? " FORCE" : ""); 30913fcc683SDavid Howells 31013fcc683SDavid Howells fc->source = param->string; 31113fcc683SDavid Howells param->string = NULL; 31213fcc683SDavid Howells return 0; 31313fcc683SDavid Howells } 31413fcc683SDavid Howells 31513fcc683SDavid Howells /* 31613fcc683SDavid Howells * Parse a single mount parameter. 31713fcc683SDavid Howells */ 31813fcc683SDavid Howells static int afs_parse_param(struct fs_context *fc, struct fs_parameter *param) 31913fcc683SDavid Howells { 32013fcc683SDavid Howells struct fs_parse_result result; 32113fcc683SDavid Howells struct afs_fs_context *ctx = fc->fs_private; 32213fcc683SDavid Howells int opt; 32313fcc683SDavid Howells 32413fcc683SDavid Howells opt = fs_parse(fc, &afs_fs_parameters, param, &result); 32513fcc683SDavid Howells if (opt < 0) 32613fcc683SDavid Howells return opt; 32713fcc683SDavid Howells 32813fcc683SDavid Howells switch (opt) { 32913fcc683SDavid Howells case Opt_source: 33013fcc683SDavid Howells return afs_parse_source(fc, param); 33113fcc683SDavid Howells 33213fcc683SDavid Howells case Opt_autocell: 33313fcc683SDavid Howells ctx->autocell = true; 33413fcc683SDavid Howells break; 33513fcc683SDavid Howells 33613fcc683SDavid Howells case Opt_dyn: 33713fcc683SDavid Howells ctx->dyn_root = true; 33813fcc683SDavid Howells break; 33913fcc683SDavid Howells 340*6c6c1d63SDavid Howells case Opt_flock: 341*6c6c1d63SDavid Howells ctx->flock_mode = result.uint_32; 342*6c6c1d63SDavid Howells break; 343*6c6c1d63SDavid Howells 34413fcc683SDavid Howells default: 34513fcc683SDavid Howells return -EINVAL; 34613fcc683SDavid Howells } 34713fcc683SDavid Howells 34813fcc683SDavid Howells _leave(" = 0"); 34913fcc683SDavid Howells return 0; 35013fcc683SDavid Howells } 35113fcc683SDavid Howells 35213fcc683SDavid Howells /* 35313fcc683SDavid Howells * Validate the options, get the cell key and look up the volume. 35413fcc683SDavid Howells */ 35513fcc683SDavid Howells static int afs_validate_fc(struct fs_context *fc) 35613fcc683SDavid Howells { 35713fcc683SDavid Howells struct afs_fs_context *ctx = fc->fs_private; 35813fcc683SDavid Howells struct afs_volume *volume; 35913fcc683SDavid Howells struct key *key; 36013fcc683SDavid Howells 36113fcc683SDavid Howells if (!ctx->dyn_root) { 36213fcc683SDavid Howells if (ctx->no_cell) { 36313fcc683SDavid Howells pr_warn("kAFS: Can only specify source 'none' with -o dyn\n"); 36413fcc683SDavid Howells return -EINVAL; 36513fcc683SDavid Howells } 36613fcc683SDavid Howells 36713fcc683SDavid Howells if (!ctx->cell) { 36813fcc683SDavid Howells pr_warn("kAFS: No cell specified\n"); 36913fcc683SDavid Howells return -EDESTADDRREQ; 37013fcc683SDavid Howells } 37113fcc683SDavid Howells 37213fcc683SDavid Howells /* We try to do the mount securely. */ 37313fcc683SDavid Howells key = afs_request_key(ctx->cell); 37413fcc683SDavid Howells if (IS_ERR(key)) 37513fcc683SDavid Howells return PTR_ERR(key); 37613fcc683SDavid Howells 37713fcc683SDavid Howells ctx->key = key; 37813fcc683SDavid Howells 37913fcc683SDavid Howells if (ctx->volume) { 38013fcc683SDavid Howells afs_put_volume(ctx->cell, ctx->volume); 38113fcc683SDavid Howells ctx->volume = NULL; 38213fcc683SDavid Howells } 38313fcc683SDavid Howells 38413fcc683SDavid Howells volume = afs_create_volume(ctx); 38513fcc683SDavid Howells if (IS_ERR(volume)) 38613fcc683SDavid Howells return PTR_ERR(volume); 38713fcc683SDavid Howells 38813fcc683SDavid Howells ctx->volume = volume; 38913fcc683SDavid Howells } 39000d3b7a4SDavid Howells 39100d3b7a4SDavid Howells return 0; 39200d3b7a4SDavid Howells } 39300d3b7a4SDavid Howells 39400d3b7a4SDavid Howells /* 3951da177e4SLinus Torvalds * check a superblock to see if it's the one we're looking for 3961da177e4SLinus Torvalds */ 39713fcc683SDavid Howells static int afs_test_super(struct super_block *sb, struct fs_context *fc) 3981da177e4SLinus Torvalds { 39913fcc683SDavid Howells struct afs_fs_context *ctx = fc->fs_private; 400d2ddc776SDavid Howells struct afs_super_info *as = AFS_FS_S(sb); 4011da177e4SLinus Torvalds 40213fcc683SDavid Howells return (as->net_ns == fc->net_ns && 4034d673da1SDavid Howells as->volume && 40413fcc683SDavid Howells as->volume->vid == ctx->volume->vid && 4050da0b7fdSDavid Howells !as->dyn_root); 4064d673da1SDavid Howells } 4074d673da1SDavid Howells 40813fcc683SDavid Howells static int afs_dynroot_test_super(struct super_block *sb, struct fs_context *fc) 4094d673da1SDavid Howells { 4100da0b7fdSDavid Howells struct afs_super_info *as = AFS_FS_S(sb); 4110da0b7fdSDavid Howells 41213fcc683SDavid Howells return (as->net_ns == fc->net_ns && 4130da0b7fdSDavid Howells as->dyn_root); 414dde194a6SAl Viro } 415dde194a6SAl Viro 41613fcc683SDavid Howells static int afs_set_super(struct super_block *sb, struct fs_context *fc) 417dde194a6SAl Viro { 418dde194a6SAl Viro return set_anon_super(sb, NULL); 419ec26815aSDavid Howells } 4201da177e4SLinus Torvalds 4211da177e4SLinus Torvalds /* 4221da177e4SLinus Torvalds * fill in the superblock 4231da177e4SLinus Torvalds */ 42413fcc683SDavid Howells static int afs_fill_super(struct super_block *sb, struct afs_fs_context *ctx) 4251da177e4SLinus Torvalds { 426d2ddc776SDavid Howells struct afs_super_info *as = AFS_FS_S(sb); 4271da177e4SLinus Torvalds struct afs_fid fid; 4281da177e4SLinus Torvalds struct inode *inode = NULL; 4291da177e4SLinus Torvalds int ret; 4301da177e4SLinus Torvalds 43108e0e7c8SDavid Howells _enter(""); 4321da177e4SLinus Torvalds 4331da177e4SLinus Torvalds /* fill in the superblock */ 43409cbfeafSKirill A. Shutemov sb->s_blocksize = PAGE_SIZE; 43509cbfeafSKirill A. Shutemov sb->s_blocksize_bits = PAGE_SHIFT; 4361da177e4SLinus Torvalds sb->s_magic = AFS_FS_MAGIC; 4371da177e4SLinus Torvalds sb->s_op = &afs_super_ops; 4384d673da1SDavid Howells if (!as->dyn_root) 439d3e3b7eaSDavid Howells sb->s_xattr = afs_xattr_handlers; 440edd3ba94SJan Kara ret = super_setup_bdi(sb); 441edd3ba94SJan Kara if (ret) 442edd3ba94SJan Kara return ret; 443b5420237SNikolay Borisov sb->s_bdi->ra_pages = VM_READAHEAD_PAGES; 4441da177e4SLinus Torvalds 4451da177e4SLinus Torvalds /* allocate the root inode and dentry */ 4464d673da1SDavid Howells if (as->dyn_root) { 4474d673da1SDavid Howells inode = afs_iget_pseudo_dir(sb, true); 4484d673da1SDavid Howells sb->s_flags |= SB_RDONLY; 4494d673da1SDavid Howells } else { 4503b6492dfSDavid Howells sprintf(sb->s_id, "%llu", as->volume->vid); 4514d673da1SDavid Howells afs_activate_volume(as->volume); 4521da177e4SLinus Torvalds fid.vid = as->volume->vid; 4531da177e4SLinus Torvalds fid.vnode = 1; 4543b6492dfSDavid Howells fid.vnode_hi = 0; 4551da177e4SLinus Torvalds fid.unique = 1; 45613fcc683SDavid Howells inode = afs_iget(sb, ctx->key, &fid, NULL, NULL, NULL); 4574d673da1SDavid Howells } 4584d673da1SDavid Howells 45908e0e7c8SDavid Howells if (IS_ERR(inode)) 460dde194a6SAl Viro return PTR_ERR(inode); 4611da177e4SLinus Torvalds 46213fcc683SDavid Howells if (ctx->autocell || as->dyn_root) 463bec5eb61Swanglei set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags); 464bec5eb61Swanglei 4651da177e4SLinus Torvalds ret = -ENOMEM; 46648fde701SAl Viro sb->s_root = d_make_root(inode); 46748fde701SAl Viro if (!sb->s_root) 4681da177e4SLinus Torvalds goto error; 4691da177e4SLinus Torvalds 4700da0b7fdSDavid Howells if (as->dyn_root) { 47166c7e1d3SDavid Howells sb->s_d_op = &afs_dynroot_dentry_operations; 4720da0b7fdSDavid Howells ret = afs_dynroot_populate(sb); 4730da0b7fdSDavid Howells if (ret < 0) 4740da0b7fdSDavid Howells goto error; 4750da0b7fdSDavid Howells } else { 476d61dcce2SAl Viro sb->s_d_op = &afs_fs_dentry_operations; 4770da0b7fdSDavid Howells } 4781da177e4SLinus Torvalds 47908e0e7c8SDavid Howells _leave(" = 0"); 4801da177e4SLinus Torvalds return 0; 4811da177e4SLinus Torvalds 4821da177e4SLinus Torvalds error: 48308e0e7c8SDavid Howells _leave(" = %d", ret); 4841da177e4SLinus Torvalds return ret; 485ec26815aSDavid Howells } 4861da177e4SLinus Torvalds 48713fcc683SDavid Howells static struct afs_super_info *afs_alloc_sbi(struct fs_context *fc) 48849566f6fSDavid Howells { 48913fcc683SDavid Howells struct afs_fs_context *ctx = fc->fs_private; 49049566f6fSDavid Howells struct afs_super_info *as; 49149566f6fSDavid Howells 49249566f6fSDavid Howells as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL); 49349566f6fSDavid Howells if (as) { 49413fcc683SDavid Howells as->net_ns = get_net(fc->net_ns); 495*6c6c1d63SDavid Howells as->flock_mode = ctx->flock_mode; 49613fcc683SDavid Howells if (ctx->dyn_root) { 4974d673da1SDavid Howells as->dyn_root = true; 49813fcc683SDavid Howells } else { 49913fcc683SDavid Howells as->cell = afs_get_cell(ctx->cell); 50013fcc683SDavid Howells as->volume = __afs_get_volume(ctx->volume); 50113fcc683SDavid Howells } 50249566f6fSDavid Howells } 50349566f6fSDavid Howells return as; 50449566f6fSDavid Howells } 50549566f6fSDavid Howells 50649566f6fSDavid Howells static void afs_destroy_sbi(struct afs_super_info *as) 50749566f6fSDavid Howells { 50849566f6fSDavid Howells if (as) { 5099ed900b1SDavid Howells afs_put_volume(as->cell, as->volume); 5105b86d4ffSDavid Howells afs_put_cell(afs_net(as->net_ns), as->cell); 5115b86d4ffSDavid Howells put_net(as->net_ns); 51249566f6fSDavid Howells kfree(as); 51349566f6fSDavid Howells } 51449566f6fSDavid Howells } 51549566f6fSDavid Howells 5160da0b7fdSDavid Howells static void afs_kill_super(struct super_block *sb) 5170da0b7fdSDavid Howells { 5180da0b7fdSDavid Howells struct afs_super_info *as = AFS_FS_S(sb); 5190da0b7fdSDavid Howells struct afs_net *net = afs_net(as->net_ns); 5200da0b7fdSDavid Howells 5210da0b7fdSDavid Howells if (as->dyn_root) 5220da0b7fdSDavid Howells afs_dynroot_depopulate(sb); 5230da0b7fdSDavid Howells 5240da0b7fdSDavid Howells /* Clear the callback interests (which will do ilookup5) before 5250da0b7fdSDavid Howells * deactivating the superblock. 5260da0b7fdSDavid Howells */ 5270da0b7fdSDavid Howells if (as->volume) 5280da0b7fdSDavid Howells afs_clear_callback_interests(net, as->volume->servers); 5290da0b7fdSDavid Howells kill_anon_super(sb); 5300da0b7fdSDavid Howells if (as->volume) 5310da0b7fdSDavid Howells afs_deactivate_volume(as->volume); 5320da0b7fdSDavid Howells afs_destroy_sbi(as); 5330da0b7fdSDavid Howells } 5340da0b7fdSDavid Howells 5351da177e4SLinus Torvalds /* 53613fcc683SDavid Howells * Get an AFS superblock and root directory. 5371da177e4SLinus Torvalds */ 53813fcc683SDavid Howells static int afs_get_tree(struct fs_context *fc) 5391da177e4SLinus Torvalds { 54013fcc683SDavid Howells struct afs_fs_context *ctx = fc->fs_private; 5411da177e4SLinus Torvalds struct super_block *sb; 542dde194a6SAl Viro struct afs_super_info *as; 5431da177e4SLinus Torvalds int ret; 5441da177e4SLinus Torvalds 54513fcc683SDavid Howells ret = afs_validate_fc(fc); 54613fcc683SDavid Howells if (ret) 54700d3b7a4SDavid Howells goto error; 54800d3b7a4SDavid Howells 54913fcc683SDavid Howells _enter(""); 55000d3b7a4SDavid Howells 55149566f6fSDavid Howells /* allocate a superblock info record */ 55249566f6fSDavid Howells ret = -ENOMEM; 55313fcc683SDavid Howells as = afs_alloc_sbi(fc); 55449566f6fSDavid Howells if (!as) 55513fcc683SDavid Howells goto error; 55613fcc683SDavid Howells fc->s_fs_info = as; 5571da177e4SLinus Torvalds 5581da177e4SLinus Torvalds /* allocate a deviceless superblock */ 55913fcc683SDavid Howells sb = sget_fc(fc, 5604d673da1SDavid Howells as->dyn_root ? afs_dynroot_test_super : afs_test_super, 56113fcc683SDavid Howells afs_set_super); 56208e0e7c8SDavid Howells if (IS_ERR(sb)) { 56308e0e7c8SDavid Howells ret = PTR_ERR(sb); 56413fcc683SDavid Howells goto error; 56508e0e7c8SDavid Howells } 5661da177e4SLinus Torvalds 567436058a4SDavid Howells if (!sb->s_root) { 568436058a4SDavid Howells /* initial superblock/root creation */ 569436058a4SDavid Howells _debug("create"); 57013fcc683SDavid Howells ret = afs_fill_super(sb, ctx); 571f044c884SDavid Howells if (ret < 0) 572f044c884SDavid Howells goto error_sb; 5731751e8a6SLinus Torvalds sb->s_flags |= SB_ACTIVE; 574436058a4SDavid Howells } else { 575436058a4SDavid Howells _debug("reuse"); 5761751e8a6SLinus Torvalds ASSERTCMP(sb->s_flags, &, SB_ACTIVE); 577436058a4SDavid Howells } 5781da177e4SLinus Torvalds 57913fcc683SDavid Howells fc->root = dget(sb->s_root); 58080548b03SDavid Howells trace_afs_get_tree(as->cell, as->volume); 58108e0e7c8SDavid Howells _leave(" = 0 [%p]", sb); 58213fcc683SDavid Howells return 0; 5831da177e4SLinus Torvalds 584f044c884SDavid Howells error_sb: 585f044c884SDavid Howells deactivate_locked_super(sb); 5861da177e4SLinus Torvalds error: 5871da177e4SLinus Torvalds _leave(" = %d", ret); 58813fcc683SDavid Howells return ret; 58913fcc683SDavid Howells } 59013fcc683SDavid Howells 59113fcc683SDavid Howells static void afs_free_fc(struct fs_context *fc) 59213fcc683SDavid Howells { 59313fcc683SDavid Howells struct afs_fs_context *ctx = fc->fs_private; 59413fcc683SDavid Howells 59513fcc683SDavid Howells afs_destroy_sbi(fc->s_fs_info); 59613fcc683SDavid Howells afs_put_volume(ctx->cell, ctx->volume); 59713fcc683SDavid Howells afs_put_cell(ctx->net, ctx->cell); 59813fcc683SDavid Howells key_put(ctx->key); 59913fcc683SDavid Howells kfree(ctx); 60013fcc683SDavid Howells } 60113fcc683SDavid Howells 60213fcc683SDavid Howells static const struct fs_context_operations afs_context_ops = { 60313fcc683SDavid Howells .free = afs_free_fc, 60413fcc683SDavid Howells .parse_param = afs_parse_param, 60513fcc683SDavid Howells .get_tree = afs_get_tree, 60613fcc683SDavid Howells }; 60713fcc683SDavid Howells 60813fcc683SDavid Howells /* 60913fcc683SDavid Howells * Set up the filesystem mount context. 61013fcc683SDavid Howells */ 61113fcc683SDavid Howells static int afs_init_fs_context(struct fs_context *fc) 61213fcc683SDavid Howells { 61313fcc683SDavid Howells struct afs_fs_context *ctx; 61413fcc683SDavid Howells struct afs_cell *cell; 61513fcc683SDavid Howells 61613fcc683SDavid Howells ctx = kzalloc(sizeof(struct afs_fs_context), GFP_KERNEL); 61713fcc683SDavid Howells if (!ctx) 61813fcc683SDavid Howells return -ENOMEM; 61913fcc683SDavid Howells 62013fcc683SDavid Howells ctx->type = AFSVL_ROVOL; 62113fcc683SDavid Howells ctx->net = afs_net(fc->net_ns); 62213fcc683SDavid Howells 62313fcc683SDavid Howells /* Default to the workstation cell. */ 62413fcc683SDavid Howells rcu_read_lock(); 62513fcc683SDavid Howells cell = afs_lookup_cell_rcu(ctx->net, NULL, 0); 62613fcc683SDavid Howells rcu_read_unlock(); 62713fcc683SDavid Howells if (IS_ERR(cell)) 62813fcc683SDavid Howells cell = NULL; 62913fcc683SDavid Howells ctx->cell = cell; 63013fcc683SDavid Howells 63113fcc683SDavid Howells fc->fs_private = ctx; 63213fcc683SDavid Howells fc->ops = &afs_context_ops; 63313fcc683SDavid Howells return 0; 634ec26815aSDavid Howells } 6351da177e4SLinus Torvalds 6361da177e4SLinus Torvalds /* 637f8de483eSDavid Howells * Initialise an inode cache slab element prior to any use. Note that 638f8de483eSDavid Howells * afs_alloc_inode() *must* reset anything that could incorrectly leak from one 639f8de483eSDavid Howells * inode to another. 6401da177e4SLinus Torvalds */ 64151cc5068SAlexey Dobriyan static void afs_i_init_once(void *_vnode) 6421da177e4SLinus Torvalds { 643ec26815aSDavid Howells struct afs_vnode *vnode = _vnode; 6441da177e4SLinus Torvalds 6451da177e4SLinus Torvalds memset(vnode, 0, sizeof(*vnode)); 6461da177e4SLinus Torvalds inode_init_once(&vnode->vfs_inode); 647d2ddc776SDavid Howells mutex_init(&vnode->io_lock); 648b61f7dcfSDavid Howells init_rwsem(&vnode->validate_lock); 6494343d008SDavid Howells spin_lock_init(&vnode->wb_lock); 6501da177e4SLinus Torvalds spin_lock_init(&vnode->lock); 6514343d008SDavid Howells INIT_LIST_HEAD(&vnode->wb_keys); 652e8d6c554SDavid Howells INIT_LIST_HEAD(&vnode->pending_locks); 653e8d6c554SDavid Howells INIT_LIST_HEAD(&vnode->granted_locks); 654e8d6c554SDavid Howells INIT_DELAYED_WORK(&vnode->lock_work, afs_lock_work); 655c435ee34SDavid Howells seqlock_init(&vnode->cb_lock); 6561da177e4SLinus Torvalds } 6571da177e4SLinus Torvalds 6581da177e4SLinus Torvalds /* 6591da177e4SLinus Torvalds * allocate an AFS inode struct from our slab cache 6601da177e4SLinus Torvalds */ 6611da177e4SLinus Torvalds static struct inode *afs_alloc_inode(struct super_block *sb) 6621da177e4SLinus Torvalds { 6631da177e4SLinus Torvalds struct afs_vnode *vnode; 6641da177e4SLinus Torvalds 665ec26815aSDavid Howells vnode = kmem_cache_alloc(afs_inode_cachep, GFP_KERNEL); 6661da177e4SLinus Torvalds if (!vnode) 6671da177e4SLinus Torvalds return NULL; 6681da177e4SLinus Torvalds 6691da177e4SLinus Torvalds atomic_inc(&afs_count_active_inodes); 6701da177e4SLinus Torvalds 671f8de483eSDavid Howells /* Reset anything that shouldn't leak from one inode to the next. */ 6721da177e4SLinus Torvalds memset(&vnode->fid, 0, sizeof(vnode->fid)); 6731da177e4SLinus Torvalds memset(&vnode->status, 0, sizeof(vnode->status)); 6741da177e4SLinus Torvalds 6751da177e4SLinus Torvalds vnode->volume = NULL; 676f8de483eSDavid Howells vnode->lock_key = NULL; 677f8de483eSDavid Howells vnode->permit_cache = NULL; 678f8de483eSDavid Howells vnode->cb_interest = NULL; 679f8de483eSDavid Howells #ifdef CONFIG_AFS_FSCACHE 680f8de483eSDavid Howells vnode->cache = NULL; 681f8de483eSDavid Howells #endif 682f8de483eSDavid Howells 683260a9803SDavid Howells vnode->flags = 1 << AFS_VNODE_UNSET; 684f8de483eSDavid Howells vnode->cb_type = 0; 685f8de483eSDavid Howells vnode->lock_state = AFS_VNODE_LOCK_NONE; 6861da177e4SLinus Torvalds 68779ddbfa5SDavid Howells init_rwsem(&vnode->rmdir_lock); 68879ddbfa5SDavid Howells 6890f300ca9SDavid Howells _leave(" = %p", &vnode->vfs_inode); 6901da177e4SLinus Torvalds return &vnode->vfs_inode; 691ec26815aSDavid Howells } 6921da177e4SLinus Torvalds 693fa0d7e3dSNick Piggin static void afs_i_callback(struct rcu_head *head) 694fa0d7e3dSNick Piggin { 695fa0d7e3dSNick Piggin struct inode *inode = container_of(head, struct inode, i_rcu); 696fa0d7e3dSNick Piggin struct afs_vnode *vnode = AFS_FS_I(inode); 697fa0d7e3dSNick Piggin kmem_cache_free(afs_inode_cachep, vnode); 698fa0d7e3dSNick Piggin } 699fa0d7e3dSNick Piggin 7001da177e4SLinus Torvalds /* 7011da177e4SLinus Torvalds * destroy an AFS inode struct 7021da177e4SLinus Torvalds */ 7031da177e4SLinus Torvalds static void afs_destroy_inode(struct inode *inode) 7041da177e4SLinus Torvalds { 70508e0e7c8SDavid Howells struct afs_vnode *vnode = AFS_FS_I(inode); 70608e0e7c8SDavid Howells 7073b6492dfSDavid Howells _enter("%p{%llx:%llu}", inode, vnode->fid.vid, vnode->fid.vnode); 7081da177e4SLinus Torvalds 70908e0e7c8SDavid Howells _debug("DESTROY INODE %p", inode); 71008e0e7c8SDavid Howells 711c435ee34SDavid Howells ASSERTCMP(vnode->cb_interest, ==, NULL); 71208e0e7c8SDavid Howells 713fa0d7e3dSNick Piggin call_rcu(&inode->i_rcu, afs_i_callback); 7141da177e4SLinus Torvalds atomic_dec(&afs_count_active_inodes); 715ec26815aSDavid Howells } 71645222b9eSDavid Howells 71745222b9eSDavid Howells /* 71845222b9eSDavid Howells * return information about an AFS volume 71945222b9eSDavid Howells */ 72045222b9eSDavid Howells static int afs_statfs(struct dentry *dentry, struct kstatfs *buf) 72145222b9eSDavid Howells { 7224d673da1SDavid Howells struct afs_super_info *as = AFS_FS_S(dentry->d_sb); 723d2ddc776SDavid Howells struct afs_fs_cursor fc; 72445222b9eSDavid Howells struct afs_volume_status vs; 7252b0143b5SDavid Howells struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry)); 72645222b9eSDavid Howells struct key *key; 72745222b9eSDavid Howells int ret; 72845222b9eSDavid Howells 7294d673da1SDavid Howells buf->f_type = dentry->d_sb->s_magic; 7304d673da1SDavid Howells buf->f_bsize = AFS_BLOCK_SIZE; 7314d673da1SDavid Howells buf->f_namelen = AFSNAMEMAX - 1; 7324d673da1SDavid Howells 7334d673da1SDavid Howells if (as->dyn_root) { 7344d673da1SDavid Howells buf->f_blocks = 1; 7354d673da1SDavid Howells buf->f_bavail = 0; 7364d673da1SDavid Howells buf->f_bfree = 0; 7374d673da1SDavid Howells return 0; 7384d673da1SDavid Howells } 7394d673da1SDavid Howells 74045222b9eSDavid Howells key = afs_request_key(vnode->volume->cell); 74145222b9eSDavid Howells if (IS_ERR(key)) 74245222b9eSDavid Howells return PTR_ERR(key); 74345222b9eSDavid Howells 744d2ddc776SDavid Howells ret = -ERESTARTSYS; 745d2ddc776SDavid Howells if (afs_begin_vnode_operation(&fc, vnode, key)) { 746d2ddc776SDavid Howells fc.flags |= AFS_FS_CURSOR_NO_VSLEEP; 747d2ddc776SDavid Howells while (afs_select_fileserver(&fc)) { 74868251f0aSDavid Howells fc.cb_break = afs_calc_vnode_cb_break(vnode); 749d2ddc776SDavid Howells afs_fs_get_volume_status(&fc, &vs); 75045222b9eSDavid Howells } 75145222b9eSDavid Howells 752d2ddc776SDavid Howells afs_check_for_remote_deletion(&fc, fc.vnode); 753d2ddc776SDavid Howells afs_vnode_commit_status(&fc, vnode, fc.cb_break); 754d2ddc776SDavid Howells ret = afs_end_vnode_operation(&fc); 755d2ddc776SDavid Howells } 756d2ddc776SDavid Howells 757d2ddc776SDavid Howells key_put(key); 758d2ddc776SDavid Howells 759d2ddc776SDavid Howells if (ret == 0) { 76045222b9eSDavid Howells if (vs.max_quota == 0) 76145222b9eSDavid Howells buf->f_blocks = vs.part_max_blocks; 76245222b9eSDavid Howells else 76345222b9eSDavid Howells buf->f_blocks = vs.max_quota; 76445222b9eSDavid Howells buf->f_bavail = buf->f_bfree = buf->f_blocks - vs.blocks_in_use; 765d2ddc776SDavid Howells } 766d2ddc776SDavid Howells 767d2ddc776SDavid Howells return ret; 76845222b9eSDavid Howells } 769