X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=fs%2Fafs%2Fsuper.c;h=d24be334b6089c592068634de7f613d8f2114f27;hb=d3f9882cca84a7cb67a19bbc597356b49896b8c2;hp=eb7e32349da3e4354c884af376c6ffcbff509b71;hpb=902b236c087bf021c94cc21a2b09d928c4156c2b;p=powerpc.git diff --git a/fs/afs/super.c b/fs/afs/super.c index eb7e32349d..d24be334b6 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -1,5 +1,6 @@ -/* - * Copyright (c) 2002 Red Hat, Inc. All rights reserved. +/* AFS superblock handling + * + * Copyright (c) 2002, 2007 Red Hat, Inc. All rights reserved. * * This software may be freely redistributed under the terms of the * GNU General Public License. @@ -9,7 +10,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Authors: David Howells - * David Woodhouse + * David Woodhouse * */ @@ -19,22 +20,11 @@ #include #include #include -#include "vnode.h" -#include "volume.h" -#include "cell.h" -#include "cmservice.h" -#include "fsclient.h" -#include "super.h" +#include #include "internal.h" #define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */ -struct afs_mount_params { - int rwpath; - struct afs_cell *default_cell; - struct afs_volume *volume; -}; - static void afs_i_init_once(void *foo, struct kmem_cache *cachep, unsigned long flags); @@ -53,22 +43,37 @@ struct file_system_type afs_fs_type = { .name = "afs", .get_sb = afs_get_sb, .kill_sb = kill_anon_super, - .fs_flags = FS_BINARY_MOUNTDATA, + .fs_flags = 0, }; static const struct super_operations afs_super_ops = { .statfs = simple_statfs, .alloc_inode = afs_alloc_inode, .drop_inode = generic_delete_inode, + .write_inode = afs_write_inode, .destroy_inode = afs_destroy_inode, .clear_inode = afs_clear_inode, + .umount_begin = afs_umount_begin, .put_super = afs_put_super, }; static struct kmem_cache *afs_inode_cachep; static atomic_t afs_count_active_inodes; -/*****************************************************************************/ +enum { + afs_no_opt, + afs_opt_cell, + afs_opt_rwpath, + afs_opt_vol, +}; + +static match_table_t afs_options_list = { + { afs_opt_cell, "cell=%s" }, + { afs_opt_rwpath, "rwpath" }, + { afs_opt_vol, "vol=%s" }, + { afs_no_opt, NULL }, +}; + /* * initialise the filesystem */ @@ -78,8 +83,6 @@ int __init afs_fs_init(void) _enter(""); - afs_timer_init(&afs_mntpt_expiry_timer, &afs_mntpt_expiry_timer_ops); - /* create ourselves an inode cache */ atomic_set(&afs_count_active_inodes, 0); @@ -99,20 +102,22 @@ int __init afs_fs_init(void) ret = register_filesystem(&afs_fs_type); if (ret < 0) { kmem_cache_destroy(afs_inode_cachep); - kleave(" = %d", ret); + _leave(" = %d", ret); return ret; } - kleave(" = 0"); + _leave(" = 0"); return 0; -} /* end afs_fs_init() */ +} -/*****************************************************************************/ /* * clean up the filesystem */ void __exit afs_fs_exit(void) { + _enter(""); + + afs_mntpt_kill_timer(); unregister_filesystem(&afs_fs_type); if (atomic_read(&afs_count_active_inodes) != 0) { @@ -122,99 +127,153 @@ void __exit afs_fs_exit(void) } kmem_cache_destroy(afs_inode_cachep); + _leave(""); +} -} /* end afs_fs_exit() */ - -/*****************************************************************************/ -/* - * check that an argument has a value - */ -static int want_arg(char **_value, const char *option) -{ - if (!_value || !*_value || !**_value) { - printk(KERN_NOTICE "kAFS: %s: argument missing\n", option); - return 0; - } - return 1; -} /* end want_arg() */ - -/*****************************************************************************/ -/* - * check that there's no subsequent value - */ -static int want_no_value(char *const *_value, const char *option) -{ - if (*_value && **_value) { - printk(KERN_NOTICE "kAFS: %s: Invalid argument: %s\n", - option, *_value); - return 0; - } - return 1; -} /* end want_no_value() */ - -/*****************************************************************************/ /* * parse the mount options * - this function has been shamelessly adapted from the ext3 fs which * shamelessly adapted it from the msdos fs */ -static int afs_super_parse_options(struct afs_mount_params *params, - char *options, - const char **devname) +static int afs_parse_options(struct afs_mount_params *params, + char *options, const char **devname) { - char *key, *value; - int ret; + struct afs_cell *cell; + substring_t args[MAX_OPT_ARGS]; + char *p; + int token; _enter("%s", options); options[PAGE_SIZE - 1] = 0; - ret = 0; - while ((key = strsep(&options, ",")) != 0) - { - value = strchr(key, '='); - if (value) - *value++ = 0; - - printk("kAFS: KEY: %s, VAL:%s\n", key, value ?: "-"); + while ((p = strsep(&options, ","))) { + if (!*p) + continue; - if (strcmp(key, "rwpath") == 0) { - if (!want_no_value(&value, "rwpath")) - return -EINVAL; + token = match_token(p, afs_options_list, args); + switch (token) { + case afs_opt_cell: + cell = afs_cell_lookup(args[0].from, + args[0].to - args[0].from); + if (IS_ERR(cell)) + return PTR_ERR(cell); + afs_put_cell(params->cell); + params->cell = cell; + break; + + case afs_opt_rwpath: params->rwpath = 1; - continue; - } - else if (strcmp(key, "vol") == 0) { - if (!want_arg(&value, "vol")) - return -EINVAL; - *devname = value; - continue; + break; + + case afs_opt_vol: + *devname = args[0].from; + break; + + default: + printk(KERN_ERR "kAFS:" + " Unknown or invalid mount option: '%s'\n", p); + return -EINVAL; } - else if (strcmp(key, "cell") == 0) { - if (!want_arg(&value, "cell")) - return -EINVAL; - afs_put_cell(params->default_cell); - ret = afs_cell_lookup(value, - strlen(value), - ¶ms->default_cell); - if (ret < 0) - return -EINVAL; - continue; + } + + _leave(" = 0"); + return 0; +} + +/* + * parse a device name to get cell name, volume name, volume type and R/W + * selector + * - this can be one of the following: + * "%[cell:]volume[.]" R/W volume + * "#[cell:]volume[.]" R/O or R/W volume (rwpath=0), + * or R/W (rwpath=1) volume + * "%[cell:]volume.readonly" R/O volume + * "#[cell:]volume.readonly" R/O volume + * "%[cell:]volume.backup" Backup volume + * "#[cell:]volume.backup" Backup volume + */ +static int afs_parse_device_name(struct afs_mount_params *params, + const char *name) +{ + struct afs_cell *cell; + const char *cellname, *suffix; + int cellnamesz; + + _enter(",%s", name); + + if (!name) { + printk(KERN_ERR "kAFS: no volume name specified\n"); + return -EINVAL; + } + + if ((name[0] != '%' && name[0] != '#') || !name[1]) { + printk(KERN_ERR "kAFS: unparsable volume name\n"); + return -EINVAL; + } + + /* determine the type of volume we're looking for */ + params->type = AFSVL_ROVOL; + params->force = false; + if (params->rwpath || name[0] == '%') { + params->type = AFSVL_RWVOL; + params->force = true; + } + name++; + + /* split the cell name out if there is one */ + params->volname = strchr(name, ':'); + if (params->volname) { + cellname = name; + cellnamesz = params->volname - name; + params->volname++; + } else { + params->volname = name; + cellname = NULL; + cellnamesz = 0; + } + + /* the volume type is further affected by a possible suffix */ + suffix = strrchr(params->volname, '.'); + if (suffix) { + if (strcmp(suffix, ".readonly") == 0) { + params->type = AFSVL_ROVOL; + params->force = true; + } else if (strcmp(suffix, ".backup") == 0) { + params->type = AFSVL_BACKVOL; + params->force = true; + } else if (suffix[1] == 0) { + } else { + suffix = NULL; } + } - printk("kAFS: Unknown mount option: '%s'\n", key); - ret = -EINVAL; - goto error; + params->volnamesz = suffix ? + suffix - params->volname : strlen(params->volname); + + _debug("cell %*.*s [%p]", + cellnamesz, cellnamesz, cellname ?: "", params->cell); + + /* lookup the cell record */ + if (cellname || !params->cell) { + cell = afs_cell_lookup(cellname, cellnamesz); + if (IS_ERR(cell)) { + printk(KERN_ERR "kAFS: unable to lookup cell '%s'\n", + cellname ?: ""); + return PTR_ERR(cell); + } + afs_put_cell(params->cell); + params->cell = cell; } - ret = 0; + _debug("CELL:%s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s", + params->cell->name, params->cell, + params->volnamesz, params->volnamesz, params->volname, + suffix ?: "-", params->type, params->force ? " FORCE" : ""); - error: - _leave(" = %d", ret); - return ret; -} /* end afs_super_parse_options() */ + return 0; +} -/*****************************************************************************/ /* * check a superblock to see if it's the one we're looking for */ @@ -224,13 +283,12 @@ static int afs_test_super(struct super_block *sb, void *data) struct afs_super_info *as = sb->s_fs_info; return as->volume == params->volume; -} /* end afs_test_super() */ +} -/*****************************************************************************/ /* * fill in the superblock */ -static int afs_fill_super(struct super_block *sb, void *data, int silent) +static int afs_fill_super(struct super_block *sb, void *data) { struct afs_mount_params *params = data; struct afs_super_info *as = NULL; @@ -239,7 +297,7 @@ static int afs_fill_super(struct super_block *sb, void *data, int silent) struct inode *inode = NULL; int ret; - kenter(""); + _enter(""); /* allocate a superblock info record */ as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL); @@ -262,9 +320,9 @@ static int afs_fill_super(struct super_block *sb, void *data, int silent) fid.vid = as->volume->vid; fid.vnode = 1; fid.unique = 1; - ret = afs_iget(sb, &fid, &inode); - if (ret < 0) - goto error; + inode = afs_iget(sb, params->key, &fid, NULL, NULL); + if (IS_ERR(inode)) + goto error_inode; ret = -ENOMEM; root = d_alloc_root(inode); @@ -273,24 +331,25 @@ static int afs_fill_super(struct super_block *sb, void *data, int silent) sb->s_root = root; - kleave(" = 0"); + _leave(" = 0"); return 0; - error: +error_inode: + ret = PTR_ERR(inode); + inode = NULL; +error: iput(inode); afs_put_volume(as->volume); kfree(as); sb->s_fs_info = NULL; - kleave(" = %d", ret); + _leave(" = %d", ret); return ret; -} /* end afs_fill_super() */ +} -/*****************************************************************************/ /* * get an AFS superblock - * - TODO: don't use get_sb_nodev(), but rather call sget() directly */ static int afs_get_sb(struct file_system_type *fs_type, int flags, @@ -300,69 +359,79 @@ static int afs_get_sb(struct file_system_type *fs_type, { struct afs_mount_params params; struct super_block *sb; + struct afs_volume *vol; + struct key *key; int ret; _enter(",,%s,%p", dev_name, options); memset(¶ms, 0, sizeof(params)); - /* start the cache manager */ - ret = afscm_start(); - if (ret < 0) { - _leave(" = %d", ret); - return ret; - } - - /* parse the options */ + /* parse the options and device name */ if (options) { - ret = afs_super_parse_options(¶ms, options, &dev_name); + ret = afs_parse_options(¶ms, options, &dev_name); if (ret < 0) goto error; - if (!dev_name) { - printk("kAFS: no volume name specified\n"); - ret = -EINVAL; - goto error; - } } - /* parse the device name */ - ret = afs_volume_lookup(dev_name, - params.default_cell, - params.rwpath, - ¶ms.volume); + ret = afs_parse_device_name(¶ms, dev_name); if (ret < 0) goto error; - /* allocate a deviceless superblock */ - sb = sget(fs_type, afs_test_super, set_anon_super, ¶ms); - if (IS_ERR(sb)) + /* try and do the mount securely */ + key = afs_request_key(params.cell); + if (IS_ERR(key)) { + _leave(" = %ld [key]", PTR_ERR(key)); + ret = PTR_ERR(key); goto error; + } + params.key = key; - sb->s_flags = flags; + /* parse the device name */ + vol = afs_volume_lookup(¶ms); + if (IS_ERR(vol)) { + ret = PTR_ERR(vol); + goto error; + } + params.volume = vol; - ret = afs_fill_super(sb, ¶ms, flags & MS_SILENT ? 1 : 0); - if (ret < 0) { - up_write(&sb->s_umount); - deactivate_super(sb); + /* allocate a deviceless superblock */ + sb = sget(fs_type, afs_test_super, set_anon_super, ¶ms); + if (IS_ERR(sb)) { + ret = PTR_ERR(sb); goto error; } - sb->s_flags |= MS_ACTIVE; - simple_set_mnt(mnt, sb); + if (!sb->s_root) { + /* initial superblock/root creation */ + _debug("create"); + sb->s_flags = flags; + ret = afs_fill_super(sb, ¶ms); + if (ret < 0) { + up_write(&sb->s_umount); + deactivate_super(sb); + goto error; + } + sb->s_flags |= MS_ACTIVE; + } else { + _debug("reuse"); + ASSERTCMP(sb->s_flags, &, MS_ACTIVE); + } + + simple_set_mnt(mnt, sb); afs_put_volume(params.volume); - afs_put_cell(params.default_cell); - _leave(" = 0 [%p]", 0, sb); + afs_put_cell(params.cell); + _leave(" = 0 [%p]", sb); return 0; - error: +error: afs_put_volume(params.volume); - afs_put_cell(params.default_cell); - afscm_stop(); + afs_put_cell(params.cell); + key_put(params.key); _leave(" = %d", ret); return ret; -} /* end afs_get_sb() */ +} -/*****************************************************************************/ /* * finish the unmounting process on the superblock */ @@ -373,35 +442,31 @@ static void afs_put_super(struct super_block *sb) _enter(""); afs_put_volume(as->volume); - afscm_stop(); _leave(""); -} /* end afs_put_super() */ +} -/*****************************************************************************/ /* * initialise an inode cache slab element prior to any use */ static void afs_i_init_once(void *_vnode, struct kmem_cache *cachep, unsigned long flags) { - struct afs_vnode *vnode = (struct afs_vnode *) _vnode; + struct afs_vnode *vnode = _vnode; - if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == - SLAB_CTOR_CONSTRUCTOR) { + if (flags & SLAB_CTOR_CONSTRUCTOR) { memset(vnode, 0, sizeof(*vnode)); inode_init_once(&vnode->vfs_inode); init_waitqueue_head(&vnode->update_waitq); + mutex_init(&vnode->permits_lock); + mutex_init(&vnode->validate_lock); + spin_lock_init(&vnode->writeback_lock); spin_lock_init(&vnode->lock); - INIT_LIST_HEAD(&vnode->cb_link); - INIT_LIST_HEAD(&vnode->cb_hash_link); - afs_timer_init(&vnode->cb_timeout, - &afs_vnode_cb_timed_out_ops); + INIT_LIST_HEAD(&vnode->writebacks); + INIT_WORK(&vnode->cb_broken_work, afs_broken_callback_work); } +} -} /* end afs_i_init_once() */ - -/*****************************************************************************/ /* * allocate an AFS inode struct from our slab cache */ @@ -409,8 +474,7 @@ static struct inode *afs_alloc_inode(struct super_block *sb) { struct afs_vnode *vnode; - vnode = (struct afs_vnode *) - kmem_cache_alloc(afs_inode_cachep, GFP_KERNEL); + vnode = kmem_cache_alloc(afs_inode_cachep, GFP_KERNEL); if (!vnode) return NULL; @@ -421,21 +485,25 @@ static struct inode *afs_alloc_inode(struct super_block *sb) vnode->volume = NULL; vnode->update_cnt = 0; - vnode->flags = 0; + vnode->flags = 1 << AFS_VNODE_UNSET; + vnode->cb_promised = false; return &vnode->vfs_inode; -} /* end afs_alloc_inode() */ +} -/*****************************************************************************/ /* * destroy an AFS inode struct */ static void afs_destroy_inode(struct inode *inode) { + struct afs_vnode *vnode = AFS_FS_I(inode); + _enter("{%lu}", inode->i_ino); - kmem_cache_free(afs_inode_cachep, AFS_FS_I(inode)); + _debug("DESTROY INODE %p", inode); - atomic_dec(&afs_count_active_inodes); + ASSERTCMP(vnode->server, ==, NULL); -} /* end afs_destroy_inode() */ + kmem_cache_free(afs_inode_cachep, vnode); + atomic_dec(&afs_count_active_inodes); +}