123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441 |
- /*
- * Copyright (c) 2002 Red Hat, Inc. All rights reserved.
- *
- * This software may be freely redistributed under the terms of the
- * GNU General Public License.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Authors: David Howells <dhowells@redhat.com>
- * David Woodhouse <dwmw2@cambridge.redhat.com>
- *
- */
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/slab.h>
- #include <linux/fs.h>
- #include <linux/pagemap.h>
- #include "vnode.h"
- #include "volume.h"
- #include "cell.h"
- #include "cmservice.h"
- #include "fsclient.h"
- #include "super.h"
- #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, kmem_cache_t *cachep,
- unsigned long flags);
- static struct super_block *afs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data);
- static struct inode *afs_alloc_inode(struct super_block *sb);
- static void afs_put_super(struct super_block *sb);
- static void afs_destroy_inode(struct inode *inode);
- static struct file_system_type afs_fs_type = {
- .owner = THIS_MODULE,
- .name = "afs",
- .get_sb = afs_get_sb,
- .kill_sb = kill_anon_super,
- .fs_flags = FS_BINARY_MOUNTDATA,
- };
- static struct super_operations afs_super_ops = {
- .statfs = simple_statfs,
- .alloc_inode = afs_alloc_inode,
- .drop_inode = generic_delete_inode,
- .destroy_inode = afs_destroy_inode,
- .clear_inode = afs_clear_inode,
- .put_super = afs_put_super,
- };
- static kmem_cache_t *afs_inode_cachep;
- static atomic_t afs_count_active_inodes;
- /*****************************************************************************/
- /*
- * initialise the filesystem
- */
- int __init afs_fs_init(void)
- {
- int ret;
- _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);
- ret = -ENOMEM;
- afs_inode_cachep = kmem_cache_create("afs_inode_cache",
- sizeof(struct afs_vnode),
- 0,
- SLAB_HWCACHE_ALIGN,
- afs_i_init_once,
- NULL);
- if (!afs_inode_cachep) {
- printk(KERN_NOTICE "kAFS: Failed to allocate inode cache\n");
- return ret;
- }
- /* now export our filesystem to lesser mortals */
- ret = register_filesystem(&afs_fs_type);
- if (ret < 0) {
- kmem_cache_destroy(afs_inode_cachep);
- kleave(" = %d", ret);
- return ret;
- }
- kleave(" = 0");
- return 0;
- } /* end afs_fs_init() */
- /*****************************************************************************/
- /*
- * clean up the filesystem
- */
- void __exit afs_fs_exit(void)
- {
- unregister_filesystem(&afs_fs_type);
- if (atomic_read(&afs_count_active_inodes) != 0) {
- printk("kAFS: %d active inode objects still present\n",
- atomic_read(&afs_count_active_inodes));
- BUG();
- }
- kmem_cache_destroy(afs_inode_cachep);
- } /* 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)
- {
- char *key, *value;
- int ret;
- _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 ?: "-");
- if (strcmp(key, "rwpath") == 0) {
- if (!want_no_value(&value, "rwpath"))
- return -EINVAL;
- params->rwpath = 1;
- continue;
- }
- else if (strcmp(key, "vol") == 0) {
- if (!want_arg(&value, "vol"))
- return -EINVAL;
- *devname = value;
- continue;
- }
- 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;
- }
- printk("kAFS: Unknown mount option: '%s'\n", key);
- ret = -EINVAL;
- goto error;
- }
- ret = 0;
- error:
- _leave(" = %d", ret);
- return ret;
- } /* end afs_super_parse_options() */
- /*****************************************************************************/
- /*
- * check a superblock to see if it's the one we're looking for
- */
- static int afs_test_super(struct super_block *sb, void *data)
- {
- struct afs_mount_params *params = 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)
- {
- struct afs_mount_params *params = data;
- struct afs_super_info *as = NULL;
- struct afs_fid fid;
- struct dentry *root = NULL;
- struct inode *inode = NULL;
- int ret;
- kenter("");
- /* allocate a superblock info record */
- as = kmalloc(sizeof(struct afs_super_info), GFP_KERNEL);
- if (!as) {
- _leave(" = -ENOMEM");
- return -ENOMEM;
- }
- memset(as, 0, sizeof(struct afs_super_info));
- afs_get_volume(params->volume);
- as->volume = params->volume;
- /* fill in the superblock */
- sb->s_blocksize = PAGE_CACHE_SIZE;
- sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
- sb->s_magic = AFS_FS_MAGIC;
- sb->s_op = &afs_super_ops;
- sb->s_fs_info = as;
- /* allocate the root inode and dentry */
- fid.vid = as->volume->vid;
- fid.vnode = 1;
- fid.unique = 1;
- ret = afs_iget(sb, &fid, &inode);
- if (ret < 0)
- goto error;
- ret = -ENOMEM;
- root = d_alloc_root(inode);
- if (!root)
- goto error;
- sb->s_root = root;
- kleave(" = 0");
- return 0;
- error:
- iput(inode);
- afs_put_volume(as->volume);
- kfree(as);
- sb->s_fs_info = NULL;
- kleave(" = %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 struct super_block *afs_get_sb(struct file_system_type *fs_type,
- int flags,
- const char *dev_name,
- void *options)
- {
- struct afs_mount_params params;
- struct super_block *sb;
- 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 ERR_PTR(ret);
- }
- /* parse the options */
- if (options) {
- ret = afs_super_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);
- if (ret < 0)
- goto error;
- /* allocate a deviceless superblock */
- sb = sget(fs_type, afs_test_super, set_anon_super, ¶ms);
- if (IS_ERR(sb))
- goto error;
- sb->s_flags = flags;
- ret = afs_fill_super(sb, ¶ms, flags & MS_SILENT ? 1 : 0);
- if (ret < 0) {
- up_write(&sb->s_umount);
- deactivate_super(sb);
- goto error;
- }
- sb->s_flags |= MS_ACTIVE;
- afs_put_volume(params.volume);
- afs_put_cell(params.default_cell);
- _leave(" = %p", sb);
- return sb;
- error:
- afs_put_volume(params.volume);
- afs_put_cell(params.default_cell);
- afscm_stop();
- _leave(" = %d", ret);
- return ERR_PTR(ret);
- } /* end afs_get_sb() */
- /*****************************************************************************/
- /*
- * finish the unmounting process on the superblock
- */
- static void afs_put_super(struct super_block *sb)
- {
- struct afs_super_info *as = sb->s_fs_info;
- _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, kmem_cache_t *cachep,
- unsigned long flags)
- {
- struct afs_vnode *vnode = (struct afs_vnode *) _vnode;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR) {
- memset(vnode, 0, sizeof(*vnode));
- inode_init_once(&vnode->vfs_inode);
- init_waitqueue_head(&vnode->update_waitq);
- 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);
- }
- } /* end afs_i_init_once() */
- /*****************************************************************************/
- /*
- * allocate an AFS inode struct from our slab cache
- */
- static struct inode *afs_alloc_inode(struct super_block *sb)
- {
- struct afs_vnode *vnode;
- vnode = (struct afs_vnode *)
- kmem_cache_alloc(afs_inode_cachep, SLAB_KERNEL);
- if (!vnode)
- return NULL;
- atomic_inc(&afs_count_active_inodes);
- memset(&vnode->fid, 0, sizeof(vnode->fid));
- memset(&vnode->status, 0, sizeof(vnode->status));
- vnode->volume = NULL;
- vnode->update_cnt = 0;
- vnode->flags = 0;
- return &vnode->vfs_inode;
- } /* end afs_alloc_inode() */
- /*****************************************************************************/
- /*
- * destroy an AFS inode struct
- */
- static void afs_destroy_inode(struct inode *inode)
- {
- _enter("{%lu}", inode->i_ino);
- kmem_cache_free(afs_inode_cachep, AFS_FS_I(inode));
- atomic_dec(&afs_count_active_inodes);
- } /* end afs_destroy_inode() */
|