diff options
Diffstat (limited to 'fs/afs/super.c')
| -rw-r--r-- | fs/afs/super.c | 104 | 
1 files changed, 56 insertions, 48 deletions
diff --git a/fs/afs/super.c b/fs/afs/super.c index 27201cffece..c4861557e38 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -24,6 +24,8 @@  #include <linux/parser.h>  #include <linux/statfs.h>  #include <linux/sched.h> +#include <linux/nsproxy.h> +#include <net/net_namespace.h>  #include "internal.h"  #define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */ @@ -31,8 +33,8 @@  static void afs_i_init_once(void *foo);  static struct dentry *afs_mount(struct file_system_type *fs_type,  		      int flags, const char *dev_name, void *data); +static void afs_kill_super(struct super_block *sb);  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 int afs_statfs(struct dentry *dentry, struct kstatfs *buf); @@ -40,9 +42,10 @@ struct file_system_type afs_fs_type = {  	.owner		= THIS_MODULE,  	.name		= "afs",  	.mount		= afs_mount, -	.kill_sb	= kill_anon_super, +	.kill_sb	= afs_kill_super,  	.fs_flags	= 0,  }; +MODULE_ALIAS_FS("afs");  static const struct super_operations afs_super_ops = {  	.statfs		= afs_statfs, @@ -50,7 +53,6 @@ static const struct super_operations afs_super_ops = {  	.drop_inode	= afs_drop_inode,  	.destroy_inode	= afs_destroy_inode,  	.evict_inode	= afs_evict_inode, -	.put_super	= afs_put_super,  	.show_options	= generic_show_options,  }; @@ -124,6 +126,11 @@ void __exit afs_fs_exit(void)  		BUG();  	} +	/* +	 * Make sure all delayed rcu free inodes are flushed before we +	 * destroy cache. +	 */ +	rcu_barrier();  	kmem_cache_destroy(afs_inode_cachep);  	_leave("");  } @@ -282,43 +289,38 @@ static int afs_parse_device_name(struct afs_mount_params *params,   */  static int afs_test_super(struct super_block *sb, void *data)  { -	struct afs_mount_params *params = data; +	struct afs_super_info *as1 = data;  	struct afs_super_info *as = sb->s_fs_info; -	return as->volume == params->volume; +	return as->volume == as1->volume; +} + +static int afs_set_super(struct super_block *sb, void *data) +{ +	sb->s_fs_info = data; +	return set_anon_super(sb, NULL);  }  /*   * fill in the superblock   */ -static int afs_fill_super(struct super_block *sb, void *data) +static int afs_fill_super(struct super_block *sb, +			  struct afs_mount_params *params)  { -	struct afs_mount_params *params = data; -	struct afs_super_info *as = NULL; +	struct afs_super_info *as = sb->s_fs_info;  	struct afs_fid fid; -	struct dentry *root = NULL;  	struct inode *inode = NULL;  	int ret;  	_enter(""); -	/* allocate a superblock info record */ -	as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL); -	if (!as) { -		_leave(" = -ENOMEM"); -		return -ENOMEM; -	} - -	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;  	sb->s_bdi		= &as->volume->bdi; +	strlcpy(sb->s_id, as->volume->vlocation->vldb.name, sizeof(sb->s_id));  	/* allocate the root inode and dentry */  	fid.vid		= as->volume->vid; @@ -326,31 +328,22 @@ static int afs_fill_super(struct super_block *sb, void *data)  	fid.unique	= 1;  	inode = afs_iget(sb, params->key, &fid, NULL, NULL);  	if (IS_ERR(inode)) -		goto error_inode; +		return PTR_ERR(inode);  	if (params->autocell)  		set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags);  	ret = -ENOMEM; -	root = d_alloc_root(inode); -	if (!root) +	sb->s_root = d_make_root(inode); +	if (!sb->s_root)  		goto error; -	sb->s_root = root; +	sb->s_d_op = &afs_fs_dentry_operations;  	_leave(" = 0");  	return 0; -error_inode: -	ret = PTR_ERR(inode); -	inode = NULL;  error: -	iput(inode); -	afs_put_volume(as->volume); -	kfree(as); - -	sb->s_fs_info = NULL; -  	_leave(" = %d", ret);  	return ret;  } @@ -366,12 +359,17 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,  	struct afs_volume *vol;  	struct key *key;  	char *new_opts = kstrdup(options, GFP_KERNEL); +	struct afs_super_info *as;  	int ret;  	_enter(",,%s,%p", dev_name, options);  	memset(¶ms, 0, sizeof(params)); +	ret = -EINVAL; +	if (current->nsproxy->net_ns != &init_net) +		goto error; +  	/* parse the options and device name */  	if (options) {  		ret = afs_parse_options(¶ms, options, &dev_name); @@ -398,19 +396,28 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,  		ret = PTR_ERR(vol);  		goto error;  	} -	params.volume = vol; + +	/* allocate a superblock info record */ +	as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL); +	if (!as) { +		ret = -ENOMEM; +		afs_put_volume(vol); +		goto error; +	} +	as->volume = vol;  	/* allocate a deviceless superblock */ -	sb = sget(fs_type, afs_test_super, set_anon_super, ¶ms); +	sb = sget(fs_type, afs_test_super, afs_set_super, flags, as);  	if (IS_ERR(sb)) {  		ret = PTR_ERR(sb); +		afs_put_volume(vol); +		kfree(as);  		goto error;  	}  	if (!sb->s_root) {  		/* initial superblock/root creation */  		_debug("create"); -		sb->s_flags = flags;  		ret = afs_fill_super(sb, ¶ms);  		if (ret < 0) {  			deactivate_locked_super(sb); @@ -421,16 +428,16 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,  	} else {  		_debug("reuse");  		ASSERTCMP(sb->s_flags, &, MS_ACTIVE); +		afs_put_volume(vol); +		kfree(as);  	} -	afs_put_volume(params.volume);  	afs_put_cell(params.cell);  	kfree(new_opts);  	_leave(" = 0 [%p]", sb);  	return dget(sb->s_root);  error: -	afs_put_volume(params.volume);  	afs_put_cell(params.cell);  	key_put(params.key);  	kfree(new_opts); @@ -438,18 +445,12 @@ error:  	return ERR_PTR(ret);  } -/* - * finish the unmounting process on the superblock - */ -static void afs_put_super(struct super_block *sb) +static void afs_kill_super(struct super_block *sb)  {  	struct afs_super_info *as = sb->s_fs_info; - -	_enter(""); - +	kill_anon_super(sb);  	afs_put_volume(as->volume); - -	_leave(""); +	kfree(as);  }  /* @@ -498,6 +499,13 @@ static struct inode *afs_alloc_inode(struct super_block *sb)  	return &vnode->vfs_inode;  } +static void afs_i_callback(struct rcu_head *head) +{ +	struct inode *inode = container_of(head, struct inode, i_rcu); +	struct afs_vnode *vnode = AFS_FS_I(inode); +	kmem_cache_free(afs_inode_cachep, vnode); +} +  /*   * destroy an AFS inode struct   */ @@ -511,7 +519,7 @@ static void afs_destroy_inode(struct inode *inode)  	ASSERTCMP(vnode->server, ==, NULL); -	kmem_cache_free(afs_inode_cachep, vnode); +	call_rcu(&inode->i_rcu, afs_i_callback);  	atomic_dec(&afs_count_active_inodes);  }  | 
