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, 4880c72fe4SDavid Howells .fs_flags = 0, 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, 7013fcc683SDavid Howells Opt_source, 7180c72fe4SDavid Howells }; 7280c72fe4SDavid Howells 7313fcc683SDavid Howells static const struct fs_parameter_spec afs_param_specs[] = { 7413fcc683SDavid Howells fsparam_flag ("autocell", Opt_autocell), 7513fcc683SDavid Howells fsparam_flag ("dyn", Opt_dyn), 7613fcc683SDavid Howells fsparam_string("source", Opt_source), 7713fcc683SDavid Howells {} 7813fcc683SDavid Howells }; 7913fcc683SDavid Howells 8013fcc683SDavid Howells static const struct fs_parameter_description afs_fs_parameters = { 8113fcc683SDavid Howells .name = "kAFS", 8213fcc683SDavid Howells .specs = afs_param_specs, 8380c72fe4SDavid Howells }; 8480c72fe4SDavid Howells 851da177e4SLinus Torvalds /* 861da177e4SLinus Torvalds * initialise the filesystem 871da177e4SLinus Torvalds */ 881da177e4SLinus Torvalds int __init afs_fs_init(void) 891da177e4SLinus Torvalds { 901da177e4SLinus Torvalds int ret; 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds _enter(""); 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds /* create ourselves an inode cache */ 951da177e4SLinus Torvalds atomic_set(&afs_count_active_inodes, 0); 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds ret = -ENOMEM; 981da177e4SLinus Torvalds afs_inode_cachep = kmem_cache_create("afs_inode_cache", 991da177e4SLinus Torvalds sizeof(struct afs_vnode), 1001da177e4SLinus Torvalds 0, 1015d097056SVladimir Davydov SLAB_HWCACHE_ALIGN|SLAB_ACCOUNT, 10220c2df83SPaul Mundt afs_i_init_once); 1031da177e4SLinus Torvalds if (!afs_inode_cachep) { 1041da177e4SLinus Torvalds printk(KERN_NOTICE "kAFS: Failed to allocate inode cache\n"); 1051da177e4SLinus Torvalds return ret; 1061da177e4SLinus Torvalds } 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds /* now export our filesystem to lesser mortals */ 1091da177e4SLinus Torvalds ret = register_filesystem(&afs_fs_type); 1101da177e4SLinus Torvalds if (ret < 0) { 1111da177e4SLinus Torvalds kmem_cache_destroy(afs_inode_cachep); 11208e0e7c8SDavid Howells _leave(" = %d", ret); 1131da177e4SLinus Torvalds return ret; 1141da177e4SLinus Torvalds } 1151da177e4SLinus Torvalds 11608e0e7c8SDavid Howells _leave(" = 0"); 1171da177e4SLinus Torvalds return 0; 118ec26815aSDavid Howells } 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds /* 1211da177e4SLinus Torvalds * clean up the filesystem 1221da177e4SLinus Torvalds */ 1235b86d4ffSDavid Howells void afs_fs_exit(void) 1241da177e4SLinus Torvalds { 12508e0e7c8SDavid Howells _enter(""); 12608e0e7c8SDavid Howells 12708e0e7c8SDavid Howells afs_mntpt_kill_timer(); 1281da177e4SLinus Torvalds unregister_filesystem(&afs_fs_type); 1291da177e4SLinus Torvalds 1301da177e4SLinus Torvalds if (atomic_read(&afs_count_active_inodes) != 0) { 1311da177e4SLinus Torvalds printk("kAFS: %d active inode objects still present\n", 1321da177e4SLinus Torvalds atomic_read(&afs_count_active_inodes)); 1331da177e4SLinus Torvalds BUG(); 1341da177e4SLinus Torvalds } 1351da177e4SLinus Torvalds 1368c0a8537SKirill A. Shutemov /* 1378c0a8537SKirill A. Shutemov * Make sure all delayed rcu free inodes are flushed before we 1388c0a8537SKirill A. Shutemov * destroy cache. 1398c0a8537SKirill A. Shutemov */ 1408c0a8537SKirill A. Shutemov rcu_barrier(); 1411da177e4SLinus Torvalds kmem_cache_destroy(afs_inode_cachep); 14208e0e7c8SDavid Howells _leave(""); 143ec26815aSDavid Howells } 1441da177e4SLinus Torvalds 1451da177e4SLinus Torvalds /* 146677018a6SDavid Howells * Display the mount device name in /proc/mounts. 147677018a6SDavid Howells */ 148677018a6SDavid Howells static int afs_show_devname(struct seq_file *m, struct dentry *root) 149677018a6SDavid Howells { 150d2ddc776SDavid Howells struct afs_super_info *as = AFS_FS_S(root->d_sb); 151677018a6SDavid Howells struct afs_volume *volume = as->volume; 152d2ddc776SDavid Howells struct afs_cell *cell = as->cell; 153677018a6SDavid Howells const char *suf = ""; 154677018a6SDavid Howells char pref = '%'; 155677018a6SDavid Howells 1564d673da1SDavid Howells if (as->dyn_root) { 1574d673da1SDavid Howells seq_puts(m, "none"); 1584d673da1SDavid Howells return 0; 1594d673da1SDavid Howells } 1604d673da1SDavid Howells 161677018a6SDavid Howells switch (volume->type) { 162677018a6SDavid Howells case AFSVL_RWVOL: 163677018a6SDavid Howells break; 164677018a6SDavid Howells case AFSVL_ROVOL: 165677018a6SDavid Howells pref = '#'; 166677018a6SDavid Howells if (volume->type_force) 167677018a6SDavid Howells suf = ".readonly"; 168677018a6SDavid Howells break; 169677018a6SDavid Howells case AFSVL_BACKVOL: 170677018a6SDavid Howells pref = '#'; 171677018a6SDavid Howells suf = ".backup"; 172677018a6SDavid Howells break; 173677018a6SDavid Howells } 174677018a6SDavid Howells 175d2ddc776SDavid Howells seq_printf(m, "%c%s:%s%s", pref, cell->name, volume->name, suf); 176677018a6SDavid Howells return 0; 177677018a6SDavid Howells } 178677018a6SDavid Howells 179677018a6SDavid Howells /* 180677018a6SDavid Howells * Display the mount options in /proc/mounts. 181677018a6SDavid Howells */ 182677018a6SDavid Howells static int afs_show_options(struct seq_file *m, struct dentry *root) 183677018a6SDavid Howells { 1844d673da1SDavid Howells struct afs_super_info *as = AFS_FS_S(root->d_sb); 1854d673da1SDavid Howells 1864d673da1SDavid Howells if (as->dyn_root) 1874d673da1SDavid Howells seq_puts(m, ",dyn"); 188677018a6SDavid Howells if (test_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(d_inode(root))->flags)) 1894d673da1SDavid Howells seq_puts(m, ",autocell"); 190677018a6SDavid Howells return 0; 191677018a6SDavid Howells } 192677018a6SDavid Howells 193677018a6SDavid Howells /* 19413fcc683SDavid Howells * Parse the source name to get cell name, volume name, volume type and R/W 19513fcc683SDavid Howells * selector. 19613fcc683SDavid Howells * 19713fcc683SDavid Howells * This can be one of the following: 19800d3b7a4SDavid Howells * "%[cell:]volume[.]" R/W volume 199*c99c2171SDavid Howells * "#[cell:]volume[.]" R/O or R/W volume (R/O parent), 200*c99c2171SDavid Howells * or R/W (R/W parent) volume 20100d3b7a4SDavid Howells * "%[cell:]volume.readonly" R/O volume 20200d3b7a4SDavid Howells * "#[cell:]volume.readonly" R/O volume 20300d3b7a4SDavid Howells * "%[cell:]volume.backup" Backup volume 20400d3b7a4SDavid Howells * "#[cell:]volume.backup" Backup volume 20500d3b7a4SDavid Howells */ 20613fcc683SDavid Howells static int afs_parse_source(struct fs_context *fc, struct fs_parameter *param) 20700d3b7a4SDavid Howells { 20813fcc683SDavid Howells struct afs_fs_context *ctx = fc->fs_private; 20900d3b7a4SDavid Howells struct afs_cell *cell; 21013fcc683SDavid Howells const char *cellname, *suffix, *name = param->string; 21100d3b7a4SDavid Howells int cellnamesz; 21200d3b7a4SDavid Howells 21300d3b7a4SDavid Howells _enter(",%s", name); 21400d3b7a4SDavid Howells 21500d3b7a4SDavid Howells if (!name) { 21600d3b7a4SDavid Howells printk(KERN_ERR "kAFS: no volume name specified\n"); 21700d3b7a4SDavid Howells return -EINVAL; 21800d3b7a4SDavid Howells } 21900d3b7a4SDavid Howells 22000d3b7a4SDavid Howells if ((name[0] != '%' && name[0] != '#') || !name[1]) { 22113fcc683SDavid Howells /* To use dynroot, we don't want to have to provide a source */ 22213fcc683SDavid Howells if (strcmp(name, "none") == 0) { 22313fcc683SDavid Howells ctx->no_cell = true; 22413fcc683SDavid Howells return 0; 22513fcc683SDavid Howells } 22600d3b7a4SDavid Howells printk(KERN_ERR "kAFS: unparsable volume name\n"); 22700d3b7a4SDavid Howells return -EINVAL; 22800d3b7a4SDavid Howells } 22900d3b7a4SDavid Howells 23000d3b7a4SDavid Howells /* determine the type of volume we're looking for */ 231*c99c2171SDavid Howells if (name[0] == '%') { 23213fcc683SDavid Howells ctx->type = AFSVL_RWVOL; 23313fcc683SDavid Howells ctx->force = true; 23400d3b7a4SDavid Howells } 23500d3b7a4SDavid Howells name++; 23600d3b7a4SDavid Howells 23700d3b7a4SDavid Howells /* split the cell name out if there is one */ 23813fcc683SDavid Howells ctx->volname = strchr(name, ':'); 23913fcc683SDavid Howells if (ctx->volname) { 24000d3b7a4SDavid Howells cellname = name; 24113fcc683SDavid Howells cellnamesz = ctx->volname - name; 24213fcc683SDavid Howells ctx->volname++; 24300d3b7a4SDavid Howells } else { 24413fcc683SDavid Howells ctx->volname = name; 24500d3b7a4SDavid Howells cellname = NULL; 24600d3b7a4SDavid Howells cellnamesz = 0; 24700d3b7a4SDavid Howells } 24800d3b7a4SDavid Howells 24900d3b7a4SDavid Howells /* the volume type is further affected by a possible suffix */ 25013fcc683SDavid Howells suffix = strrchr(ctx->volname, '.'); 25100d3b7a4SDavid Howells if (suffix) { 25200d3b7a4SDavid Howells if (strcmp(suffix, ".readonly") == 0) { 25313fcc683SDavid Howells ctx->type = AFSVL_ROVOL; 25413fcc683SDavid Howells ctx->force = true; 25500d3b7a4SDavid Howells } else if (strcmp(suffix, ".backup") == 0) { 25613fcc683SDavid Howells ctx->type = AFSVL_BACKVOL; 25713fcc683SDavid Howells ctx->force = true; 25800d3b7a4SDavid Howells } else if (suffix[1] == 0) { 25900d3b7a4SDavid Howells } else { 26000d3b7a4SDavid Howells suffix = NULL; 26100d3b7a4SDavid Howells } 26200d3b7a4SDavid Howells } 26300d3b7a4SDavid Howells 26413fcc683SDavid Howells ctx->volnamesz = suffix ? 26513fcc683SDavid Howells suffix - ctx->volname : strlen(ctx->volname); 26600d3b7a4SDavid Howells 26700d3b7a4SDavid Howells _debug("cell %*.*s [%p]", 26813fcc683SDavid Howells cellnamesz, cellnamesz, cellname ?: "", ctx->cell); 26900d3b7a4SDavid Howells 27000d3b7a4SDavid Howells /* lookup the cell record */ 27113fcc683SDavid Howells if (cellname) { 27213fcc683SDavid Howells cell = afs_lookup_cell(ctx->net, cellname, cellnamesz, 273989782dcSDavid Howells NULL, false); 27400d3b7a4SDavid Howells if (IS_ERR(cell)) { 27513fcc683SDavid Howells pr_err("kAFS: unable to lookup cell '%*.*s'\n", 276bec5eb61Swanglei cellnamesz, cellnamesz, cellname ?: ""); 27700d3b7a4SDavid Howells return PTR_ERR(cell); 27800d3b7a4SDavid Howells } 27913fcc683SDavid Howells afs_put_cell(ctx->net, ctx->cell); 28013fcc683SDavid Howells ctx->cell = cell; 28100d3b7a4SDavid Howells } 28200d3b7a4SDavid Howells 28300d3b7a4SDavid Howells _debug("CELL:%s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s", 28413fcc683SDavid Howells ctx->cell->name, ctx->cell, 28513fcc683SDavid Howells ctx->volnamesz, ctx->volnamesz, ctx->volname, 28613fcc683SDavid Howells suffix ?: "-", ctx->type, ctx->force ? " FORCE" : ""); 28713fcc683SDavid Howells 28813fcc683SDavid Howells fc->source = param->string; 28913fcc683SDavid Howells param->string = NULL; 29013fcc683SDavid Howells return 0; 29113fcc683SDavid Howells } 29213fcc683SDavid Howells 29313fcc683SDavid Howells /* 29413fcc683SDavid Howells * Parse a single mount parameter. 29513fcc683SDavid Howells */ 29613fcc683SDavid Howells static int afs_parse_param(struct fs_context *fc, struct fs_parameter *param) 29713fcc683SDavid Howells { 29813fcc683SDavid Howells struct fs_parse_result result; 29913fcc683SDavid Howells struct afs_fs_context *ctx = fc->fs_private; 30013fcc683SDavid Howells int opt; 30113fcc683SDavid Howells 30213fcc683SDavid Howells opt = fs_parse(fc, &afs_fs_parameters, param, &result); 30313fcc683SDavid Howells if (opt < 0) 30413fcc683SDavid Howells return opt; 30513fcc683SDavid Howells 30613fcc683SDavid Howells switch (opt) { 30713fcc683SDavid Howells case Opt_source: 30813fcc683SDavid Howells return afs_parse_source(fc, param); 30913fcc683SDavid Howells 31013fcc683SDavid Howells case Opt_autocell: 31113fcc683SDavid Howells ctx->autocell = true; 31213fcc683SDavid Howells break; 31313fcc683SDavid Howells 31413fcc683SDavid Howells case Opt_dyn: 31513fcc683SDavid Howells ctx->dyn_root = true; 31613fcc683SDavid Howells break; 31713fcc683SDavid Howells 31813fcc683SDavid Howells default: 31913fcc683SDavid Howells return -EINVAL; 32013fcc683SDavid Howells } 32113fcc683SDavid Howells 32213fcc683SDavid Howells _leave(" = 0"); 32313fcc683SDavid Howells return 0; 32413fcc683SDavid Howells } 32513fcc683SDavid Howells 32613fcc683SDavid Howells /* 32713fcc683SDavid Howells * Validate the options, get the cell key and look up the volume. 32813fcc683SDavid Howells */ 32913fcc683SDavid Howells static int afs_validate_fc(struct fs_context *fc) 33013fcc683SDavid Howells { 33113fcc683SDavid Howells struct afs_fs_context *ctx = fc->fs_private; 33213fcc683SDavid Howells struct afs_volume *volume; 33313fcc683SDavid Howells struct key *key; 33413fcc683SDavid Howells 33513fcc683SDavid Howells if (!ctx->dyn_root) { 33613fcc683SDavid Howells if (ctx->no_cell) { 33713fcc683SDavid Howells pr_warn("kAFS: Can only specify source 'none' with -o dyn\n"); 33813fcc683SDavid Howells return -EINVAL; 33913fcc683SDavid Howells } 34013fcc683SDavid Howells 34113fcc683SDavid Howells if (!ctx->cell) { 34213fcc683SDavid Howells pr_warn("kAFS: No cell specified\n"); 34313fcc683SDavid Howells return -EDESTADDRREQ; 34413fcc683SDavid Howells } 34513fcc683SDavid Howells 34613fcc683SDavid Howells /* We try to do the mount securely. */ 34713fcc683SDavid Howells key = afs_request_key(ctx->cell); 34813fcc683SDavid Howells if (IS_ERR(key)) 34913fcc683SDavid Howells return PTR_ERR(key); 35013fcc683SDavid Howells 35113fcc683SDavid Howells ctx->key = key; 35213fcc683SDavid Howells 35313fcc683SDavid Howells if (ctx->volume) { 35413fcc683SDavid Howells afs_put_volume(ctx->cell, ctx->volume); 35513fcc683SDavid Howells ctx->volume = NULL; 35613fcc683SDavid Howells } 35713fcc683SDavid Howells 35813fcc683SDavid Howells volume = afs_create_volume(ctx); 35913fcc683SDavid Howells if (IS_ERR(volume)) 36013fcc683SDavid Howells return PTR_ERR(volume); 36113fcc683SDavid Howells 36213fcc683SDavid Howells ctx->volume = volume; 36313fcc683SDavid Howells } 36400d3b7a4SDavid Howells 36500d3b7a4SDavid Howells return 0; 36600d3b7a4SDavid Howells } 36700d3b7a4SDavid Howells 36800d3b7a4SDavid Howells /* 3691da177e4SLinus Torvalds * check a superblock to see if it's the one we're looking for 3701da177e4SLinus Torvalds */ 37113fcc683SDavid Howells static int afs_test_super(struct super_block *sb, struct fs_context *fc) 3721da177e4SLinus Torvalds { 37313fcc683SDavid Howells struct afs_fs_context *ctx = fc->fs_private; 374d2ddc776SDavid Howells struct afs_super_info *as = AFS_FS_S(sb); 3751da177e4SLinus Torvalds 37613fcc683SDavid Howells return (as->net_ns == fc->net_ns && 3774d673da1SDavid Howells as->volume && 37813fcc683SDavid Howells as->volume->vid == ctx->volume->vid && 3790da0b7fdSDavid Howells !as->dyn_root); 3804d673da1SDavid Howells } 3814d673da1SDavid Howells 38213fcc683SDavid Howells static int afs_dynroot_test_super(struct super_block *sb, struct fs_context *fc) 3834d673da1SDavid Howells { 3840da0b7fdSDavid Howells struct afs_super_info *as = AFS_FS_S(sb); 3850da0b7fdSDavid Howells 38613fcc683SDavid Howells return (as->net_ns == fc->net_ns && 3870da0b7fdSDavid Howells as->dyn_root); 388dde194a6SAl Viro } 389dde194a6SAl Viro 39013fcc683SDavid Howells static int afs_set_super(struct super_block *sb, struct fs_context *fc) 391dde194a6SAl Viro { 392dde194a6SAl Viro return set_anon_super(sb, NULL); 393ec26815aSDavid Howells } 3941da177e4SLinus Torvalds 3951da177e4SLinus Torvalds /* 3961da177e4SLinus Torvalds * fill in the superblock 3971da177e4SLinus Torvalds */ 39813fcc683SDavid Howells static int afs_fill_super(struct super_block *sb, struct afs_fs_context *ctx) 3991da177e4SLinus Torvalds { 400d2ddc776SDavid Howells struct afs_super_info *as = AFS_FS_S(sb); 4011da177e4SLinus Torvalds struct afs_fid fid; 4021da177e4SLinus Torvalds struct inode *inode = NULL; 4031da177e4SLinus Torvalds int ret; 4041da177e4SLinus Torvalds 40508e0e7c8SDavid Howells _enter(""); 4061da177e4SLinus Torvalds 4071da177e4SLinus Torvalds /* fill in the superblock */ 40809cbfeafSKirill A. Shutemov sb->s_blocksize = PAGE_SIZE; 40909cbfeafSKirill A. Shutemov sb->s_blocksize_bits = PAGE_SHIFT; 4101da177e4SLinus Torvalds sb->s_magic = AFS_FS_MAGIC; 4111da177e4SLinus Torvalds sb->s_op = &afs_super_ops; 4124d673da1SDavid Howells if (!as->dyn_root) 413d3e3b7eaSDavid Howells sb->s_xattr = afs_xattr_handlers; 414edd3ba94SJan Kara ret = super_setup_bdi(sb); 415edd3ba94SJan Kara if (ret) 416edd3ba94SJan Kara return ret; 417edd3ba94SJan Kara sb->s_bdi->ra_pages = VM_MAX_READAHEAD * 1024 / PAGE_SIZE; 4181da177e4SLinus Torvalds 4191da177e4SLinus Torvalds /* allocate the root inode and dentry */ 4204d673da1SDavid Howells if (as->dyn_root) { 4214d673da1SDavid Howells inode = afs_iget_pseudo_dir(sb, true); 4224d673da1SDavid Howells sb->s_flags |= SB_RDONLY; 4234d673da1SDavid Howells } else { 4243b6492dfSDavid Howells sprintf(sb->s_id, "%llu", as->volume->vid); 4254d673da1SDavid Howells afs_activate_volume(as->volume); 4261da177e4SLinus Torvalds fid.vid = as->volume->vid; 4271da177e4SLinus Torvalds fid.vnode = 1; 4283b6492dfSDavid Howells fid.vnode_hi = 0; 4291da177e4SLinus Torvalds fid.unique = 1; 43013fcc683SDavid Howells inode = afs_iget(sb, ctx->key, &fid, NULL, NULL, NULL); 4314d673da1SDavid Howells } 4324d673da1SDavid Howells 43308e0e7c8SDavid Howells if (IS_ERR(inode)) 434dde194a6SAl Viro return PTR_ERR(inode); 4351da177e4SLinus Torvalds 43613fcc683SDavid Howells if (ctx->autocell || as->dyn_root) 437bec5eb61Swanglei set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags); 438bec5eb61Swanglei 4391da177e4SLinus Torvalds ret = -ENOMEM; 44048fde701SAl Viro sb->s_root = d_make_root(inode); 44148fde701SAl Viro if (!sb->s_root) 4421da177e4SLinus Torvalds goto error; 4431da177e4SLinus Torvalds 4440da0b7fdSDavid Howells if (as->dyn_root) { 44566c7e1d3SDavid Howells sb->s_d_op = &afs_dynroot_dentry_operations; 4460da0b7fdSDavid Howells ret = afs_dynroot_populate(sb); 4470da0b7fdSDavid Howells if (ret < 0) 4480da0b7fdSDavid Howells goto error; 4490da0b7fdSDavid Howells } else { 450d61dcce2SAl Viro sb->s_d_op = &afs_fs_dentry_operations; 4510da0b7fdSDavid Howells } 4521da177e4SLinus Torvalds 45308e0e7c8SDavid Howells _leave(" = 0"); 4541da177e4SLinus Torvalds return 0; 4551da177e4SLinus Torvalds 4561da177e4SLinus Torvalds error: 45708e0e7c8SDavid Howells _leave(" = %d", ret); 4581da177e4SLinus Torvalds return ret; 459ec26815aSDavid Howells } 4601da177e4SLinus Torvalds 46113fcc683SDavid Howells static struct afs_super_info *afs_alloc_sbi(struct fs_context *fc) 46249566f6fSDavid Howells { 46313fcc683SDavid Howells struct afs_fs_context *ctx = fc->fs_private; 46449566f6fSDavid Howells struct afs_super_info *as; 46549566f6fSDavid Howells 46649566f6fSDavid Howells as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL); 46749566f6fSDavid Howells if (as) { 46813fcc683SDavid Howells as->net_ns = get_net(fc->net_ns); 46913fcc683SDavid Howells if (ctx->dyn_root) { 4704d673da1SDavid Howells as->dyn_root = true; 47113fcc683SDavid Howells } else { 47213fcc683SDavid Howells as->cell = afs_get_cell(ctx->cell); 47313fcc683SDavid Howells as->volume = __afs_get_volume(ctx->volume); 47413fcc683SDavid Howells } 47549566f6fSDavid Howells } 47649566f6fSDavid Howells return as; 47749566f6fSDavid Howells } 47849566f6fSDavid Howells 47949566f6fSDavid Howells static void afs_destroy_sbi(struct afs_super_info *as) 48049566f6fSDavid Howells { 48149566f6fSDavid Howells if (as) { 4829ed900b1SDavid Howells afs_put_volume(as->cell, as->volume); 4835b86d4ffSDavid Howells afs_put_cell(afs_net(as->net_ns), as->cell); 4845b86d4ffSDavid Howells put_net(as->net_ns); 48549566f6fSDavid Howells kfree(as); 48649566f6fSDavid Howells } 48749566f6fSDavid Howells } 48849566f6fSDavid Howells 4890da0b7fdSDavid Howells static void afs_kill_super(struct super_block *sb) 4900da0b7fdSDavid Howells { 4910da0b7fdSDavid Howells struct afs_super_info *as = AFS_FS_S(sb); 4920da0b7fdSDavid Howells struct afs_net *net = afs_net(as->net_ns); 4930da0b7fdSDavid Howells 4940da0b7fdSDavid Howells if (as->dyn_root) 4950da0b7fdSDavid Howells afs_dynroot_depopulate(sb); 4960da0b7fdSDavid Howells 4970da0b7fdSDavid Howells /* Clear the callback interests (which will do ilookup5) before 4980da0b7fdSDavid Howells * deactivating the superblock. 4990da0b7fdSDavid Howells */ 5000da0b7fdSDavid Howells if (as->volume) 5010da0b7fdSDavid Howells afs_clear_callback_interests(net, as->volume->servers); 5020da0b7fdSDavid Howells kill_anon_super(sb); 5030da0b7fdSDavid Howells if (as->volume) 5040da0b7fdSDavid Howells afs_deactivate_volume(as->volume); 5050da0b7fdSDavid Howells afs_destroy_sbi(as); 5060da0b7fdSDavid Howells } 5070da0b7fdSDavid Howells 5081da177e4SLinus Torvalds /* 50913fcc683SDavid Howells * Get an AFS superblock and root directory. 5101da177e4SLinus Torvalds */ 51113fcc683SDavid Howells static int afs_get_tree(struct fs_context *fc) 5121da177e4SLinus Torvalds { 51313fcc683SDavid Howells struct afs_fs_context *ctx = fc->fs_private; 5141da177e4SLinus Torvalds struct super_block *sb; 515dde194a6SAl Viro struct afs_super_info *as; 5161da177e4SLinus Torvalds int ret; 5171da177e4SLinus Torvalds 51813fcc683SDavid Howells ret = afs_validate_fc(fc); 51913fcc683SDavid Howells if (ret) 52000d3b7a4SDavid Howells goto error; 52100d3b7a4SDavid Howells 52213fcc683SDavid Howells _enter(""); 52300d3b7a4SDavid Howells 52449566f6fSDavid Howells /* allocate a superblock info record */ 52549566f6fSDavid Howells ret = -ENOMEM; 52613fcc683SDavid Howells as = afs_alloc_sbi(fc); 52749566f6fSDavid Howells if (!as) 52813fcc683SDavid Howells goto error; 52913fcc683SDavid Howells fc->s_fs_info = as; 5301da177e4SLinus Torvalds 5311da177e4SLinus Torvalds /* allocate a deviceless superblock */ 53213fcc683SDavid Howells sb = sget_fc(fc, 5334d673da1SDavid Howells as->dyn_root ? afs_dynroot_test_super : afs_test_super, 53413fcc683SDavid Howells afs_set_super); 53508e0e7c8SDavid Howells if (IS_ERR(sb)) { 53608e0e7c8SDavid Howells ret = PTR_ERR(sb); 53713fcc683SDavid Howells goto error; 53808e0e7c8SDavid Howells } 5391da177e4SLinus Torvalds 540436058a4SDavid Howells if (!sb->s_root) { 541436058a4SDavid Howells /* initial superblock/root creation */ 542436058a4SDavid Howells _debug("create"); 54313fcc683SDavid Howells ret = afs_fill_super(sb, ctx); 544f044c884SDavid Howells if (ret < 0) 545f044c884SDavid Howells goto error_sb; 5461751e8a6SLinus Torvalds sb->s_flags |= SB_ACTIVE; 547436058a4SDavid Howells } else { 548436058a4SDavid Howells _debug("reuse"); 5491751e8a6SLinus Torvalds ASSERTCMP(sb->s_flags, &, SB_ACTIVE); 550436058a4SDavid Howells } 5511da177e4SLinus Torvalds 55213fcc683SDavid Howells fc->root = dget(sb->s_root); 55308e0e7c8SDavid Howells _leave(" = 0 [%p]", sb); 55413fcc683SDavid Howells return 0; 5551da177e4SLinus Torvalds 556f044c884SDavid Howells error_sb: 557f044c884SDavid Howells deactivate_locked_super(sb); 5581da177e4SLinus Torvalds error: 5591da177e4SLinus Torvalds _leave(" = %d", ret); 56013fcc683SDavid Howells return ret; 56113fcc683SDavid Howells } 56213fcc683SDavid Howells 56313fcc683SDavid Howells static void afs_free_fc(struct fs_context *fc) 56413fcc683SDavid Howells { 56513fcc683SDavid Howells struct afs_fs_context *ctx = fc->fs_private; 56613fcc683SDavid Howells 56713fcc683SDavid Howells afs_destroy_sbi(fc->s_fs_info); 56813fcc683SDavid Howells afs_put_volume(ctx->cell, ctx->volume); 56913fcc683SDavid Howells afs_put_cell(ctx->net, ctx->cell); 57013fcc683SDavid Howells key_put(ctx->key); 57113fcc683SDavid Howells kfree(ctx); 57213fcc683SDavid Howells } 57313fcc683SDavid Howells 57413fcc683SDavid Howells static const struct fs_context_operations afs_context_ops = { 57513fcc683SDavid Howells .free = afs_free_fc, 57613fcc683SDavid Howells .parse_param = afs_parse_param, 57713fcc683SDavid Howells .get_tree = afs_get_tree, 57813fcc683SDavid Howells }; 57913fcc683SDavid Howells 58013fcc683SDavid Howells /* 58113fcc683SDavid Howells * Set up the filesystem mount context. 58213fcc683SDavid Howells */ 58313fcc683SDavid Howells static int afs_init_fs_context(struct fs_context *fc) 58413fcc683SDavid Howells { 58513fcc683SDavid Howells struct afs_fs_context *ctx; 58613fcc683SDavid Howells struct afs_cell *cell; 58713fcc683SDavid Howells 58813fcc683SDavid Howells ctx = kzalloc(sizeof(struct afs_fs_context), GFP_KERNEL); 58913fcc683SDavid Howells if (!ctx) 59013fcc683SDavid Howells return -ENOMEM; 59113fcc683SDavid Howells 59213fcc683SDavid Howells ctx->type = AFSVL_ROVOL; 59313fcc683SDavid Howells ctx->net = afs_net(fc->net_ns); 59413fcc683SDavid Howells 59513fcc683SDavid Howells /* Default to the workstation cell. */ 59613fcc683SDavid Howells rcu_read_lock(); 59713fcc683SDavid Howells cell = afs_lookup_cell_rcu(ctx->net, NULL, 0); 59813fcc683SDavid Howells rcu_read_unlock(); 59913fcc683SDavid Howells if (IS_ERR(cell)) 60013fcc683SDavid Howells cell = NULL; 60113fcc683SDavid Howells ctx->cell = cell; 60213fcc683SDavid Howells 60313fcc683SDavid Howells fc->fs_private = ctx; 60413fcc683SDavid Howells fc->ops = &afs_context_ops; 60513fcc683SDavid Howells return 0; 606ec26815aSDavid Howells } 6071da177e4SLinus Torvalds 6081da177e4SLinus Torvalds /* 609f8de483eSDavid Howells * Initialise an inode cache slab element prior to any use. Note that 610f8de483eSDavid Howells * afs_alloc_inode() *must* reset anything that could incorrectly leak from one 611f8de483eSDavid Howells * inode to another. 6121da177e4SLinus Torvalds */ 61351cc5068SAlexey Dobriyan static void afs_i_init_once(void *_vnode) 6141da177e4SLinus Torvalds { 615ec26815aSDavid Howells struct afs_vnode *vnode = _vnode; 6161da177e4SLinus Torvalds 6171da177e4SLinus Torvalds memset(vnode, 0, sizeof(*vnode)); 6181da177e4SLinus Torvalds inode_init_once(&vnode->vfs_inode); 619d2ddc776SDavid Howells mutex_init(&vnode->io_lock); 620b61f7dcfSDavid Howells init_rwsem(&vnode->validate_lock); 6214343d008SDavid Howells spin_lock_init(&vnode->wb_lock); 6221da177e4SLinus Torvalds spin_lock_init(&vnode->lock); 6234343d008SDavid Howells INIT_LIST_HEAD(&vnode->wb_keys); 624e8d6c554SDavid Howells INIT_LIST_HEAD(&vnode->pending_locks); 625e8d6c554SDavid Howells INIT_LIST_HEAD(&vnode->granted_locks); 626e8d6c554SDavid Howells INIT_DELAYED_WORK(&vnode->lock_work, afs_lock_work); 627c435ee34SDavid Howells seqlock_init(&vnode->cb_lock); 6281da177e4SLinus Torvalds } 6291da177e4SLinus Torvalds 6301da177e4SLinus Torvalds /* 6311da177e4SLinus Torvalds * allocate an AFS inode struct from our slab cache 6321da177e4SLinus Torvalds */ 6331da177e4SLinus Torvalds static struct inode *afs_alloc_inode(struct super_block *sb) 6341da177e4SLinus Torvalds { 6351da177e4SLinus Torvalds struct afs_vnode *vnode; 6361da177e4SLinus Torvalds 637ec26815aSDavid Howells vnode = kmem_cache_alloc(afs_inode_cachep, GFP_KERNEL); 6381da177e4SLinus Torvalds if (!vnode) 6391da177e4SLinus Torvalds return NULL; 6401da177e4SLinus Torvalds 6411da177e4SLinus Torvalds atomic_inc(&afs_count_active_inodes); 6421da177e4SLinus Torvalds 643f8de483eSDavid Howells /* Reset anything that shouldn't leak from one inode to the next. */ 6441da177e4SLinus Torvalds memset(&vnode->fid, 0, sizeof(vnode->fid)); 6451da177e4SLinus Torvalds memset(&vnode->status, 0, sizeof(vnode->status)); 6461da177e4SLinus Torvalds 6471da177e4SLinus Torvalds vnode->volume = NULL; 648f8de483eSDavid Howells vnode->lock_key = NULL; 649f8de483eSDavid Howells vnode->permit_cache = NULL; 650f8de483eSDavid Howells vnode->cb_interest = NULL; 651f8de483eSDavid Howells #ifdef CONFIG_AFS_FSCACHE 652f8de483eSDavid Howells vnode->cache = NULL; 653f8de483eSDavid Howells #endif 654f8de483eSDavid Howells 655260a9803SDavid Howells vnode->flags = 1 << AFS_VNODE_UNSET; 656f8de483eSDavid Howells vnode->cb_type = 0; 657f8de483eSDavid Howells vnode->lock_state = AFS_VNODE_LOCK_NONE; 6581da177e4SLinus Torvalds 6590f300ca9SDavid Howells _leave(" = %p", &vnode->vfs_inode); 6601da177e4SLinus Torvalds return &vnode->vfs_inode; 661ec26815aSDavid Howells } 6621da177e4SLinus Torvalds 663fa0d7e3dSNick Piggin static void afs_i_callback(struct rcu_head *head) 664fa0d7e3dSNick Piggin { 665fa0d7e3dSNick Piggin struct inode *inode = container_of(head, struct inode, i_rcu); 666fa0d7e3dSNick Piggin struct afs_vnode *vnode = AFS_FS_I(inode); 667fa0d7e3dSNick Piggin kmem_cache_free(afs_inode_cachep, vnode); 668fa0d7e3dSNick Piggin } 669fa0d7e3dSNick Piggin 6701da177e4SLinus Torvalds /* 6711da177e4SLinus Torvalds * destroy an AFS inode struct 6721da177e4SLinus Torvalds */ 6731da177e4SLinus Torvalds static void afs_destroy_inode(struct inode *inode) 6741da177e4SLinus Torvalds { 67508e0e7c8SDavid Howells struct afs_vnode *vnode = AFS_FS_I(inode); 67608e0e7c8SDavid Howells 6773b6492dfSDavid Howells _enter("%p{%llx:%llu}", inode, vnode->fid.vid, vnode->fid.vnode); 6781da177e4SLinus Torvalds 67908e0e7c8SDavid Howells _debug("DESTROY INODE %p", inode); 68008e0e7c8SDavid Howells 681c435ee34SDavid Howells ASSERTCMP(vnode->cb_interest, ==, NULL); 68208e0e7c8SDavid Howells 683fa0d7e3dSNick Piggin call_rcu(&inode->i_rcu, afs_i_callback); 6841da177e4SLinus Torvalds atomic_dec(&afs_count_active_inodes); 685ec26815aSDavid Howells } 68645222b9eSDavid Howells 68745222b9eSDavid Howells /* 68845222b9eSDavid Howells * return information about an AFS volume 68945222b9eSDavid Howells */ 69045222b9eSDavid Howells static int afs_statfs(struct dentry *dentry, struct kstatfs *buf) 69145222b9eSDavid Howells { 6924d673da1SDavid Howells struct afs_super_info *as = AFS_FS_S(dentry->d_sb); 693d2ddc776SDavid Howells struct afs_fs_cursor fc; 69445222b9eSDavid Howells struct afs_volume_status vs; 6952b0143b5SDavid Howells struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry)); 69645222b9eSDavid Howells struct key *key; 69745222b9eSDavid Howells int ret; 69845222b9eSDavid Howells 6994d673da1SDavid Howells buf->f_type = dentry->d_sb->s_magic; 7004d673da1SDavid Howells buf->f_bsize = AFS_BLOCK_SIZE; 7014d673da1SDavid Howells buf->f_namelen = AFSNAMEMAX - 1; 7024d673da1SDavid Howells 7034d673da1SDavid Howells if (as->dyn_root) { 7044d673da1SDavid Howells buf->f_blocks = 1; 7054d673da1SDavid Howells buf->f_bavail = 0; 7064d673da1SDavid Howells buf->f_bfree = 0; 7074d673da1SDavid Howells return 0; 7084d673da1SDavid Howells } 7094d673da1SDavid Howells 71045222b9eSDavid Howells key = afs_request_key(vnode->volume->cell); 71145222b9eSDavid Howells if (IS_ERR(key)) 71245222b9eSDavid Howells return PTR_ERR(key); 71345222b9eSDavid Howells 714d2ddc776SDavid Howells ret = -ERESTARTSYS; 715d2ddc776SDavid Howells if (afs_begin_vnode_operation(&fc, vnode, key)) { 716d2ddc776SDavid Howells fc.flags |= AFS_FS_CURSOR_NO_VSLEEP; 717d2ddc776SDavid Howells while (afs_select_fileserver(&fc)) { 71868251f0aSDavid Howells fc.cb_break = afs_calc_vnode_cb_break(vnode); 719d2ddc776SDavid Howells afs_fs_get_volume_status(&fc, &vs); 72045222b9eSDavid Howells } 72145222b9eSDavid Howells 722d2ddc776SDavid Howells afs_check_for_remote_deletion(&fc, fc.vnode); 723d2ddc776SDavid Howells afs_vnode_commit_status(&fc, vnode, fc.cb_break); 724d2ddc776SDavid Howells ret = afs_end_vnode_operation(&fc); 725d2ddc776SDavid Howells } 726d2ddc776SDavid Howells 727d2ddc776SDavid Howells key_put(key); 728d2ddc776SDavid Howells 729d2ddc776SDavid Howells if (ret == 0) { 73045222b9eSDavid Howells if (vs.max_quota == 0) 73145222b9eSDavid Howells buf->f_blocks = vs.part_max_blocks; 73245222b9eSDavid Howells else 73345222b9eSDavid Howells buf->f_blocks = vs.max_quota; 73445222b9eSDavid Howells buf->f_bavail = buf->f_bfree = buf->f_blocks - vs.blocks_in_use; 735d2ddc776SDavid Howells } 736d2ddc776SDavid Howells 737d2ddc776SDavid Howells return ret; 73845222b9eSDavid Howells } 739