xref: /openbmc/linux/fs/jfs/super.c (revision 42954c37)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *   Copyright (C) International Business Machines Corp., 2000-2004
41da177e4SLinus Torvalds  *   Portions Copyright (C) Christoph Hellwig, 2001-2002
51da177e4SLinus Torvalds  */
61da177e4SLinus Torvalds 
71da177e4SLinus Torvalds #include <linux/fs.h>
81da177e4SLinus Torvalds #include <linux/module.h>
91da177e4SLinus Torvalds #include <linux/parser.h>
101da177e4SLinus Torvalds #include <linux/completion.h>
111da177e4SLinus Torvalds #include <linux/vfs.h>
1274abb989SJan Kara #include <linux/quotaops.h>
138fc2751bSMark Bellon #include <linux/mount.h>
141da177e4SLinus Torvalds #include <linux/moduleparam.h>
1591dbb4deSChristoph Hellwig #include <linux/kthread.h>
169a59f452SChristoph Hellwig #include <linux/posix_acl.h>
17115ff50bSDave Kleikamp #include <linux/buffer_head.h>
18a5694255SChristoph Hellwig #include <linux/exportfs.h>
19b5c816a4SColy Li #include <linux/crc32.h>
205a0e3ad6STejun Heo #include <linux/slab.h>
217c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
228fc2751bSMark Bellon #include <linux/seq_file.h>
23b40c2e66STino Reichardt #include <linux/blkdev.h>
241da177e4SLinus Torvalds 
251da177e4SLinus Torvalds #include "jfs_incore.h"
261da177e4SLinus Torvalds #include "jfs_filsys.h"
271868f4aaSDave Kleikamp #include "jfs_inode.h"
281da177e4SLinus Torvalds #include "jfs_metapage.h"
291da177e4SLinus Torvalds #include "jfs_superblock.h"
301da177e4SLinus Torvalds #include "jfs_dmap.h"
311da177e4SLinus Torvalds #include "jfs_imap.h"
321da177e4SLinus Torvalds #include "jfs_acl.h"
331da177e4SLinus Torvalds #include "jfs_debug.h"
342cc6a5a0SChristoph Hellwig #include "jfs_xattr.h"
3512fd086dSJan Kara #include "jfs_dinode.h"
361da177e4SLinus Torvalds 
371da177e4SLinus Torvalds MODULE_DESCRIPTION("The Journaled Filesystem (JFS)");
381da177e4SLinus Torvalds MODULE_AUTHOR("Steve Best/Dave Kleikamp/Barry Arndt, IBM");
391da177e4SLinus Torvalds MODULE_LICENSE("GPL");
401da177e4SLinus Torvalds 
41e18b890bSChristoph Lameter static struct kmem_cache *jfs_inode_cachep;
421da177e4SLinus Torvalds 
43ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations jfs_super_operations;
4439655164SChristoph Hellwig static const struct export_operations jfs_export_operations;
451da177e4SLinus Torvalds static struct file_system_type jfs_fs_type;
461da177e4SLinus Torvalds 
471da177e4SLinus Torvalds #define MAX_COMMIT_THREADS 64
48789602e9SFabian Frederick static int commit_threads;
491da177e4SLinus Torvalds module_param(commit_threads, int, 0);
501da177e4SLinus Torvalds MODULE_PARM_DESC(commit_threads, "Number of commit threads");
511da177e4SLinus Torvalds 
5291dbb4deSChristoph Hellwig static struct task_struct *jfsCommitThread[MAX_COMMIT_THREADS];
5391dbb4deSChristoph Hellwig struct task_struct *jfsIOthread;
5491dbb4deSChristoph Hellwig struct task_struct *jfsSyncThread;
551da177e4SLinus Torvalds 
561da177e4SLinus Torvalds #ifdef CONFIG_JFS_DEBUG
571da177e4SLinus Torvalds int jfsloglevel = JFS_LOGLEVEL_WARN;
581da177e4SLinus Torvalds module_param(jfsloglevel, int, 0644);
591da177e4SLinus Torvalds MODULE_PARM_DESC(jfsloglevel, "Specify JFS loglevel (0, 1 or 2)");
601da177e4SLinus Torvalds #endif
611da177e4SLinus Torvalds 
jfs_handle_error(struct super_block * sb)621da177e4SLinus Torvalds static void jfs_handle_error(struct super_block *sb)
631da177e4SLinus Torvalds {
641da177e4SLinus Torvalds 	struct jfs_sb_info *sbi = JFS_SBI(sb);
651da177e4SLinus Torvalds 
66bc98a42cSDavid Howells 	if (sb_rdonly(sb))
671da177e4SLinus Torvalds 		return;
681da177e4SLinus Torvalds 
691da177e4SLinus Torvalds 	updateSuper(sb, FM_DIRTY);
701da177e4SLinus Torvalds 
711da177e4SLinus Torvalds 	if (sbi->flag & JFS_ERR_PANIC)
721da177e4SLinus Torvalds 		panic("JFS (device %s): panic forced after error\n",
731da177e4SLinus Torvalds 			sb->s_id);
741da177e4SLinus Torvalds 	else if (sbi->flag & JFS_ERR_REMOUNT_RO) {
75b18db6deSJoe Perches 		jfs_err("ERROR: (device %s): remounting filesystem as read-only",
761da177e4SLinus Torvalds 			sb->s_id);
771751e8a6SLinus Torvalds 		sb->s_flags |= SB_RDONLY;
781da177e4SLinus Torvalds 	}
791da177e4SLinus Torvalds 
801da177e4SLinus Torvalds 	/* nothing is done for continue beyond marking the superblock dirty */
811da177e4SLinus Torvalds }
821da177e4SLinus Torvalds 
jfs_error(struct super_block * sb,const char * fmt,...)83eb8630d7SJoe Perches void jfs_error(struct super_block *sb, const char *fmt, ...)
841da177e4SLinus Torvalds {
85eb8630d7SJoe Perches 	struct va_format vaf;
861da177e4SLinus Torvalds 	va_list args;
871da177e4SLinus Torvalds 
88eb8630d7SJoe Perches 	va_start(args, fmt);
891da177e4SLinus Torvalds 
90eb8630d7SJoe Perches 	vaf.fmt = fmt;
91eb8630d7SJoe Perches 	vaf.va = &args;
92eb8630d7SJoe Perches 
937d2ac456SScott Wood 	pr_err("ERROR: (device %s): %ps: %pV\n",
94eb8630d7SJoe Perches 	       sb->s_id, __builtin_return_address(0), &vaf);
95eb8630d7SJoe Perches 
96eb8630d7SJoe Perches 	va_end(args);
971da177e4SLinus Torvalds 
981da177e4SLinus Torvalds 	jfs_handle_error(sb);
991da177e4SLinus Torvalds }
1001da177e4SLinus Torvalds 
jfs_alloc_inode(struct super_block * sb)1011da177e4SLinus Torvalds static struct inode *jfs_alloc_inode(struct super_block *sb)
1021da177e4SLinus Torvalds {
1031da177e4SLinus Torvalds 	struct jfs_inode_info *jfs_inode;
1041da177e4SLinus Torvalds 
105fd60b288SMuchun Song 	jfs_inode = alloc_inode_sb(sb, jfs_inode_cachep, GFP_NOFS);
1061da177e4SLinus Torvalds 	if (!jfs_inode)
1071da177e4SLinus Torvalds 		return NULL;
108507e1fa6SJan Kara #ifdef CONFIG_QUOTA
109507e1fa6SJan Kara 	memset(&jfs_inode->i_dquot, 0, sizeof(jfs_inode->i_dquot));
110507e1fa6SJan Kara #endif
1111da177e4SLinus Torvalds 	return &jfs_inode->vfs_inode;
1121da177e4SLinus Torvalds }
1131da177e4SLinus Torvalds 
jfs_free_inode(struct inode * inode)114b3b4a6e3SAl Viro static void jfs_free_inode(struct inode *inode)
115fa0d7e3dSNick Piggin {
116b3b4a6e3SAl Viro 	kmem_cache_free(jfs_inode_cachep, JFS_IP(inode));
1171da177e4SLinus Torvalds }
1181da177e4SLinus Torvalds 
jfs_statfs(struct dentry * dentry,struct kstatfs * buf)119726c3342SDavid Howells static int jfs_statfs(struct dentry *dentry, struct kstatfs *buf)
1201da177e4SLinus Torvalds {
121726c3342SDavid Howells 	struct jfs_sb_info *sbi = JFS_SBI(dentry->d_sb);
1221da177e4SLinus Torvalds 	s64 maxinodes;
1231da177e4SLinus Torvalds 	struct inomap *imap = JFS_IP(sbi->ipimap)->i_imap;
1241da177e4SLinus Torvalds 
1251da177e4SLinus Torvalds 	jfs_info("In jfs_statfs");
1261da177e4SLinus Torvalds 	buf->f_type = JFS_SUPER_MAGIC;
1271da177e4SLinus Torvalds 	buf->f_bsize = sbi->bsize;
1281da177e4SLinus Torvalds 	buf->f_blocks = sbi->bmap->db_mapsize;
1291da177e4SLinus Torvalds 	buf->f_bfree = sbi->bmap->db_nfree;
1301da177e4SLinus Torvalds 	buf->f_bavail = sbi->bmap->db_nfree;
1311da177e4SLinus Torvalds 	/*
1321da177e4SLinus Torvalds 	 * If we really return the number of allocated & free inodes, some
1331da177e4SLinus Torvalds 	 * applications will fail because they won't see enough free inodes.
1344de80273SPhilippe De Muyter 	 * We'll try to calculate some guess as to how many inodes we can
1351da177e4SLinus Torvalds 	 * really allocate
1361da177e4SLinus Torvalds 	 *
1371da177e4SLinus Torvalds 	 * buf->f_files = atomic_read(&imap->im_numinos);
1381da177e4SLinus Torvalds 	 * buf->f_ffree = atomic_read(&imap->im_numfree);
1391da177e4SLinus Torvalds 	 */
1401da177e4SLinus Torvalds 	maxinodes = min((s64) atomic_read(&imap->im_numinos) +
1411da177e4SLinus Torvalds 			((sbi->bmap->db_nfree >> imap->im_l2nbperiext)
1421da177e4SLinus Torvalds 			 << L2INOSPEREXT), (s64) 0xffffffffLL);
1431da177e4SLinus Torvalds 	buf->f_files = maxinodes;
1441da177e4SLinus Torvalds 	buf->f_ffree = maxinodes - (atomic_read(&imap->im_numinos) -
1451da177e4SLinus Torvalds 				    atomic_read(&imap->im_numfree));
1462e3bc612SAndy Shevchenko 	buf->f_fsid.val[0] = crc32_le(0, (char *)&sbi->uuid,
1472e3bc612SAndy Shevchenko 				      sizeof(sbi->uuid)/2);
1482e3bc612SAndy Shevchenko 	buf->f_fsid.val[1] = crc32_le(0,
1492e3bc612SAndy Shevchenko 				      (char *)&sbi->uuid + sizeof(sbi->uuid)/2,
150b5c816a4SColy Li 				      sizeof(sbi->uuid)/2);
1511da177e4SLinus Torvalds 
1521da177e4SLinus Torvalds 	buf->f_namelen = JFS_NAME_MAX;
1531da177e4SLinus Torvalds 	return 0;
1541da177e4SLinus Torvalds }
1551da177e4SLinus Torvalds 
15612fd086dSJan Kara #ifdef CONFIG_QUOTA
15712fd086dSJan Kara static int jfs_quota_off(struct super_block *sb, int type);
15812fd086dSJan Kara static int jfs_quota_on(struct super_block *sb, int type, int format_id,
15912fd086dSJan Kara 			const struct path *path);
16012fd086dSJan Kara 
jfs_quota_off_umount(struct super_block * sb)16112fd086dSJan Kara static void jfs_quota_off_umount(struct super_block *sb)
16212fd086dSJan Kara {
16312fd086dSJan Kara 	int type;
16412fd086dSJan Kara 
16512fd086dSJan Kara 	for (type = 0; type < MAXQUOTAS; type++)
16612fd086dSJan Kara 		jfs_quota_off(sb, type);
16712fd086dSJan Kara }
16812fd086dSJan Kara 
16912fd086dSJan Kara static const struct quotactl_ops jfs_quotactl_ops = {
17012fd086dSJan Kara 	.quota_on	= jfs_quota_on,
17112fd086dSJan Kara 	.quota_off	= jfs_quota_off,
17212fd086dSJan Kara 	.quota_sync	= dquot_quota_sync,
17312fd086dSJan Kara 	.get_state	= dquot_get_state,
17412fd086dSJan Kara 	.set_info	= dquot_set_dqinfo,
17512fd086dSJan Kara 	.get_dqblk	= dquot_get_dqblk,
17612fd086dSJan Kara 	.set_dqblk	= dquot_set_dqblk,
17712fd086dSJan Kara 	.get_nextdqblk	= dquot_get_next_dqblk,
17812fd086dSJan Kara };
17912fd086dSJan Kara #else
jfs_quota_off_umount(struct super_block * sb)18012fd086dSJan Kara static inline void jfs_quota_off_umount(struct super_block *sb)
18112fd086dSJan Kara {
18212fd086dSJan Kara }
18312fd086dSJan Kara #endif
18412fd086dSJan Kara 
jfs_put_super(struct super_block * sb)1851da177e4SLinus Torvalds static void jfs_put_super(struct super_block *sb)
1861da177e4SLinus Torvalds {
1871da177e4SLinus Torvalds 	struct jfs_sb_info *sbi = JFS_SBI(sb);
1881da177e4SLinus Torvalds 	int rc;
1891da177e4SLinus Torvalds 
1901da177e4SLinus Torvalds 	jfs_info("In jfs_put_super");
1916cfd0148SChristoph Hellwig 
19212fd086dSJan Kara 	jfs_quota_off_umount(sb);
193e0ccfd95SChristoph Hellwig 
1941da177e4SLinus Torvalds 	rc = jfs_umount(sb);
1951da177e4SLinus Torvalds 	if (rc)
1961da177e4SLinus Torvalds 		jfs_err("jfs_umount failed with return code %d", rc);
1976d729e44SThomas Gleixner 
1981da177e4SLinus Torvalds 	unload_nls(sbi->nls_tab);
1991da177e4SLinus Torvalds 
2007fab479bSDave Kleikamp 	truncate_inode_pages(sbi->direct_inode->i_mapping, 0);
2017fab479bSDave Kleikamp 	iput(sbi->direct_inode);
2027fab479bSDave Kleikamp 
2031da177e4SLinus Torvalds 	kfree(sbi);
2041da177e4SLinus Torvalds }
2051da177e4SLinus Torvalds 
2061da177e4SLinus Torvalds enum {
2071da177e4SLinus Torvalds 	Opt_integrity, Opt_nointegrity, Opt_iocharset, Opt_resize,
2088fc2751bSMark Bellon 	Opt_resize_nosize, Opt_errors, Opt_ignore, Opt_err, Opt_quota,
209b40c2e66STino Reichardt 	Opt_usrquota, Opt_grpquota, Opt_uid, Opt_gid, Opt_umask,
210b40c2e66STino Reichardt 	Opt_discard, Opt_nodiscard, Opt_discard_minblk
2111da177e4SLinus Torvalds };
2121da177e4SLinus Torvalds 
213a447c093SSteven Whitehouse static const match_table_t tokens = {
2141da177e4SLinus Torvalds 	{Opt_integrity, "integrity"},
2151da177e4SLinus Torvalds 	{Opt_nointegrity, "nointegrity"},
2161da177e4SLinus Torvalds 	{Opt_iocharset, "iocharset=%s"},
2171da177e4SLinus Torvalds 	{Opt_resize, "resize=%u"},
2181da177e4SLinus Torvalds 	{Opt_resize_nosize, "resize"},
2191da177e4SLinus Torvalds 	{Opt_errors, "errors=%s"},
2201da177e4SLinus Torvalds 	{Opt_ignore, "noquota"},
22102645bcdSChengguang Xu 	{Opt_quota, "quota"},
2228fc2751bSMark Bellon 	{Opt_usrquota, "usrquota"},
2238fc2751bSMark Bellon 	{Opt_grpquota, "grpquota"},
22469eb66d7SDave Kleikamp 	{Opt_uid, "uid=%u"},
22569eb66d7SDave Kleikamp 	{Opt_gid, "gid=%u"},
22669eb66d7SDave Kleikamp 	{Opt_umask, "umask=%u"},
227b40c2e66STino Reichardt 	{Opt_discard, "discard"},
228b40c2e66STino Reichardt 	{Opt_nodiscard, "nodiscard"},
229b40c2e66STino Reichardt 	{Opt_discard_minblk, "discard=%u"},
2301da177e4SLinus Torvalds 	{Opt_err, NULL}
2311da177e4SLinus Torvalds };
2321da177e4SLinus Torvalds 
parse_options(char * options,struct super_block * sb,s64 * newLVSize,int * flag)2331da177e4SLinus Torvalds static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,
2341da177e4SLinus Torvalds 			 int *flag)
2351da177e4SLinus Torvalds {
2361da177e4SLinus Torvalds 	void *nls_map = (void *)-1;	/* -1: no change;  NULL: none */
2371da177e4SLinus Torvalds 	char *p;
2381da177e4SLinus Torvalds 	struct jfs_sb_info *sbi = JFS_SBI(sb);
2391da177e4SLinus Torvalds 
2401da177e4SLinus Torvalds 	*newLVSize = 0;
2411da177e4SLinus Torvalds 
2421da177e4SLinus Torvalds 	if (!options)
2431da177e4SLinus Torvalds 		return 1;
2441da177e4SLinus Torvalds 
2451da177e4SLinus Torvalds 	while ((p = strsep(&options, ",")) != NULL) {
2461da177e4SLinus Torvalds 		substring_t args[MAX_OPT_ARGS];
2471da177e4SLinus Torvalds 		int token;
2481da177e4SLinus Torvalds 		if (!*p)
2491da177e4SLinus Torvalds 			continue;
2501da177e4SLinus Torvalds 
2511da177e4SLinus Torvalds 		token = match_token(p, tokens, args);
2521da177e4SLinus Torvalds 		switch (token) {
2531da177e4SLinus Torvalds 		case Opt_integrity:
2541da177e4SLinus Torvalds 			*flag &= ~JFS_NOINTEGRITY;
2551da177e4SLinus Torvalds 			break;
2561da177e4SLinus Torvalds 		case Opt_nointegrity:
2571da177e4SLinus Torvalds 			*flag |= JFS_NOINTEGRITY;
2581da177e4SLinus Torvalds 			break;
2591da177e4SLinus Torvalds 		case Opt_ignore:
2601da177e4SLinus Torvalds 			/* Silently ignore the quota options */
2611da177e4SLinus Torvalds 			/* Don't do anything ;-) */
2621da177e4SLinus Torvalds 			break;
2631da177e4SLinus Torvalds 		case Opt_iocharset:
2641da177e4SLinus Torvalds 			if (nls_map && nls_map != (void *) -1)
2651da177e4SLinus Torvalds 				unload_nls(nls_map);
2661da177e4SLinus Torvalds 			if (!strcmp(args[0].from, "none"))
2671da177e4SLinus Torvalds 				nls_map = NULL;
2681da177e4SLinus Torvalds 			else {
2691da177e4SLinus Torvalds 				nls_map = load_nls(args[0].from);
2701da177e4SLinus Torvalds 				if (!nls_map) {
271b40c2e66STino Reichardt 					pr_err("JFS: charset not found\n");
2721da177e4SLinus Torvalds 					goto cleanup;
2731da177e4SLinus Torvalds 				}
2741da177e4SLinus Torvalds 			}
2751da177e4SLinus Torvalds 			break;
2761da177e4SLinus Torvalds 		case Opt_resize:
2771da177e4SLinus Torvalds 		{
2781da177e4SLinus Torvalds 			char *resize = args[0].from;
279bb5e50aaSFabian Frederick 			int rc = kstrtoll(resize, 0, newLVSize);
280bb5e50aaSFabian Frederick 
281bb5e50aaSFabian Frederick 			if (rc)
282bb5e50aaSFabian Frederick 				goto cleanup;
2831da177e4SLinus Torvalds 			break;
2841da177e4SLinus Torvalds 		}
2851da177e4SLinus Torvalds 		case Opt_resize_nosize:
2861da177e4SLinus Torvalds 		{
287dd0c0bdfSChristoph Hellwig 			*newLVSize = sb_bdev_nr_blocks(sb);
2881da177e4SLinus Torvalds 			if (*newLVSize == 0)
289b40c2e66STino Reichardt 				pr_err("JFS: Cannot determine volume size\n");
2901da177e4SLinus Torvalds 			break;
2911da177e4SLinus Torvalds 		}
2921da177e4SLinus Torvalds 		case Opt_errors:
2931da177e4SLinus Torvalds 		{
2941da177e4SLinus Torvalds 			char *errors = args[0].from;
2951da177e4SLinus Torvalds 			if (!errors || !*errors)
2961da177e4SLinus Torvalds 				goto cleanup;
2971da177e4SLinus Torvalds 			if (!strcmp(errors, "continue")) {
2981da177e4SLinus Torvalds 				*flag &= ~JFS_ERR_REMOUNT_RO;
2991da177e4SLinus Torvalds 				*flag &= ~JFS_ERR_PANIC;
3001da177e4SLinus Torvalds 				*flag |= JFS_ERR_CONTINUE;
3011da177e4SLinus Torvalds 			} else if (!strcmp(errors, "remount-ro")) {
3021da177e4SLinus Torvalds 				*flag &= ~JFS_ERR_CONTINUE;
3031da177e4SLinus Torvalds 				*flag &= ~JFS_ERR_PANIC;
3041da177e4SLinus Torvalds 				*flag |= JFS_ERR_REMOUNT_RO;
3051da177e4SLinus Torvalds 			} else if (!strcmp(errors, "panic")) {
3061da177e4SLinus Torvalds 				*flag &= ~JFS_ERR_CONTINUE;
3071da177e4SLinus Torvalds 				*flag &= ~JFS_ERR_REMOUNT_RO;
3081da177e4SLinus Torvalds 				*flag |= JFS_ERR_PANIC;
3091da177e4SLinus Torvalds 			} else {
310b40c2e66STino Reichardt 				pr_err("JFS: %s is an invalid error handler\n",
3111da177e4SLinus Torvalds 				       errors);
3121da177e4SLinus Torvalds 				goto cleanup;
3131da177e4SLinus Torvalds 			}
3141da177e4SLinus Torvalds 			break;
3151da177e4SLinus Torvalds 		}
3168fc2751bSMark Bellon 
317115ff50bSDave Kleikamp #ifdef CONFIG_QUOTA
3188fc2751bSMark Bellon 		case Opt_quota:
3198fc2751bSMark Bellon 		case Opt_usrquota:
3208fc2751bSMark Bellon 			*flag |= JFS_USRQUOTA;
3218fc2751bSMark Bellon 			break;
3228fc2751bSMark Bellon 		case Opt_grpquota:
3238fc2751bSMark Bellon 			*flag |= JFS_GRPQUOTA;
3248fc2751bSMark Bellon 			break;
3258fc2751bSMark Bellon #else
3268fc2751bSMark Bellon 		case Opt_usrquota:
3278fc2751bSMark Bellon 		case Opt_grpquota:
3288fc2751bSMark Bellon 		case Opt_quota:
329b40c2e66STino Reichardt 			pr_err("JFS: quota operations not supported\n");
3308fc2751bSMark Bellon 			break;
3318fc2751bSMark Bellon #endif
33269eb66d7SDave Kleikamp 		case Opt_uid:
33369eb66d7SDave Kleikamp 		{
33469eb66d7SDave Kleikamp 			char *uid = args[0].from;
335bb5e50aaSFabian Frederick 			uid_t val;
336bb5e50aaSFabian Frederick 			int rc = kstrtouint(uid, 0, &val);
337bb5e50aaSFabian Frederick 
338bb5e50aaSFabian Frederick 			if (rc)
339bb5e50aaSFabian Frederick 				goto cleanup;
340c18cdc1aSEric W. Biederman 			sbi->uid = make_kuid(current_user_ns(), val);
341c18cdc1aSEric W. Biederman 			if (!uid_valid(sbi->uid))
342c18cdc1aSEric W. Biederman 				goto cleanup;
34369eb66d7SDave Kleikamp 			break;
34469eb66d7SDave Kleikamp 		}
345b40c2e66STino Reichardt 
34669eb66d7SDave Kleikamp 		case Opt_gid:
34769eb66d7SDave Kleikamp 		{
34869eb66d7SDave Kleikamp 			char *gid = args[0].from;
349bb5e50aaSFabian Frederick 			gid_t val;
350bb5e50aaSFabian Frederick 			int rc = kstrtouint(gid, 0, &val);
351bb5e50aaSFabian Frederick 
352bb5e50aaSFabian Frederick 			if (rc)
353bb5e50aaSFabian Frederick 				goto cleanup;
354c18cdc1aSEric W. Biederman 			sbi->gid = make_kgid(current_user_ns(), val);
355c18cdc1aSEric W. Biederman 			if (!gid_valid(sbi->gid))
356c18cdc1aSEric W. Biederman 				goto cleanup;
35769eb66d7SDave Kleikamp 			break;
35869eb66d7SDave Kleikamp 		}
359b40c2e66STino Reichardt 
36069eb66d7SDave Kleikamp 		case Opt_umask:
36169eb66d7SDave Kleikamp 		{
36269eb66d7SDave Kleikamp 			char *umask = args[0].from;
363bb5e50aaSFabian Frederick 			int rc = kstrtouint(umask, 8, &sbi->umask);
364bb5e50aaSFabian Frederick 
365bb5e50aaSFabian Frederick 			if (rc)
366bb5e50aaSFabian Frederick 				goto cleanup;
36769eb66d7SDave Kleikamp 			if (sbi->umask & ~0777) {
368b40c2e66STino Reichardt 				pr_err("JFS: Invalid value of umask\n");
36969eb66d7SDave Kleikamp 				goto cleanup;
37069eb66d7SDave Kleikamp 			}
37169eb66d7SDave Kleikamp 			break;
37269eb66d7SDave Kleikamp 		}
373b40c2e66STino Reichardt 
374b40c2e66STino Reichardt 		case Opt_discard:
375b40c2e66STino Reichardt 			/* if set to 1, even copying files will cause
376b40c2e66STino Reichardt 			 * trimming :O
377b40c2e66STino Reichardt 			 * -> user has more control over the online trimming
378b40c2e66STino Reichardt 			 */
379b40c2e66STino Reichardt 			sbi->minblks_trim = 64;
38070200574SChristoph Hellwig 			if (bdev_max_discard_sectors(sb->s_bdev))
381b40c2e66STino Reichardt 				*flag |= JFS_DISCARD;
382789602e9SFabian Frederick 			else
383789602e9SFabian Frederick 				pr_err("JFS: discard option not supported on device\n");
384b40c2e66STino Reichardt 			break;
385b40c2e66STino Reichardt 
386b40c2e66STino Reichardt 		case Opt_nodiscard:
387b40c2e66STino Reichardt 			*flag &= ~JFS_DISCARD;
388b40c2e66STino Reichardt 			break;
389b40c2e66STino Reichardt 
390b40c2e66STino Reichardt 		case Opt_discard_minblk:
391b40c2e66STino Reichardt 		{
392b40c2e66STino Reichardt 			char *minblks_trim = args[0].from;
393bb5e50aaSFabian Frederick 			int rc;
39470200574SChristoph Hellwig 			if (bdev_max_discard_sectors(sb->s_bdev)) {
395b40c2e66STino Reichardt 				*flag |= JFS_DISCARD;
396bb5e50aaSFabian Frederick 				rc = kstrtouint(minblks_trim, 0,
397bb5e50aaSFabian Frederick 						&sbi->minblks_trim);
398bb5e50aaSFabian Frederick 				if (rc)
399bb5e50aaSFabian Frederick 					goto cleanup;
400bb5e50aaSFabian Frederick 			} else
401789602e9SFabian Frederick 				pr_err("JFS: discard option not supported on device\n");
402b40c2e66STino Reichardt 			break;
403b40c2e66STino Reichardt 		}
404b40c2e66STino Reichardt 
4051da177e4SLinus Torvalds 		default:
406789602e9SFabian Frederick 			printk("jfs: Unrecognized mount option \"%s\" or missing value\n",
407789602e9SFabian Frederick 			       p);
4081da177e4SLinus Torvalds 			goto cleanup;
4091da177e4SLinus Torvalds 		}
4101da177e4SLinus Torvalds 	}
4111da177e4SLinus Torvalds 
4121da177e4SLinus Torvalds 	if (nls_map != (void *) -1) {
4131da177e4SLinus Torvalds 		/* Discard old (if remount) */
4141da177e4SLinus Torvalds 		unload_nls(sbi->nls_tab);
4151da177e4SLinus Torvalds 		sbi->nls_tab = nls_map;
4161da177e4SLinus Torvalds 	}
4171da177e4SLinus Torvalds 	return 1;
4181da177e4SLinus Torvalds 
4191da177e4SLinus Torvalds cleanup:
4201da177e4SLinus Torvalds 	if (nls_map && nls_map != (void *) -1)
4211da177e4SLinus Torvalds 		unload_nls(nls_map);
4221da177e4SLinus Torvalds 	return 0;
4231da177e4SLinus Torvalds }
4241da177e4SLinus Torvalds 
jfs_remount(struct super_block * sb,int * flags,char * data)4251da177e4SLinus Torvalds static int jfs_remount(struct super_block *sb, int *flags, char *data)
4261da177e4SLinus Torvalds {
4271da177e4SLinus Torvalds 	s64 newLVSize = 0;
4281da177e4SLinus Torvalds 	int rc = 0;
4291da177e4SLinus Torvalds 	int flag = JFS_SBI(sb)->flag;
430337eb00aSAlessio Igor Bogani 	int ret;
4311da177e4SLinus Torvalds 
43202b9984dSTheodore Ts'o 	sync_filesystem(sb);
433789602e9SFabian Frederick 	if (!parse_options(data, sb, &newLVSize, &flag))
4341da177e4SLinus Torvalds 		return -EINVAL;
43522b26db6SJan Blunck 
4361da177e4SLinus Torvalds 	if (newLVSize) {
437bc98a42cSDavid Howells 		if (sb_rdonly(sb)) {
438789602e9SFabian Frederick 			pr_err("JFS: resize requires volume to be mounted read-write\n");
4391da177e4SLinus Torvalds 			return -EROFS;
4401da177e4SLinus Torvalds 		}
4411da177e4SLinus Torvalds 		rc = jfs_extendfs(sb, newLVSize, 0);
44222b26db6SJan Blunck 		if (rc)
4431da177e4SLinus Torvalds 			return rc;
4441da177e4SLinus Torvalds 	}
4451da177e4SLinus Torvalds 
4461751e8a6SLinus Torvalds 	if (sb_rdonly(sb) && !(*flags & SB_RDONLY)) {
4477fab479bSDave Kleikamp 		/*
4487fab479bSDave Kleikamp 		 * Invalidate any previously read metadata.  fsck may have
4497fab479bSDave Kleikamp 		 * changed the on-disk data since we mounted r/o
4507fab479bSDave Kleikamp 		 */
4517fab479bSDave Kleikamp 		truncate_inode_pages(JFS_SBI(sb)->direct_inode->i_mapping, 0);
4527fab479bSDave Kleikamp 
4531da177e4SLinus Torvalds 		JFS_SBI(sb)->flag = flag;
454337eb00aSAlessio Igor Bogani 		ret = jfs_mount_rw(sb, 1);
455c79d967dSChristoph Hellwig 
456c79d967dSChristoph Hellwig 		/* mark the fs r/w for quota activity */
4571751e8a6SLinus Torvalds 		sb->s_flags &= ~SB_RDONLY;
458c79d967dSChristoph Hellwig 
4590f0dd62fSChristoph Hellwig 		dquot_resume(sb, -1);
460337eb00aSAlessio Igor Bogani 		return ret;
4611da177e4SLinus Torvalds 	}
4621751e8a6SLinus Torvalds 	if (!sb_rdonly(sb) && (*flags & SB_RDONLY)) {
4630f0dd62fSChristoph Hellwig 		rc = dquot_suspend(sb, -1);
464789602e9SFabian Frederick 		if (rc < 0)
4650f0dd62fSChristoph Hellwig 			return rc;
4661da177e4SLinus Torvalds 		rc = jfs_umount_rw(sb);
4671da177e4SLinus Torvalds 		JFS_SBI(sb)->flag = flag;
4681da177e4SLinus Torvalds 		return rc;
4691da177e4SLinus Torvalds 	}
4701da177e4SLinus Torvalds 	if ((JFS_SBI(sb)->flag & JFS_NOINTEGRITY) != (flag & JFS_NOINTEGRITY))
471bc98a42cSDavid Howells 		if (!sb_rdonly(sb)) {
4721da177e4SLinus Torvalds 			rc = jfs_umount_rw(sb);
47322b26db6SJan Blunck 			if (rc)
4741da177e4SLinus Torvalds 				return rc;
47522b26db6SJan Blunck 
4761da177e4SLinus Torvalds 			JFS_SBI(sb)->flag = flag;
477337eb00aSAlessio Igor Bogani 			ret = jfs_mount_rw(sb, 1);
478337eb00aSAlessio Igor Bogani 			return ret;
4791da177e4SLinus Torvalds 		}
4801da177e4SLinus Torvalds 	JFS_SBI(sb)->flag = flag;
4811da177e4SLinus Torvalds 
4821da177e4SLinus Torvalds 	return 0;
4831da177e4SLinus Torvalds }
4841da177e4SLinus Torvalds 
jfs_fill_super(struct super_block * sb,void * data,int silent)4851da177e4SLinus Torvalds static int jfs_fill_super(struct super_block *sb, void *data, int silent)
4861da177e4SLinus Torvalds {
4871da177e4SLinus Torvalds 	struct jfs_sb_info *sbi;
4881da177e4SLinus Torvalds 	struct inode *inode;
4891da177e4SLinus Torvalds 	int rc;
4901da177e4SLinus Torvalds 	s64 newLVSize = 0;
491eab1df71SDavid Howells 	int flag, ret = -EINVAL;
4921da177e4SLinus Torvalds 
4931da177e4SLinus Torvalds 	jfs_info("In jfs_read_super: s_flags=0x%lx", sb->s_flags);
4941da177e4SLinus Torvalds 
4955b3030e3SEric Sesterhenn 	sbi = kzalloc(sizeof(struct jfs_sb_info), GFP_KERNEL);
49622b26db6SJan Blunck 	if (!sbi)
497087387f9SAkinobu Mita 		return -ENOMEM;
49822b26db6SJan Blunck 
4991da177e4SLinus Torvalds 	sb->s_fs_info = sbi;
5008de52778SAl Viro 	sb->s_max_links = JFS_LINK_MAX;
50122b13969SDeepa Dinamani 	sb->s_time_min = 0;
50222b13969SDeepa Dinamani 	sb->s_time_max = U32_MAX;
5031da177e4SLinus Torvalds 	sbi->sb = sb;
504c18cdc1aSEric W. Biederman 	sbi->uid = INVALID_UID;
505c18cdc1aSEric W. Biederman 	sbi->gid = INVALID_GID;
506c18cdc1aSEric W. Biederman 	sbi->umask = -1;
5071da177e4SLinus Torvalds 
5081da177e4SLinus Torvalds 	/* initialize the mount flag and determine the default error handler */
5091da177e4SLinus Torvalds 	flag = JFS_ERR_REMOUNT_RO;
5101da177e4SLinus Torvalds 
511684bdc7fSJan Blunck 	if (!parse_options((char *) data, sb, &newLVSize, &flag))
512684bdc7fSJan Blunck 		goto out_kfree;
5131da177e4SLinus Torvalds 	sbi->flag = flag;
5141da177e4SLinus Torvalds 
5151da177e4SLinus Torvalds #ifdef CONFIG_JFS_POSIX_ACL
5161751e8a6SLinus Torvalds 	sb->s_flags |= SB_POSIXACL;
5171da177e4SLinus Torvalds #endif
5181da177e4SLinus Torvalds 
5191da177e4SLinus Torvalds 	if (newLVSize) {
520b40c2e66STino Reichardt 		pr_err("resize option for remount only\n");
521684bdc7fSJan Blunck 		goto out_kfree;
5221da177e4SLinus Torvalds 	}
5231da177e4SLinus Torvalds 
5241da177e4SLinus Torvalds 	/*
5251da177e4SLinus Torvalds 	 * Initialize blocksize to 4K.
5261da177e4SLinus Torvalds 	 */
5271da177e4SLinus Torvalds 	sb_set_blocksize(sb, PSIZE);
5281da177e4SLinus Torvalds 
5291da177e4SLinus Torvalds 	/*
5301da177e4SLinus Torvalds 	 * Set method vectors.
5311da177e4SLinus Torvalds 	 */
5321da177e4SLinus Torvalds 	sb->s_op = &jfs_super_operations;
5331da177e4SLinus Torvalds 	sb->s_export_op = &jfs_export_operations;
5342cc6a5a0SChristoph Hellwig 	sb->s_xattr = jfs_xattr_handlers;
535123e9cafSChristoph Hellwig #ifdef CONFIG_QUOTA
536123e9cafSChristoph Hellwig 	sb->dq_op = &dquot_operations;
53712fd086dSJan Kara 	sb->s_qcop = &jfs_quotactl_ops;
538507e1fa6SJan Kara 	sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP;
539123e9cafSChristoph Hellwig #endif
5401da177e4SLinus Torvalds 
5417fab479bSDave Kleikamp 	/*
5427fab479bSDave Kleikamp 	 * Initialize direct-mapping inode/address-space
5437fab479bSDave Kleikamp 	 */
5447fab479bSDave Kleikamp 	inode = new_inode(sb);
545eab1df71SDavid Howells 	if (inode == NULL) {
546eab1df71SDavid Howells 		ret = -ENOMEM;
547684bdc7fSJan Blunck 		goto out_unload;
548eab1df71SDavid Howells 	}
54974e157e6SChristoph Hellwig 	inode->i_size = bdev_nr_bytes(sb->s_bdev);
5507fab479bSDave Kleikamp 	inode->i_mapping->a_ops = &jfs_metapage_aops;
5515bef9151SAl Viro 	inode_fake_hash(inode);
5527fab479bSDave Kleikamp 	mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);
5537fab479bSDave Kleikamp 
5547fab479bSDave Kleikamp 	sbi->direct_inode = inode;
5557fab479bSDave Kleikamp 
5561da177e4SLinus Torvalds 	rc = jfs_mount(sb);
5571da177e4SLinus Torvalds 	if (rc) {
558789602e9SFabian Frederick 		if (!silent)
5591da177e4SLinus Torvalds 			jfs_err("jfs_mount failed w/return code = %d", rc);
5607fab479bSDave Kleikamp 		goto out_mount_failed;
5611da177e4SLinus Torvalds 	}
562bc98a42cSDavid Howells 	if (sb_rdonly(sb))
5631da177e4SLinus Torvalds 		sbi->log = NULL;
5641da177e4SLinus Torvalds 	else {
5651da177e4SLinus Torvalds 		rc = jfs_mount_rw(sb, 0);
5661da177e4SLinus Torvalds 		if (rc) {
5671da177e4SLinus Torvalds 			if (!silent) {
5681da177e4SLinus Torvalds 				jfs_err("jfs_mount_rw failed, return code = %d",
5691da177e4SLinus Torvalds 					rc);
5701da177e4SLinus Torvalds 			}
5711da177e4SLinus Torvalds 			goto out_no_rw;
5721da177e4SLinus Torvalds 		}
5731da177e4SLinus Torvalds 	}
5741da177e4SLinus Torvalds 
5751da177e4SLinus Torvalds 	sb->s_magic = JFS_SUPER_MAGIC;
5761da177e4SLinus Torvalds 
57794b77bd8SAl Viro 	if (sbi->mntflag & JFS_OS2)
57894b77bd8SAl Viro 		sb->s_d_op = &jfs_ci_dentry_operations;
57994b77bd8SAl Viro 
580eab1df71SDavid Howells 	inode = jfs_iget(sb, ROOT_I);
581eab1df71SDavid Howells 	if (IS_ERR(inode)) {
582eab1df71SDavid Howells 		ret = PTR_ERR(inode);
5836536d289SDave Kleikamp 		goto out_no_rw;
584eab1df71SDavid Howells 	}
58548fde701SAl Viro 	sb->s_root = d_make_root(inode);
5861da177e4SLinus Torvalds 	if (!sb->s_root)
5871da177e4SLinus Torvalds 		goto out_no_root;
5881da177e4SLinus Torvalds 
589c227390cSDave Kleikamp 	/* logical blocks are represented by 40 bits in pxd_t, etc.
590c227390cSDave Kleikamp 	 * and page cache is indexed by long
5911da177e4SLinus Torvalds 	 */
592c227390cSDave Kleikamp 	sb->s_maxbytes = min(((loff_t)sb->s_blocksize) << 40, MAX_LFS_FILESIZE);
5931da177e4SLinus Torvalds 	sb->s_time_gran = 1;
5941da177e4SLinus Torvalds 	return 0;
5951da177e4SLinus Torvalds 
5961da177e4SLinus Torvalds out_no_root:
5976536d289SDave Kleikamp 	jfs_err("jfs_read_super: get root dentry failed");
5981da177e4SLinus Torvalds 
5991da177e4SLinus Torvalds out_no_rw:
6001da177e4SLinus Torvalds 	rc = jfs_umount(sb);
601789602e9SFabian Frederick 	if (rc)
6021da177e4SLinus Torvalds 		jfs_err("jfs_umount failed with return code %d", rc);
6037fab479bSDave Kleikamp out_mount_failed:
60428fd1298SOGAWA Hirofumi 	filemap_write_and_wait(sbi->direct_inode->i_mapping);
6057fab479bSDave Kleikamp 	truncate_inode_pages(sbi->direct_inode->i_mapping, 0);
6067fab479bSDave Kleikamp 	make_bad_inode(sbi->direct_inode);
6077fab479bSDave Kleikamp 	iput(sbi->direct_inode);
6087fab479bSDave Kleikamp 	sbi->direct_inode = NULL;
609684bdc7fSJan Blunck out_unload:
6101da177e4SLinus Torvalds 	unload_nls(sbi->nls_tab);
611684bdc7fSJan Blunck out_kfree:
6121da177e4SLinus Torvalds 	kfree(sbi);
613eab1df71SDavid Howells 	return ret;
6141da177e4SLinus Torvalds }
6151da177e4SLinus Torvalds 
jfs_freeze(struct super_block * sb)616c4be0c1dSTakashi Sato static int jfs_freeze(struct super_block *sb)
6171da177e4SLinus Torvalds {
6181da177e4SLinus Torvalds 	struct jfs_sb_info *sbi = JFS_SBI(sb);
6191da177e4SLinus Torvalds 	struct jfs_log *log = sbi->log;
620e9b37667SVahram Martirosyan 	int rc = 0;
6211da177e4SLinus Torvalds 
622bc98a42cSDavid Howells 	if (!sb_rdonly(sb)) {
6231da177e4SLinus Torvalds 		txQuiesce(sb);
624e9b37667SVahram Martirosyan 		rc = lmLogShutdown(log);
625e9b37667SVahram Martirosyan 		if (rc) {
626eb8630d7SJoe Perches 			jfs_error(sb, "lmLogShutdown failed\n");
627e9b37667SVahram Martirosyan 
628e9b37667SVahram Martirosyan 			/* let operations fail rather than hang */
629e9b37667SVahram Martirosyan 			txResume(sb);
630e9b37667SVahram Martirosyan 
631e9b37667SVahram Martirosyan 			return rc;
632e9b37667SVahram Martirosyan 		}
633e9b37667SVahram Martirosyan 		rc = updateSuper(sb, FM_CLEAN);
634e9b37667SVahram Martirosyan 		if (rc) {
635b18db6deSJoe Perches 			jfs_err("jfs_freeze: updateSuper failed");
636e9b37667SVahram Martirosyan 			/*
637e9b37667SVahram Martirosyan 			 * Don't fail here. Everything succeeded except
638e9b37667SVahram Martirosyan 			 * marking the superblock clean, so there's really
639e9b37667SVahram Martirosyan 			 * no harm in leaving it frozen for now.
640e9b37667SVahram Martirosyan 			 */
641e9b37667SVahram Martirosyan 		}
6421da177e4SLinus Torvalds 	}
643c4be0c1dSTakashi Sato 	return 0;
6441da177e4SLinus Torvalds }
6451da177e4SLinus Torvalds 
jfs_unfreeze(struct super_block * sb)646c4be0c1dSTakashi Sato static int jfs_unfreeze(struct super_block *sb)
6471da177e4SLinus Torvalds {
6481da177e4SLinus Torvalds 	struct jfs_sb_info *sbi = JFS_SBI(sb);
6491da177e4SLinus Torvalds 	struct jfs_log *log = sbi->log;
6501da177e4SLinus Torvalds 	int rc = 0;
6511da177e4SLinus Torvalds 
652bc98a42cSDavid Howells 	if (!sb_rdonly(sb)) {
653e9b37667SVahram Martirosyan 		rc = updateSuper(sb, FM_MOUNT);
654e9b37667SVahram Martirosyan 		if (rc) {
655eb8630d7SJoe Perches 			jfs_error(sb, "updateSuper failed\n");
656e9b37667SVahram Martirosyan 			goto out;
657e9b37667SVahram Martirosyan 		}
658e9b37667SVahram Martirosyan 		rc = lmLogInit(log);
659e9b37667SVahram Martirosyan 		if (rc)
660eb8630d7SJoe Perches 			jfs_error(sb, "lmLogInit failed\n");
661e9b37667SVahram Martirosyan out:
6621da177e4SLinus Torvalds 		txResume(sb);
6631da177e4SLinus Torvalds 	}
664e9b37667SVahram Martirosyan 	return rc;
6651da177e4SLinus Torvalds }
6661da177e4SLinus Torvalds 
jfs_do_mount(struct file_system_type * fs_type,int flags,const char * dev_name,void * data)667152a0836SAl Viro static struct dentry *jfs_do_mount(struct file_system_type *fs_type,
668152a0836SAl Viro 	int flags, const char *dev_name, void *data)
6691da177e4SLinus Torvalds {
670152a0836SAl Viro 	return mount_bdev(fs_type, flags, dev_name, data, jfs_fill_super);
6711da177e4SLinus Torvalds }
6721da177e4SLinus Torvalds 
jfs_sync_fs(struct super_block * sb,int wait)6731da177e4SLinus Torvalds static int jfs_sync_fs(struct super_block *sb, int wait)
6741da177e4SLinus Torvalds {
6751da177e4SLinus Torvalds 	struct jfs_log *log = JFS_SBI(sb)->log;
6761da177e4SLinus Torvalds 
6771da177e4SLinus Torvalds 	/* log == NULL indicates read-only mount */
6781c627829SDave Kleikamp 	if (log) {
679a1177825SJan Kara 		/*
680a1177825SJan Kara 		 * Write quota structures to quota file, sync_blockdev() will
681a1177825SJan Kara 		 * write them to disk later
682a1177825SJan Kara 		 */
683a1177825SJan Kara 		dquot_writeback_dquots(sb, -1);
6841da177e4SLinus Torvalds 		jfs_flush_journal(log, wait);
685cbc3d65eSDave Kleikamp 		jfs_syncpt(log, 0);
6861c627829SDave Kleikamp 	}
6871da177e4SLinus Torvalds 
6881da177e4SLinus Torvalds 	return 0;
6891da177e4SLinus Torvalds }
6901da177e4SLinus Torvalds 
jfs_show_options(struct seq_file * seq,struct dentry * root)69134c80b1dSAl Viro static int jfs_show_options(struct seq_file *seq, struct dentry *root)
6928fc2751bSMark Bellon {
69334c80b1dSAl Viro 	struct jfs_sb_info *sbi = JFS_SBI(root->d_sb);
6948fc2751bSMark Bellon 
695c18cdc1aSEric W. Biederman 	if (uid_valid(sbi->uid))
696c18cdc1aSEric W. Biederman 		seq_printf(seq, ",uid=%d", from_kuid(&init_user_ns, sbi->uid));
697c18cdc1aSEric W. Biederman 	if (gid_valid(sbi->gid))
698c18cdc1aSEric W. Biederman 		seq_printf(seq, ",gid=%d", from_kgid(&init_user_ns, sbi->gid));
69969eb66d7SDave Kleikamp 	if (sbi->umask != -1)
70069eb66d7SDave Kleikamp 		seq_printf(seq, ",umask=%03o", sbi->umask);
7018fc2751bSMark Bellon 	if (sbi->flag & JFS_NOINTEGRITY)
7028fc2751bSMark Bellon 		seq_puts(seq, ",nointegrity");
703b40c2e66STino Reichardt 	if (sbi->flag & JFS_DISCARD)
704b40c2e66STino Reichardt 		seq_printf(seq, ",discard=%u", sbi->minblks_trim);
7055c5e32ceSMiklos Szeredi 	if (sbi->nls_tab)
7065c5e32ceSMiklos Szeredi 		seq_printf(seq, ",iocharset=%s", sbi->nls_tab->charset);
7075c5e32ceSMiklos Szeredi 	if (sbi->flag & JFS_ERR_CONTINUE)
7085c5e32ceSMiklos Szeredi 		seq_printf(seq, ",errors=continue");
7095c5e32ceSMiklos Szeredi 	if (sbi->flag & JFS_ERR_PANIC)
7105c5e32ceSMiklos Szeredi 		seq_printf(seq, ",errors=panic");
7118fc2751bSMark Bellon 
712115ff50bSDave Kleikamp #ifdef CONFIG_QUOTA
7138fc2751bSMark Bellon 	if (sbi->flag & JFS_USRQUOTA)
7148fc2751bSMark Bellon 		seq_puts(seq, ",usrquota");
7158fc2751bSMark Bellon 
7168fc2751bSMark Bellon 	if (sbi->flag & JFS_GRPQUOTA)
7178fc2751bSMark Bellon 		seq_puts(seq, ",grpquota");
7188fc2751bSMark Bellon #endif
7198fc2751bSMark Bellon 
7208fc2751bSMark Bellon 	return 0;
7218fc2751bSMark Bellon }
7228fc2751bSMark Bellon 
723115ff50bSDave Kleikamp #ifdef CONFIG_QUOTA
724115ff50bSDave Kleikamp 
725115ff50bSDave Kleikamp /* Read data from quotafile - avoid pagecache and such because we cannot afford
726115ff50bSDave Kleikamp  * acquiring the locks... As quota files are never truncated and quota code
727115ff50bSDave Kleikamp  * itself serializes the operations (and no one else should touch the files)
728115ff50bSDave Kleikamp  * we don't have to be afraid of races */
jfs_quota_read(struct super_block * sb,int type,char * data,size_t len,loff_t off)729115ff50bSDave Kleikamp static ssize_t jfs_quota_read(struct super_block *sb, int type, char *data,
730115ff50bSDave Kleikamp 			      size_t len, loff_t off)
731115ff50bSDave Kleikamp {
732115ff50bSDave Kleikamp 	struct inode *inode = sb_dqopt(sb)->files[type];
733115ff50bSDave Kleikamp 	sector_t blk = off >> sb->s_blocksize_bits;
734115ff50bSDave Kleikamp 	int err = 0;
735115ff50bSDave Kleikamp 	int offset = off & (sb->s_blocksize - 1);
736115ff50bSDave Kleikamp 	int tocopy;
737115ff50bSDave Kleikamp 	size_t toread;
738115ff50bSDave Kleikamp 	struct buffer_head tmp_bh;
739115ff50bSDave Kleikamp 	struct buffer_head *bh;
740115ff50bSDave Kleikamp 	loff_t i_size = i_size_read(inode);
741115ff50bSDave Kleikamp 
742115ff50bSDave Kleikamp 	if (off > i_size)
743115ff50bSDave Kleikamp 		return 0;
744115ff50bSDave Kleikamp 	if (off+len > i_size)
745115ff50bSDave Kleikamp 		len = i_size-off;
746115ff50bSDave Kleikamp 	toread = len;
747115ff50bSDave Kleikamp 	while (toread > 0) {
74873c6da32SJiangshan Yi 		tocopy = min_t(size_t, sb->s_blocksize - offset, toread);
749115ff50bSDave Kleikamp 
750115ff50bSDave Kleikamp 		tmp_bh.b_state = 0;
75193407472SFabian Frederick 		tmp_bh.b_size = i_blocksize(inode);
752115ff50bSDave Kleikamp 		err = jfs_get_block(inode, blk, &tmp_bh, 0);
753115ff50bSDave Kleikamp 		if (err)
754115ff50bSDave Kleikamp 			return err;
755115ff50bSDave Kleikamp 		if (!buffer_mapped(&tmp_bh))	/* A hole? */
756115ff50bSDave Kleikamp 			memset(data, 0, tocopy);
757115ff50bSDave Kleikamp 		else {
758115ff50bSDave Kleikamp 			bh = sb_bread(sb, tmp_bh.b_blocknr);
759115ff50bSDave Kleikamp 			if (!bh)
760115ff50bSDave Kleikamp 				return -EIO;
761115ff50bSDave Kleikamp 			memcpy(data, bh->b_data+offset, tocopy);
762115ff50bSDave Kleikamp 			brelse(bh);
763115ff50bSDave Kleikamp 		}
764115ff50bSDave Kleikamp 		offset = 0;
765115ff50bSDave Kleikamp 		toread -= tocopy;
766115ff50bSDave Kleikamp 		data += tocopy;
767115ff50bSDave Kleikamp 		blk++;
768115ff50bSDave Kleikamp 	}
769115ff50bSDave Kleikamp 	return len;
770115ff50bSDave Kleikamp }
771115ff50bSDave Kleikamp 
772115ff50bSDave Kleikamp /* Write to quotafile */
jfs_quota_write(struct super_block * sb,int type,const char * data,size_t len,loff_t off)773115ff50bSDave Kleikamp static ssize_t jfs_quota_write(struct super_block *sb, int type,
774115ff50bSDave Kleikamp 			       const char *data, size_t len, loff_t off)
775115ff50bSDave Kleikamp {
776115ff50bSDave Kleikamp 	struct inode *inode = sb_dqopt(sb)->files[type];
777115ff50bSDave Kleikamp 	sector_t blk = off >> sb->s_blocksize_bits;
778115ff50bSDave Kleikamp 	int err = 0;
779115ff50bSDave Kleikamp 	int offset = off & (sb->s_blocksize - 1);
780115ff50bSDave Kleikamp 	int tocopy;
781115ff50bSDave Kleikamp 	size_t towrite = len;
782115ff50bSDave Kleikamp 	struct buffer_head tmp_bh;
783115ff50bSDave Kleikamp 	struct buffer_head *bh;
784115ff50bSDave Kleikamp 
7855955102cSAl Viro 	inode_lock(inode);
786115ff50bSDave Kleikamp 	while (towrite > 0) {
78773c6da32SJiangshan Yi 		tocopy = min_t(size_t, sb->s_blocksize - offset, towrite);
788115ff50bSDave Kleikamp 
789115ff50bSDave Kleikamp 		tmp_bh.b_state = 0;
79093407472SFabian Frederick 		tmp_bh.b_size = i_blocksize(inode);
791115ff50bSDave Kleikamp 		err = jfs_get_block(inode, blk, &tmp_bh, 1);
792115ff50bSDave Kleikamp 		if (err)
793115ff50bSDave Kleikamp 			goto out;
794115ff50bSDave Kleikamp 		if (offset || tocopy != sb->s_blocksize)
795115ff50bSDave Kleikamp 			bh = sb_bread(sb, tmp_bh.b_blocknr);
796115ff50bSDave Kleikamp 		else
797115ff50bSDave Kleikamp 			bh = sb_getblk(sb, tmp_bh.b_blocknr);
798115ff50bSDave Kleikamp 		if (!bh) {
799115ff50bSDave Kleikamp 			err = -EIO;
800115ff50bSDave Kleikamp 			goto out;
801115ff50bSDave Kleikamp 		}
802115ff50bSDave Kleikamp 		lock_buffer(bh);
803115ff50bSDave Kleikamp 		memcpy(bh->b_data+offset, data, tocopy);
804115ff50bSDave Kleikamp 		flush_dcache_page(bh->b_page);
805115ff50bSDave Kleikamp 		set_buffer_uptodate(bh);
806115ff50bSDave Kleikamp 		mark_buffer_dirty(bh);
807115ff50bSDave Kleikamp 		unlock_buffer(bh);
808115ff50bSDave Kleikamp 		brelse(bh);
809115ff50bSDave Kleikamp 		offset = 0;
810115ff50bSDave Kleikamp 		towrite -= tocopy;
811115ff50bSDave Kleikamp 		data += tocopy;
812115ff50bSDave Kleikamp 		blk++;
813115ff50bSDave Kleikamp 	}
814115ff50bSDave Kleikamp out:
8159c83633aSDan Carpenter 	if (len == towrite) {
8165955102cSAl Viro 		inode_unlock(inode);
817115ff50bSDave Kleikamp 		return err;
8189c83633aSDan Carpenter 	}
819115ff50bSDave Kleikamp 	if (inode->i_size < off+len-towrite)
820115ff50bSDave Kleikamp 		i_size_write(inode, off+len-towrite);
821ad9dc5dfSJeff Layton 	inode->i_mtime = inode_set_ctime_current(inode);
822115ff50bSDave Kleikamp 	mark_inode_dirty(inode);
8235955102cSAl Viro 	inode_unlock(inode);
824115ff50bSDave Kleikamp 	return len - towrite;
825115ff50bSDave Kleikamp }
826115ff50bSDave Kleikamp 
jfs_get_dquots(struct inode * inode)827*42954c37SJan Kara static struct dquot __rcu **jfs_get_dquots(struct inode *inode)
828507e1fa6SJan Kara {
829507e1fa6SJan Kara 	return JFS_IP(inode)->i_dquot;
830507e1fa6SJan Kara }
83112fd086dSJan Kara 
jfs_quota_on(struct super_block * sb,int type,int format_id,const struct path * path)83212fd086dSJan Kara static int jfs_quota_on(struct super_block *sb, int type, int format_id,
83312fd086dSJan Kara 			const struct path *path)
83412fd086dSJan Kara {
83512fd086dSJan Kara 	int err;
83612fd086dSJan Kara 	struct inode *inode;
83712fd086dSJan Kara 
83812fd086dSJan Kara 	err = dquot_quota_on(sb, type, format_id, path);
83912fd086dSJan Kara 	if (err)
84012fd086dSJan Kara 		return err;
84112fd086dSJan Kara 
84212fd086dSJan Kara 	inode = d_inode(path->dentry);
84312fd086dSJan Kara 	inode_lock(inode);
84412fd086dSJan Kara 	JFS_IP(inode)->mode2 |= JFS_NOATIME_FL | JFS_IMMUTABLE_FL;
84512fd086dSJan Kara 	inode_set_flags(inode, S_NOATIME | S_IMMUTABLE,
84612fd086dSJan Kara 			S_NOATIME | S_IMMUTABLE);
84712fd086dSJan Kara 	inode_unlock(inode);
84812fd086dSJan Kara 	mark_inode_dirty(inode);
84912fd086dSJan Kara 
85012fd086dSJan Kara 	return 0;
85112fd086dSJan Kara }
85212fd086dSJan Kara 
jfs_quota_off(struct super_block * sb,int type)85312fd086dSJan Kara static int jfs_quota_off(struct super_block *sb, int type)
85412fd086dSJan Kara {
85512fd086dSJan Kara 	struct inode *inode = sb_dqopt(sb)->files[type];
85612fd086dSJan Kara 	int err;
85712fd086dSJan Kara 
85812fd086dSJan Kara 	if (!inode || !igrab(inode))
85912fd086dSJan Kara 		goto out;
86012fd086dSJan Kara 
86112fd086dSJan Kara 	err = dquot_quota_off(sb, type);
86212fd086dSJan Kara 	if (err)
86312fd086dSJan Kara 		goto out_put;
86412fd086dSJan Kara 
86512fd086dSJan Kara 	inode_lock(inode);
86612fd086dSJan Kara 	JFS_IP(inode)->mode2 &= ~(JFS_NOATIME_FL | JFS_IMMUTABLE_FL);
86712fd086dSJan Kara 	inode_set_flags(inode, 0, S_NOATIME | S_IMMUTABLE);
86812fd086dSJan Kara 	inode_unlock(inode);
86912fd086dSJan Kara 	mark_inode_dirty(inode);
87012fd086dSJan Kara out_put:
87112fd086dSJan Kara 	iput(inode);
87212fd086dSJan Kara 	return err;
87312fd086dSJan Kara out:
87412fd086dSJan Kara 	return dquot_quota_off(sb, type);
87512fd086dSJan Kara }
876115ff50bSDave Kleikamp #endif
877115ff50bSDave Kleikamp 
878ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations jfs_super_operations = {
8791da177e4SLinus Torvalds 	.alloc_inode	= jfs_alloc_inode,
880b3b4a6e3SAl Viro 	.free_inode	= jfs_free_inode,
8811da177e4SLinus Torvalds 	.dirty_inode	= jfs_dirty_inode,
8821da177e4SLinus Torvalds 	.write_inode	= jfs_write_inode,
88362aff86fSAl Viro 	.evict_inode	= jfs_evict_inode,
8841da177e4SLinus Torvalds 	.put_super	= jfs_put_super,
8851da177e4SLinus Torvalds 	.sync_fs	= jfs_sync_fs,
886c4be0c1dSTakashi Sato 	.freeze_fs	= jfs_freeze,
887c4be0c1dSTakashi Sato 	.unfreeze_fs	= jfs_unfreeze,
8881da177e4SLinus Torvalds 	.statfs		= jfs_statfs,
8891da177e4SLinus Torvalds 	.remount_fs	= jfs_remount,
890115ff50bSDave Kleikamp 	.show_options	= jfs_show_options,
891115ff50bSDave Kleikamp #ifdef CONFIG_QUOTA
892115ff50bSDave Kleikamp 	.quota_read	= jfs_quota_read,
893115ff50bSDave Kleikamp 	.quota_write	= jfs_quota_write,
894507e1fa6SJan Kara 	.get_dquots	= jfs_get_dquots,
895115ff50bSDave Kleikamp #endif
8961da177e4SLinus Torvalds };
8971da177e4SLinus Torvalds 
89839655164SChristoph Hellwig static const struct export_operations jfs_export_operations = {
899d425de70SChristoph Hellwig 	.fh_to_dentry	= jfs_fh_to_dentry,
900d425de70SChristoph Hellwig 	.fh_to_parent	= jfs_fh_to_parent,
9011da177e4SLinus Torvalds 	.get_parent	= jfs_get_parent,
9021da177e4SLinus Torvalds };
9031da177e4SLinus Torvalds 
9041da177e4SLinus Torvalds static struct file_system_type jfs_fs_type = {
9051da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
9061da177e4SLinus Torvalds 	.name		= "jfs",
907152a0836SAl Viro 	.mount		= jfs_do_mount,
9081da177e4SLinus Torvalds 	.kill_sb	= kill_block_super,
9091da177e4SLinus Torvalds 	.fs_flags	= FS_REQUIRES_DEV,
9101da177e4SLinus Torvalds };
9117f78e035SEric W. Biederman MODULE_ALIAS_FS("jfs");
9121da177e4SLinus Torvalds 
init_once(void * foo)91351cc5068SAlexey Dobriyan static void init_once(void *foo)
9141da177e4SLinus Torvalds {
9151da177e4SLinus Torvalds 	struct jfs_inode_info *jfs_ip = (struct jfs_inode_info *) foo;
9161da177e4SLinus Torvalds 
9171da177e4SLinus Torvalds 	memset(jfs_ip, 0, sizeof(struct jfs_inode_info));
9181da177e4SLinus Torvalds 	INIT_LIST_HEAD(&jfs_ip->anon_inode_list);
9191da177e4SLinus Torvalds 	init_rwsem(&jfs_ip->rdwrlock);
9201de87444SIngo Molnar 	mutex_init(&jfs_ip->commit_mutex);
9211da177e4SLinus Torvalds 	init_rwsem(&jfs_ip->xattr_sem);
9221da177e4SLinus Torvalds 	spin_lock_init(&jfs_ip->ag_lock);
9231da177e4SLinus Torvalds 	jfs_ip->active_ag = -1;
9241da177e4SLinus Torvalds 	inode_init_once(&jfs_ip->vfs_inode);
9251da177e4SLinus Torvalds }
9261da177e4SLinus Torvalds 
init_jfs_fs(void)9271da177e4SLinus Torvalds static int __init init_jfs_fs(void)
9281da177e4SLinus Torvalds {
9291da177e4SLinus Torvalds 	int i;
9301da177e4SLinus Torvalds 	int rc;
9311da177e4SLinus Torvalds 
9321da177e4SLinus Torvalds 	jfs_inode_cachep =
9338d2704d3SDavid Windsor 	    kmem_cache_create_usercopy("jfs_ip", sizeof(struct jfs_inode_info),
9348d2704d3SDavid Windsor 			0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD|SLAB_ACCOUNT,
9355d299f44SKees Cook 			offsetof(struct jfs_inode_info, i_inline_all),
9365d299f44SKees Cook 			sizeof_field(struct jfs_inode_info, i_inline_all),
93720c2df83SPaul Mundt 			init_once);
9381da177e4SLinus Torvalds 	if (jfs_inode_cachep == NULL)
9391da177e4SLinus Torvalds 		return -ENOMEM;
9401da177e4SLinus Torvalds 
9411da177e4SLinus Torvalds 	/*
9421da177e4SLinus Torvalds 	 * Metapage initialization
9431da177e4SLinus Torvalds 	 */
9441da177e4SLinus Torvalds 	rc = metapage_init();
9451da177e4SLinus Torvalds 	if (rc) {
9461da177e4SLinus Torvalds 		jfs_err("metapage_init failed w/rc = %d", rc);
9471da177e4SLinus Torvalds 		goto free_slab;
9481da177e4SLinus Torvalds 	}
9491da177e4SLinus Torvalds 
9501da177e4SLinus Torvalds 	/*
9511da177e4SLinus Torvalds 	 * Transaction Manager initialization
9521da177e4SLinus Torvalds 	 */
9531da177e4SLinus Torvalds 	rc = txInit();
9541da177e4SLinus Torvalds 	if (rc) {
9551da177e4SLinus Torvalds 		jfs_err("txInit failed w/rc = %d", rc);
9561da177e4SLinus Torvalds 		goto free_metapage;
9571da177e4SLinus Torvalds 	}
9581da177e4SLinus Torvalds 
9591da177e4SLinus Torvalds 	/*
9601da177e4SLinus Torvalds 	 * I/O completion thread (endio)
9611da177e4SLinus Torvalds 	 */
96291dbb4deSChristoph Hellwig 	jfsIOthread = kthread_run(jfsIOWait, NULL, "jfsIO");
96391dbb4deSChristoph Hellwig 	if (IS_ERR(jfsIOthread)) {
96491dbb4deSChristoph Hellwig 		rc = PTR_ERR(jfsIOthread);
96591dbb4deSChristoph Hellwig 		jfs_err("init_jfs_fs: fork failed w/rc = %d", rc);
9661da177e4SLinus Torvalds 		goto end_txmngr;
9671da177e4SLinus Torvalds 	}
9681da177e4SLinus Torvalds 
9691da177e4SLinus Torvalds 	if (commit_threads < 1)
9701da177e4SLinus Torvalds 		commit_threads = num_online_cpus();
9711da177e4SLinus Torvalds 	if (commit_threads > MAX_COMMIT_THREADS)
9721da177e4SLinus Torvalds 		commit_threads = MAX_COMMIT_THREADS;
9731da177e4SLinus Torvalds 
9741da177e4SLinus Torvalds 	for (i = 0; i < commit_threads; i++) {
975789602e9SFabian Frederick 		jfsCommitThread[i] = kthread_run(jfs_lazycommit, NULL,
976789602e9SFabian Frederick 						 "jfsCommit");
97791dbb4deSChristoph Hellwig 		if (IS_ERR(jfsCommitThread[i])) {
97891dbb4deSChristoph Hellwig 			rc = PTR_ERR(jfsCommitThread[i]);
97991dbb4deSChristoph Hellwig 			jfs_err("init_jfs_fs: fork failed w/rc = %d", rc);
9801da177e4SLinus Torvalds 			commit_threads = i;
9811da177e4SLinus Torvalds 			goto kill_committask;
9821da177e4SLinus Torvalds 		}
9831da177e4SLinus Torvalds 	}
9841da177e4SLinus Torvalds 
98591dbb4deSChristoph Hellwig 	jfsSyncThread = kthread_run(jfs_sync, NULL, "jfsSync");
98691dbb4deSChristoph Hellwig 	if (IS_ERR(jfsSyncThread)) {
98791dbb4deSChristoph Hellwig 		rc = PTR_ERR(jfsSyncThread);
98891dbb4deSChristoph Hellwig 		jfs_err("init_jfs_fs: fork failed w/rc = %d", rc);
9891da177e4SLinus Torvalds 		goto kill_committask;
9901da177e4SLinus Torvalds 	}
9911da177e4SLinus Torvalds 
9921da177e4SLinus Torvalds #ifdef PROC_FS_JFS
9931da177e4SLinus Torvalds 	jfs_proc_init();
9941da177e4SLinus Torvalds #endif
9951da177e4SLinus Torvalds 
99676bf09fcSAl Viro 	rc = register_filesystem(&jfs_fs_type);
99776bf09fcSAl Viro 	if (!rc)
99876bf09fcSAl Viro 		return 0;
9991da177e4SLinus Torvalds 
100076bf09fcSAl Viro #ifdef PROC_FS_JFS
100176bf09fcSAl Viro 	jfs_proc_clean();
100276bf09fcSAl Viro #endif
100376bf09fcSAl Viro 	kthread_stop(jfsSyncThread);
10041da177e4SLinus Torvalds kill_committask:
10051da177e4SLinus Torvalds 	for (i = 0; i < commit_threads; i++)
100691dbb4deSChristoph Hellwig 		kthread_stop(jfsCommitThread[i]);
100791dbb4deSChristoph Hellwig 	kthread_stop(jfsIOthread);
10081da177e4SLinus Torvalds end_txmngr:
10091da177e4SLinus Torvalds 	txExit();
10101da177e4SLinus Torvalds free_metapage:
10111da177e4SLinus Torvalds 	metapage_exit();
10121da177e4SLinus Torvalds free_slab:
10131da177e4SLinus Torvalds 	kmem_cache_destroy(jfs_inode_cachep);
10141da177e4SLinus Torvalds 	return rc;
10151da177e4SLinus Torvalds }
10161da177e4SLinus Torvalds 
exit_jfs_fs(void)10171da177e4SLinus Torvalds static void __exit exit_jfs_fs(void)
10181da177e4SLinus Torvalds {
10191da177e4SLinus Torvalds 	int i;
10201da177e4SLinus Torvalds 
10211da177e4SLinus Torvalds 	jfs_info("exit_jfs_fs called");
10221da177e4SLinus Torvalds 
10231da177e4SLinus Torvalds 	txExit();
10241da177e4SLinus Torvalds 	metapage_exit();
102591dbb4deSChristoph Hellwig 
102691dbb4deSChristoph Hellwig 	kthread_stop(jfsIOthread);
10271da177e4SLinus Torvalds 	for (i = 0; i < commit_threads; i++)
102891dbb4deSChristoph Hellwig 		kthread_stop(jfsCommitThread[i]);
102991dbb4deSChristoph Hellwig 	kthread_stop(jfsSyncThread);
10301da177e4SLinus Torvalds #ifdef PROC_FS_JFS
10311da177e4SLinus Torvalds 	jfs_proc_clean();
10321da177e4SLinus Torvalds #endif
10331da177e4SLinus Torvalds 	unregister_filesystem(&jfs_fs_type);
10348c0a8537SKirill A. Shutemov 
10358c0a8537SKirill A. Shutemov 	/*
10368c0a8537SKirill A. Shutemov 	 * Make sure all delayed rcu free inodes are flushed before we
10378c0a8537SKirill A. Shutemov 	 * destroy cache.
10388c0a8537SKirill A. Shutemov 	 */
10398c0a8537SKirill A. Shutemov 	rcu_barrier();
10401da177e4SLinus Torvalds 	kmem_cache_destroy(jfs_inode_cachep);
10411da177e4SLinus Torvalds }
10421da177e4SLinus Torvalds 
10431da177e4SLinus Torvalds module_init(init_jfs_fs)
10441da177e4SLinus Torvalds module_exit(exit_jfs_fs)
1045