diff options
Diffstat (limited to 'fs/ufs/super.c')
| -rw-r--r-- | fs/ufs/super.c | 275 | 
1 files changed, 148 insertions, 127 deletions
diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 2c47daed56d..b879f1ba343 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -73,7 +73,6 @@  #include <stdarg.h>  #include <asm/uaccess.h> -#include <asm/system.h>  #include <linux/errno.h>  #include <linux/fs.h> @@ -84,7 +83,6 @@  #include <linux/blkdev.h>  #include <linux/init.h>  #include <linux/parser.h> -#include <linux/smp_lock.h>  #include <linux/buffer_head.h>  #include <linux/vfs.h>  #include <linux/log2.h> @@ -96,6 +94,26 @@  #include "swab.h"  #include "util.h" +void lock_ufs(struct super_block *sb) +{ +#if defined(CONFIG_SMP) || defined (CONFIG_PREEMPT) +	struct ufs_sb_info *sbi = UFS_SB(sb); + +	mutex_lock(&sbi->mutex); +	sbi->mutex_owner = current; +#endif +} + +void unlock_ufs(struct super_block *sb) +{ +#if defined(CONFIG_SMP) || defined (CONFIG_PREEMPT) +	struct ufs_sb_info *sbi = UFS_SB(sb); + +	sbi->mutex_owner = NULL; +	mutex_unlock(&sbi->mutex); +#endif +} +  static struct inode *ufs_nfs_get_inode(struct super_block *sb, u64 ino, u32 generation)  {  	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; @@ -128,10 +146,7 @@ static struct dentry *ufs_fh_to_parent(struct super_block *sb, struct fid *fid,  static struct dentry *ufs_get_parent(struct dentry *child)  { -	struct qstr dot_dot = { -		.name	= "..", -		.len	= 2, -	}; +	struct qstr dot_dot = QSTR_INIT("..", 2);  	ino_t ino;  	ino = ufs_inode_by_name(child->d_inode, &dot_dot); @@ -287,7 +302,7 @@ void ufs_error (struct super_block * sb, const char * function,  	if (!(sb->s_flags & MS_RDONLY)) {  		usb1->fs_clean = UFS_FSBAD;  		ubh_mark_buffer_dirty(USPI_UBH(uspi)); -		sb->s_dirt = 1; +		ufs_mark_sb_dirty(sb);  		sb->s_flags |= MS_RDONLY;  	}  	va_start (args, fmt); @@ -313,14 +328,13 @@ void ufs_panic (struct super_block * sb, const char * function,  	struct ufs_super_block_first * usb1;  	va_list args; -	lock_kernel();  	uspi = UFS_SB(sb)->s_uspi;  	usb1 = ubh_get_usb_first(uspi);  	if (!(sb->s_flags & MS_RDONLY)) {  		usb1->fs_clean = UFS_FSBAD;  		ubh_mark_buffer_dirty(USPI_UBH(uspi)); -		sb->s_dirt = 1; +		ufs_mark_sb_dirty(sb);  	}  	va_start (args, fmt);  	vsnprintf (error_buf, sizeof(error_buf), fmt, args); @@ -465,9 +479,9 @@ static int ufs_parse_options (char * options, unsigned * mount_options)  }  /* - * Diffrent types of UFS hold fs_cstotal in different - * places, and use diffrent data structure for it. - * To make things simplier we just copy fs_cstotal to ufs_sb_private_info + * Different types of UFS hold fs_cstotal in different + * places, and use different data structure for it. + * To make things simpler we just copy fs_cstotal to ufs_sb_private_info   */  static void ufs_setup_cstotal(struct super_block *sb)  { @@ -510,18 +524,16 @@ static int ufs_read_cylinder_structures(struct super_block *sb)  	struct ufs_buffer_head * ubh;  	unsigned char * base, * space;  	unsigned size, blks, i; -	struct ufs_super_block_third *usb3;  	UFSD("ENTER\n"); -	usb3 = ubh_get_usb_third(uspi);  	/*  	 * Read cs structures from (usually) first data block  	 * on the device.   	 */  	size = uspi->s_cssize;  	blks = (size + uspi->s_fsize - 1) >> uspi->s_fshift; -	base = space = kmalloc(size, GFP_KERNEL); +	base = space = kmalloc(size, GFP_NOFS);  	if (!base)  		goto failed;   	sbi->s_csp = (struct ufs_csum *)space; @@ -546,7 +558,7 @@ static int ufs_read_cylinder_structures(struct super_block *sb)  	 * Read cylinder group (we read only first fragment from block  	 * at this time) and prepare internal data structures for cg caching.  	 */ -	if (!(sbi->s_ucg = kmalloc (sizeof(struct buffer_head *) * uspi->s_ncg, GFP_KERNEL))) +	if (!(sbi->s_ucg = kmalloc (sizeof(struct buffer_head *) * uspi->s_ncg, GFP_NOFS)))  		goto failed;  	for (i = 0; i < uspi->s_ncg; i++)   		sbi->s_ucg[i] = NULL; @@ -564,7 +576,7 @@ static int ufs_read_cylinder_structures(struct super_block *sb)  		ufs_print_cylinder_stuff(sb, (struct ufs_cylinder_group *) sbi->s_ucg[i]->b_data);  	}  	for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) { -		if (!(sbi->s_ucpi[i] = kmalloc (sizeof(struct ufs_cg_private_info), GFP_KERNEL))) +		if (!(sbi->s_ucpi[i] = kmalloc (sizeof(struct ufs_cg_private_info), GFP_NOFS)))  			goto failed;  		sbi->s_cgno[i] = UFS_CGNO_EMPTY;  	} @@ -646,8 +658,6 @@ static void ufs_put_super_internal(struct super_block *sb)  	UFSD("ENTER\n"); -	lock_kernel(); -  	ufs_put_cstotal(sb);  	size = uspi->s_cssize;  	blks = (size + uspi->s_fsize - 1) >> uspi->s_fshift; @@ -676,9 +686,83 @@ static void ufs_put_super_internal(struct super_block *sb)  	kfree (sbi->s_ucg);  	kfree (base); -	unlock_kernel(); +	UFSD("EXIT\n"); +} + +static int ufs_sync_fs(struct super_block *sb, int wait) +{ +	struct ufs_sb_private_info * uspi; +	struct ufs_super_block_first * usb1; +	struct ufs_super_block_third * usb3; +	unsigned flags; + +	lock_ufs(sb); + +	UFSD("ENTER\n"); + +	flags = UFS_SB(sb)->s_flags; +	uspi = UFS_SB(sb)->s_uspi; +	usb1 = ubh_get_usb_first(uspi); +	usb3 = ubh_get_usb_third(uspi); + +	usb1->fs_time = cpu_to_fs32(sb, get_seconds()); +	if ((flags & UFS_ST_MASK) == UFS_ST_SUN  || +	    (flags & UFS_ST_MASK) == UFS_ST_SUNOS || +	    (flags & UFS_ST_MASK) == UFS_ST_SUNx86) +		ufs_set_fs_state(sb, usb1, usb3, +				UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time)); +	ufs_put_cstotal(sb);  	UFSD("EXIT\n"); +	unlock_ufs(sb); + +	return 0; +} + +static void delayed_sync_fs(struct work_struct *work) +{ +	struct ufs_sb_info *sbi; + +	sbi = container_of(work, struct ufs_sb_info, sync_work.work); + +	spin_lock(&sbi->work_lock); +	sbi->work_queued = 0; +	spin_unlock(&sbi->work_lock); + +	ufs_sync_fs(sbi->sb, 1); +} + +void ufs_mark_sb_dirty(struct super_block *sb) +{ +	struct ufs_sb_info *sbi = UFS_SB(sb); +	unsigned long delay; + +	spin_lock(&sbi->work_lock); +	if (!sbi->work_queued) { +		delay = msecs_to_jiffies(dirty_writeback_interval * 10); +		queue_delayed_work(system_long_wq, &sbi->sync_work, delay); +		sbi->work_queued = 1; +	} +	spin_unlock(&sbi->work_lock); +} + +static void ufs_put_super(struct super_block *sb) +{ +	struct ufs_sb_info * sbi = UFS_SB(sb); + +	UFSD("ENTER\n"); + +	if (!(sb->s_flags & MS_RDONLY)) +		ufs_put_super_internal(sb); +	cancel_delayed_work_sync(&sbi->sync_work); + +	ubh_brelse_uspi (sbi->s_uspi); +	kfree (sbi->s_uspi); +	mutex_destroy(&sbi->mutex); +	kfree (sbi); +	sb->s_fs_info = NULL; +	UFSD("EXIT\n"); +	return;  }  static int ufs_fill_super(struct super_block *sb, void *data, int silent) @@ -696,28 +780,31 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)  	unsigned maxsymlen;  	int ret = -EINVAL; -	lock_kernel(); -  	uspi = NULL;  	ubh = NULL;  	flags = 0;  	UFSD("ENTER\n"); + +#ifndef CONFIG_UFS_FS_WRITE +	if (!(sb->s_flags & MS_RDONLY)) { +		printk("ufs was compiled with read-only support, " +		       "can't be mounted as read-write\n"); +		return -EROFS; +	} +#endif  	sbi = kzalloc(sizeof(struct ufs_sb_info), GFP_KERNEL);  	if (!sbi)  		goto failed_nomem;  	sb->s_fs_info = sbi; +	sbi->sb = sb;  	UFSD("flag %u\n", (int)(sb->s_flags & MS_RDONLY)); -#ifndef CONFIG_UFS_FS_WRITE -	if (!(sb->s_flags & MS_RDONLY)) { -		printk("ufs was compiled with read-only support, " -		"can't be mounted as read-write\n"); -		goto failed; -	} -#endif +	mutex_init(&sbi->mutex); +	spin_lock_init(&sbi->work_lock); +	INIT_DELAYED_WORK(&sbi->sync_work, delayed_sync_fs);  	/*  	 * Set default mount options  	 * Parse mount options @@ -1144,16 +1231,17 @@ magic_found:  			    "fast symlink size (%u)\n", uspi->s_maxsymlinklen);  		uspi->s_maxsymlinklen = maxsymlen;  	} +	sb->s_max_links = UFS_LINK_MAX;  	inode = ufs_iget(sb, UFS_ROOTINO);  	if (IS_ERR(inode)) {  		ret = PTR_ERR(inode);  		goto failed;  	} -	sb->s_root = d_alloc_root(inode); +	sb->s_root = d_make_root(inode);  	if (!sb->s_root) {  		ret = -ENOMEM; -		goto dalloc_failed; +		goto failed;  	}  	ufs_setup_cstotal(sb); @@ -1165,89 +1253,23 @@ magic_found:  			goto failed;  	UFSD("EXIT\n"); -	unlock_kernel();  	return 0; -dalloc_failed: -	iput(inode);  failed: +	mutex_destroy(&sbi->mutex);  	if (ubh)  		ubh_brelse_uspi (uspi);  	kfree (uspi);  	kfree(sbi);  	sb->s_fs_info = NULL;  	UFSD("EXIT (FAILED)\n"); -	unlock_kernel();  	return ret;  failed_nomem:  	UFSD("EXIT (NOMEM)\n"); -	unlock_kernel();  	return -ENOMEM;  } -static int ufs_sync_fs(struct super_block *sb, int wait) -{ -	struct ufs_sb_private_info * uspi; -	struct ufs_super_block_first * usb1; -	struct ufs_super_block_third * usb3; -	unsigned flags; - -	lock_super(sb); -	lock_kernel(); - -	UFSD("ENTER\n"); - -	flags = UFS_SB(sb)->s_flags; -	uspi = UFS_SB(sb)->s_uspi; -	usb1 = ubh_get_usb_first(uspi); -	usb3 = ubh_get_usb_third(uspi); - -	usb1->fs_time = cpu_to_fs32(sb, get_seconds()); -	if ((flags & UFS_ST_MASK) == UFS_ST_SUN  || -	    (flags & UFS_ST_MASK) == UFS_ST_SUNOS || -	    (flags & UFS_ST_MASK) == UFS_ST_SUNx86) -		ufs_set_fs_state(sb, usb1, usb3, -				UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time)); -	ufs_put_cstotal(sb); -	sb->s_dirt = 0; - -	UFSD("EXIT\n"); -	unlock_kernel(); -	unlock_super(sb); - -	return 0; -} - -static void ufs_write_super(struct super_block *sb) -{ -	if (!(sb->s_flags & MS_RDONLY)) -		ufs_sync_fs(sb, 1); -	else -		sb->s_dirt = 0; -} - -static void ufs_put_super(struct super_block *sb) -{ -	struct ufs_sb_info * sbi = UFS_SB(sb); -		 -	UFSD("ENTER\n"); - -	if (sb->s_dirt) -		ufs_write_super(sb); - -	if (!(sb->s_flags & MS_RDONLY)) -		ufs_put_super_internal(sb); -	 -	ubh_brelse_uspi (sbi->s_uspi); -	kfree (sbi->s_uspi); -	kfree (sbi); -	sb->s_fs_info = NULL; -	UFSD("EXIT\n"); -	return; -} - -  static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)  {  	struct ufs_sb_private_info * uspi; @@ -1256,8 +1278,8 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)  	unsigned new_mount_opt, ufstype;  	unsigned flags; -	lock_kernel(); -	lock_super(sb); +	sync_filesystem(sb); +	lock_ufs(sb);  	uspi = UFS_SB(sb)->s_uspi;  	flags = UFS_SB(sb)->s_flags;  	usb1 = ubh_get_usb_first(uspi); @@ -1271,23 +1293,20 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)  	new_mount_opt = 0;  	ufs_set_opt (new_mount_opt, ONERROR_LOCK);  	if (!ufs_parse_options (data, &new_mount_opt)) { -		unlock_super(sb); -		unlock_kernel(); +		unlock_ufs(sb);  		return -EINVAL;  	}  	if (!(new_mount_opt & UFS_MOUNT_UFSTYPE)) {  		new_mount_opt |= ufstype;  	} else if ((new_mount_opt & UFS_MOUNT_UFSTYPE) != ufstype) {  		printk("ufstype can't be changed during remount\n"); -		unlock_super(sb); -		unlock_kernel(); +		unlock_ufs(sb);  		return -EINVAL;  	}  	if ((*mount_flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) {  		UFS_SB(sb)->s_mount_opt = new_mount_opt; -		unlock_super(sb); -		unlock_kernel(); +		unlock_ufs(sb);  		return 0;  	} @@ -1303,7 +1322,6 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)  			ufs_set_fs_state(sb, usb1, usb3,  				UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time));  		ubh_mark_buffer_dirty (USPI_UBH(uspi)); -		sb->s_dirt = 0;  		sb->s_flags |= MS_RDONLY;  	} else {  	/* @@ -1312,8 +1330,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)  #ifndef CONFIG_UFS_FS_WRITE  		printk("ufs was compiled with read-only support, "  		"can't be mounted as read-write\n"); -		unlock_super(sb); -		unlock_kernel(); +		unlock_ufs(sb);  		return -EINVAL;  #else  		if (ufstype != UFS_MOUNT_UFSTYPE_SUN &&  @@ -1322,28 +1339,25 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)  		    ufstype != UFS_MOUNT_UFSTYPE_SUNx86 &&  		    ufstype != UFS_MOUNT_UFSTYPE_UFS2) {  			printk("this ufstype is read-only supported\n"); -			unlock_super(sb); -			unlock_kernel(); +			unlock_ufs(sb);  			return -EINVAL;  		}  		if (!ufs_read_cylinder_structures(sb)) {  			printk("failed during remounting\n"); -			unlock_super(sb); -			unlock_kernel(); +			unlock_ufs(sb);  			return -EPERM;  		}  		sb->s_flags &= ~MS_RDONLY;  #endif  	}  	UFS_SB(sb)->s_mount_opt = new_mount_opt; -	unlock_super(sb); -	unlock_kernel(); +	unlock_ufs(sb);  	return 0;  } -static int ufs_show_options(struct seq_file *seq, struct vfsmount *vfs) +static int ufs_show_options(struct seq_file *seq, struct dentry *root)  { -	struct ufs_sb_info *sbi = UFS_SB(vfs->mnt_sb); +	struct ufs_sb_info *sbi = UFS_SB(root->d_sb);  	unsigned mval = sbi->s_mount_opt & UFS_MOUNT_UFSTYPE;  	const struct match_token *tp = tokens; @@ -1366,15 +1380,11 @@ static int ufs_statfs(struct dentry *dentry, struct kstatfs *buf)  	struct super_block *sb = dentry->d_sb;  	struct ufs_sb_private_info *uspi= UFS_SB(sb)->s_uspi;  	unsigned  flags = UFS_SB(sb)->s_flags; -	struct ufs_super_block_first *usb1; -	struct ufs_super_block_second *usb2;  	struct ufs_super_block_third *usb3;  	u64 id = huge_encode_dev(sb->s_bdev->bd_dev); -	lock_kernel(); +	lock_ufs(sb); -	usb1 = ubh_get_usb_first(uspi); -	usb2 = ubh_get_usb_second(uspi);  	usb3 = ubh_get_usb_third(uspi);  	if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) { @@ -1395,7 +1405,7 @@ static int ufs_statfs(struct dentry *dentry, struct kstatfs *buf)  	buf->f_fsid.val[0] = (u32)id;  	buf->f_fsid.val[1] = (u32)(id >> 32); -	unlock_kernel(); +	unlock_ufs(sb);  	return 0;  } @@ -1405,18 +1415,24 @@ static struct kmem_cache * ufs_inode_cachep;  static struct inode *ufs_alloc_inode(struct super_block *sb)  {  	struct ufs_inode_info *ei; -	ei = (struct ufs_inode_info *)kmem_cache_alloc(ufs_inode_cachep, GFP_KERNEL); +	ei = (struct ufs_inode_info *)kmem_cache_alloc(ufs_inode_cachep, GFP_NOFS);  	if (!ei)  		return NULL;  	ei->vfs_inode.i_version = 1;  	return &ei->vfs_inode;  } -static void ufs_destroy_inode(struct inode *inode) +static void ufs_i_callback(struct rcu_head *head)  { +	struct inode *inode = container_of(head, struct inode, i_rcu);  	kmem_cache_free(ufs_inode_cachep, UFS_I(inode));  } +static void ufs_destroy_inode(struct inode *inode) +{ +	call_rcu(&inode->i_rcu, ufs_i_callback); +} +  static void init_once(void *foo)  {  	struct ufs_inode_info *ei = (struct ufs_inode_info *) foo; @@ -1424,7 +1440,7 @@ static void init_once(void *foo)  	inode_init_once(&ei->vfs_inode);  } -static int init_inodecache(void) +static int __init init_inodecache(void)  {  	ufs_inode_cachep = kmem_cache_create("ufs_inode_cache",  					     sizeof(struct ufs_inode_info), @@ -1438,6 +1454,11 @@ static int init_inodecache(void)  static void destroy_inodecache(void)  { +	/* +	 * Make sure all delayed rcu free inodes are flushed before we +	 * destroy cache. +	 */ +	rcu_barrier();  	kmem_cache_destroy(ufs_inode_cachep);  } @@ -1447,7 +1468,6 @@ static const struct super_operations ufs_super_ops = {  	.write_inode	= ufs_write_inode,  	.evict_inode	= ufs_evict_inode,  	.put_super	= ufs_put_super, -	.write_super	= ufs_write_super,  	.sync_fs	= ufs_sync_fs,  	.statfs		= ufs_statfs,  	.remount_fs	= ufs_remount, @@ -1467,6 +1487,7 @@ static struct file_system_type ufs_fs_type = {  	.kill_sb	= kill_block_super,  	.fs_flags	= FS_REQUIRES_DEV,  }; +MODULE_ALIAS_FS("ufs");  static int __init init_ufs_fs(void)  {  | 
