diff options
Diffstat (limited to 'fs/jfs/super.c')
| -rw-r--r-- | fs/jfs/super.c | 243 | 
1 files changed, 177 insertions, 66 deletions
diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 0669fc1cc3b..adf8cb045b9 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -33,6 +33,7 @@  #include <linux/slab.h>  #include <asm/uaccess.h>  #include <linux/seq_file.h> +#include <linux/blkdev.h>  #include "jfs_incore.h"  #include "jfs_filsys.h" @@ -43,19 +44,20 @@  #include "jfs_imap.h"  #include "jfs_acl.h"  #include "jfs_debug.h" +#include "jfs_xattr.h"  MODULE_DESCRIPTION("The Journaled Filesystem (JFS)");  MODULE_AUTHOR("Steve Best/Dave Kleikamp/Barry Arndt, IBM");  MODULE_LICENSE("GPL"); -static struct kmem_cache * jfs_inode_cachep; +static struct kmem_cache *jfs_inode_cachep;  static const struct super_operations jfs_super_operations;  static const struct export_operations jfs_export_operations;  static struct file_system_type jfs_fs_type;  #define MAX_COMMIT_THREADS 64 -static int commit_threads = 0; +static int commit_threads;  module_param(commit_threads, int, 0);  MODULE_PARM_DESC(commit_threads, "Number of commit threads"); @@ -82,8 +84,7 @@ static void jfs_handle_error(struct super_block *sb)  		panic("JFS (device %s): panic forced after error\n",  			sb->s_id);  	else if (sbi->flag & JFS_ERR_REMOUNT_RO) { -		jfs_err("ERROR: (device %s): remounting filesystem " -			"as read-only\n", +		jfs_err("ERROR: (device %s): remounting filesystem as read-only\n",  			sb->s_id);  		sb->s_flags |= MS_RDONLY;  	} @@ -91,16 +92,20 @@ static void jfs_handle_error(struct super_block *sb)  	/* nothing is done for continue beyond marking the superblock dirty */  } -void jfs_error(struct super_block *sb, const char * function, ...) +void jfs_error(struct super_block *sb, const char *fmt, ...)  { -	static char error_buf[256]; +	struct va_format vaf;  	va_list args; -	va_start(args, function); -	vsnprintf(error_buf, sizeof(error_buf), function, args); -	va_end(args); +	va_start(args, fmt); + +	vaf.fmt = fmt; +	vaf.va = &args; -	printk(KERN_ERR "ERROR: (device %s): %s\n", sb->s_id, error_buf); +	pr_err("ERROR: (device %s): %pf: %pV\n", +	       sb->s_id, __builtin_return_address(0), &vaf); + +	va_end(args);  	jfs_handle_error(sb);  } @@ -115,6 +120,13 @@ static struct inode *jfs_alloc_inode(struct super_block *sb)  	return &jfs_inode->vfs_inode;  } +static void jfs_i_callback(struct rcu_head *head) +{ +	struct inode *inode = container_of(head, struct inode, i_rcu); +	struct jfs_inode_info *ji = JFS_IP(inode); +	kmem_cache_free(jfs_inode_cachep, ji); +} +  static void jfs_destroy_inode(struct inode *inode)  {  	struct jfs_inode_info *ji = JFS_IP(inode); @@ -128,7 +140,7 @@ static void jfs_destroy_inode(struct inode *inode)  		ji->active_ag = -1;  	}  	spin_unlock_irq(&ji->ag_lock); -	kmem_cache_free(jfs_inode_cachep, ji); +	call_rcu(&inode->i_rcu, jfs_i_callback);  }  static int jfs_statfs(struct dentry *dentry, struct kstatfs *buf) @@ -146,7 +158,7 @@ static int jfs_statfs(struct dentry *dentry, struct kstatfs *buf)  	/*  	 * If we really return the number of allocated & free inodes, some  	 * applications will fail because they won't see enough free inodes. -	 * We'll try to calculate some guess as to how may inodes we can +	 * We'll try to calculate some guess as to how many inodes we can  	 * really allocate  	 *  	 * buf->f_files = atomic_read(&imap->im_numinos); @@ -190,7 +202,8 @@ static void jfs_put_super(struct super_block *sb)  enum {  	Opt_integrity, Opt_nointegrity, Opt_iocharset, Opt_resize,  	Opt_resize_nosize, Opt_errors, Opt_ignore, Opt_err, Opt_quota, -	Opt_usrquota, Opt_grpquota, Opt_uid, Opt_gid, Opt_umask +	Opt_usrquota, Opt_grpquota, Opt_uid, Opt_gid, Opt_umask, +	Opt_discard, Opt_nodiscard, Opt_discard_minblk  };  static const match_table_t tokens = { @@ -207,6 +220,9 @@ static const match_table_t tokens = {  	{Opt_uid, "uid=%u"},  	{Opt_gid, "gid=%u"},  	{Opt_umask, "umask=%u"}, +	{Opt_discard, "discard"}, +	{Opt_nodiscard, "nodiscard"}, +	{Opt_discard_minblk, "discard=%u"},  	{Opt_err, NULL}  }; @@ -248,8 +264,7 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,  			else {  				nls_map = load_nls(args[0].from);  				if (!nls_map) { -					printk(KERN_ERR -					       "JFS: charset not found\n"); +					pr_err("JFS: charset not found\n");  					goto cleanup;  				}  			} @@ -257,7 +272,10 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,  		case Opt_resize:  		{  			char *resize = args[0].from; -			*newLVSize = simple_strtoull(resize, &resize, 0); +			int rc = kstrtoll(resize, 0, newLVSize); + +			if (rc) +				goto cleanup;  			break;  		}  		case Opt_resize_nosize: @@ -265,8 +283,7 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,  			*newLVSize = sb->s_bdev->bd_inode->i_size >>  				sb->s_blocksize_bits;  			if (*newLVSize == 0) -				printk(KERN_ERR -				       "JFS: Cannot determine volume size\n"); +				pr_err("JFS: Cannot determine volume size\n");  			break;  		}  		case Opt_errors: @@ -287,8 +304,7 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,  				*flag &= ~JFS_ERR_REMOUNT_RO;  				*flag |= JFS_ERR_PANIC;  			} else { -				printk(KERN_ERR -				       "JFS: %s is an invalid error handler\n", +				pr_err("JFS: %s is an invalid error handler\n",  				       errors);  				goto cleanup;  			} @@ -307,36 +323,89 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,  		case Opt_usrquota:  		case Opt_grpquota:  		case Opt_quota: -			printk(KERN_ERR -			       "JFS: quota operations not supported\n"); +			pr_err("JFS: quota operations not supported\n");  			break;  #endif  		case Opt_uid:  		{  			char *uid = args[0].from; -			sbi->uid = simple_strtoul(uid, &uid, 0); +			uid_t val; +			int rc = kstrtouint(uid, 0, &val); + +			if (rc) +				goto cleanup; +			sbi->uid = make_kuid(current_user_ns(), val); +			if (!uid_valid(sbi->uid)) +				goto cleanup;  			break;  		} +  		case Opt_gid:  		{  			char *gid = args[0].from; -			sbi->gid = simple_strtoul(gid, &gid, 0); +			gid_t val; +			int rc = kstrtouint(gid, 0, &val); + +			if (rc) +				goto cleanup; +			sbi->gid = make_kgid(current_user_ns(), val); +			if (!gid_valid(sbi->gid)) +				goto cleanup;  			break;  		} +  		case Opt_umask:  		{  			char *umask = args[0].from; -			sbi->umask = simple_strtoul(umask, &umask, 8); +			int rc = kstrtouint(umask, 8, &sbi->umask); + +			if (rc) +				goto cleanup;  			if (sbi->umask & ~0777) { -				printk(KERN_ERR -				       "JFS: Invalid value of umask\n"); +				pr_err("JFS: Invalid value of umask\n");  				goto cleanup;  			}  			break;  		} + +		case Opt_discard: +		{ +			struct request_queue *q = bdev_get_queue(sb->s_bdev); +			/* if set to 1, even copying files will cause +			 * trimming :O +			 * -> user has more control over the online trimming +			 */ +			sbi->minblks_trim = 64; +			if (blk_queue_discard(q)) +				*flag |= JFS_DISCARD; +			else +				pr_err("JFS: discard option not supported on device\n"); +			break; +		} + +		case Opt_nodiscard: +			*flag &= ~JFS_DISCARD; +			break; + +		case Opt_discard_minblk: +		{ +			struct request_queue *q = bdev_get_queue(sb->s_bdev); +			char *minblks_trim = args[0].from; +			int rc; +			if (blk_queue_discard(q)) { +				*flag |= JFS_DISCARD; +				rc = kstrtouint(minblks_trim, 0, +						&sbi->minblks_trim); +				if (rc) +					goto cleanup; +			} else +				pr_err("JFS: discard option not supported on device\n"); +			break; +		} +  		default: -			printk("jfs: Unrecognized mount option \"%s\" " -					" or missing value\n", p); +			printk("jfs: Unrecognized mount option \"%s\" or missing value\n", +			       p);  			goto cleanup;  		}  	} @@ -361,14 +430,13 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data)  	int flag = JFS_SBI(sb)->flag;  	int ret; -	if (!parse_options(data, sb, &newLVSize, &flag)) { +	sync_filesystem(sb); +	if (!parse_options(data, sb, &newLVSize, &flag))  		return -EINVAL; -	}  	if (newLVSize) {  		if (sb->s_flags & MS_RDONLY) { -			printk(KERN_ERR -		  "JFS: resize requires volume to be mounted read-write\n"); +			pr_err("JFS: resize requires volume to be mounted read-write\n");  			return -EROFS;  		}  		rc = jfs_extendfs(sb, newLVSize, 0); @@ -394,9 +462,8 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data)  	}  	if ((!(sb->s_flags & MS_RDONLY)) && (*flags & MS_RDONLY)) {  		rc = dquot_suspend(sb, -1); -		if (rc < 0) { +		if (rc < 0)  			return rc; -		}  		rc = jfs_umount_rw(sb);  		JFS_SBI(sb)->flag = flag;  		return rc; @@ -429,13 +496,16 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)  	if (!new_valid_dev(sb->s_bdev->bd_dev))  		return -EOVERFLOW; -	sbi = kzalloc(sizeof (struct jfs_sb_info), GFP_KERNEL); +	sbi = kzalloc(sizeof(struct jfs_sb_info), GFP_KERNEL);  	if (!sbi)  		return -ENOMEM;  	sb->s_fs_info = sbi; +	sb->s_max_links = JFS_LINK_MAX;  	sbi->sb = sb; -	sbi->uid = sbi->gid = sbi->umask = -1; +	sbi->uid = INVALID_UID; +	sbi->gid = INVALID_GID; +	sbi->umask = -1;  	/* initialize the mount flag and determine the default error handler */  	flag = JFS_ERR_REMOUNT_RO; @@ -449,7 +519,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)  #endif  	if (newLVSize) { -		printk(KERN_ERR "resize option for remount only\n"); +		pr_err("resize option for remount only\n");  		goto out_kfree;  	} @@ -463,6 +533,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)  	 */  	sb->s_op = &jfs_super_operations;  	sb->s_export_op = &jfs_export_operations; +	sb->s_xattr = jfs_xattr_handlers;  #ifdef CONFIG_QUOTA  	sb->dq_op = &dquot_operations;  	sb->s_qcop = &dquot_quotactl_ops; @@ -477,7 +548,6 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)  		goto out_unload;  	}  	inode->i_ino = 0; -	inode->i_nlink = 1;  	inode->i_size = sb->s_bdev->bd_inode->i_size;  	inode->i_mapping->a_ops = &jfs_metapage_aops;  	insert_inode_hash(inode); @@ -487,9 +557,8 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)  	rc = jfs_mount(sb);  	if (rc) { -		if (!silent) { +		if (!silent)  			jfs_err("jfs_mount failed w/return code = %d", rc); -		}  		goto out_mount_failed;  	}  	if (sb->s_flags & MS_RDONLY) @@ -507,18 +576,18 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)  	sb->s_magic = JFS_SUPER_MAGIC; +	if (sbi->mntflag & JFS_OS2) +		sb->s_d_op = &jfs_ci_dentry_operations; +  	inode = jfs_iget(sb, ROOT_I);  	if (IS_ERR(inode)) {  		ret = PTR_ERR(inode);  		goto out_no_rw;  	} -	sb->s_root = d_alloc_root(inode); +	sb->s_root = d_make_root(inode);  	if (!sb->s_root)  		goto out_no_root; -	if (sbi->mntflag & JFS_OS2) -		sb->s_root->d_op = &jfs_ci_dentry_operations; -  	/* logical blocks are represented by 40 bits in pxd_t, etc. */  	sb->s_maxbytes = ((u64) sb->s_blocksize) << 40;  #if BITS_PER_LONG == 32 @@ -526,20 +595,19 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)  	 * Page cache is indexed by long.  	 * I would use MAX_LFS_FILESIZE, but it's only half as big  	 */ -	sb->s_maxbytes = min(((u64) PAGE_CACHE_SIZE << 32) - 1, (u64)sb->s_maxbytes); +	sb->s_maxbytes = min(((u64) PAGE_CACHE_SIZE << 32) - 1, +			     (u64)sb->s_maxbytes);  #endif  	sb->s_time_gran = 1;  	return 0;  out_no_root:  	jfs_err("jfs_read_super: get root dentry failed"); -	iput(inode);  out_no_rw:  	rc = jfs_umount(sb); -	if (rc) { +	if (rc)  		jfs_err("jfs_umount failed with return code %d", rc); -	}  out_mount_failed:  	filemap_write_and_wait(sbi->direct_inode->i_mapping);  	truncate_inode_pages(sbi->direct_inode->i_mapping, 0); @@ -558,11 +626,28 @@ static int jfs_freeze(struct super_block *sb)  {  	struct jfs_sb_info *sbi = JFS_SBI(sb);  	struct jfs_log *log = sbi->log; +	int rc = 0;  	if (!(sb->s_flags & MS_RDONLY)) {  		txQuiesce(sb); -		lmLogShutdown(log); -		updateSuper(sb, FM_CLEAN); +		rc = lmLogShutdown(log); +		if (rc) { +			jfs_error(sb, "lmLogShutdown failed\n"); + +			/* let operations fail rather than hang */ +			txResume(sb); + +			return rc; +		} +		rc = updateSuper(sb, FM_CLEAN); +		if (rc) { +			jfs_err("jfs_freeze: updateSuper failed\n"); +			/* +			 * Don't fail here. Everything succeeded except +			 * marking the superblock clean, so there's really +			 * no harm in leaving it frozen for now. +			 */ +		}  	}  	return 0;  } @@ -574,13 +659,18 @@ static int jfs_unfreeze(struct super_block *sb)  	int rc = 0;  	if (!(sb->s_flags & MS_RDONLY)) { -		updateSuper(sb, FM_MOUNT); -		if ((rc = lmLogInit(log))) -			jfs_err("jfs_unlock failed with return code %d", rc); -		else -			txResume(sb); +		rc = updateSuper(sb, FM_MOUNT); +		if (rc) { +			jfs_error(sb, "updateSuper failed\n"); +			goto out; +		} +		rc = lmLogInit(log); +		if (rc) +			jfs_error(sb, "lmLogInit failed\n"); +out: +		txResume(sb);  	} -	return 0; +	return rc;  }  static struct dentry *jfs_do_mount(struct file_system_type *fs_type, @@ -595,6 +685,11 @@ static int jfs_sync_fs(struct super_block *sb, int wait)  	/* log == NULL indicates read-only mount */  	if (log) { +		/* +		 * Write quota structures to quota file, sync_blockdev() will +		 * write them to disk later +		 */ +		dquot_writeback_dquots(sb, -1);  		jfs_flush_journal(log, wait);  		jfs_syncpt(log, 0);  	} @@ -602,18 +697,20 @@ static int jfs_sync_fs(struct super_block *sb, int wait)  	return 0;  } -static int jfs_show_options(struct seq_file *seq, struct vfsmount *vfs) +static int jfs_show_options(struct seq_file *seq, struct dentry *root)  { -	struct jfs_sb_info *sbi = JFS_SBI(vfs->mnt_sb); +	struct jfs_sb_info *sbi = JFS_SBI(root->d_sb); -	if (sbi->uid != -1) -		seq_printf(seq, ",uid=%d", sbi->uid); -	if (sbi->gid != -1) -		seq_printf(seq, ",gid=%d", sbi->gid); +	if (uid_valid(sbi->uid)) +		seq_printf(seq, ",uid=%d", from_kuid(&init_user_ns, sbi->uid)); +	if (gid_valid(sbi->gid)) +		seq_printf(seq, ",gid=%d", from_kgid(&init_user_ns, sbi->gid));  	if (sbi->umask != -1)  		seq_printf(seq, ",umask=%03o", sbi->umask);  	if (sbi->flag & JFS_NOINTEGRITY)  		seq_puts(seq, ",nointegrity"); +	if (sbi->flag & JFS_DISCARD) +		seq_printf(seq, ",discard=%u", sbi->minblks_trim);  	if (sbi->nls_tab)  		seq_printf(seq, ",iocharset=%s", sbi->nls_tab->charset);  	if (sbi->flag & JFS_ERR_CONTINUE) @@ -636,7 +733,7 @@ static int jfs_show_options(struct seq_file *seq, struct vfsmount *vfs)  /* Read data from quotafile - avoid pagecache and such because we cannot afford   * acquiring the locks... As quota files are never truncated and quota code - * itself serializes the operations (and noone else should touch the files) + * itself serializes the operations (and no one else should touch the files)   * we don't have to be afraid of races */  static ssize_t jfs_quota_read(struct super_block *sb, int type, char *data,  			      size_t len, loff_t off) @@ -773,6 +870,7 @@ static struct file_system_type jfs_fs_type = {  	.kill_sb	= kill_block_super,  	.fs_flags	= FS_REQUIRES_DEV,  }; +MODULE_ALIAS_FS("jfs");  static void init_once(void *foo)  { @@ -834,7 +932,8 @@ static int __init init_jfs_fs(void)  		commit_threads = MAX_COMMIT_THREADS;  	for (i = 0; i < commit_threads; i++) { -		jfsCommitThread[i] = kthread_run(jfs_lazycommit, NULL, "jfsCommit"); +		jfsCommitThread[i] = kthread_run(jfs_lazycommit, NULL, +						 "jfsCommit");  		if (IS_ERR(jfsCommitThread[i])) {  			rc = PTR_ERR(jfsCommitThread[i]);  			jfs_err("init_jfs_fs: fork failed w/rc = %d", rc); @@ -854,8 +953,14 @@ static int __init init_jfs_fs(void)  	jfs_proc_init();  #endif -	return register_filesystem(&jfs_fs_type); +	rc = register_filesystem(&jfs_fs_type); +	if (!rc) +		return 0; +#ifdef PROC_FS_JFS +	jfs_proc_clean(); +#endif +	kthread_stop(jfsSyncThread);  kill_committask:  	for (i = 0; i < commit_threads; i++)  		kthread_stop(jfsCommitThread[i]); @@ -886,6 +991,12 @@ static void __exit exit_jfs_fs(void)  	jfs_proc_clean();  #endif  	unregister_filesystem(&jfs_fs_type); + +	/* +	 * Make sure all delayed rcu free inodes are flushed before we +	 * destroy cache. +	 */ +	rcu_barrier();  	kmem_cache_destroy(jfs_inode_cachep);  }  | 
