super.c 23.3 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6
/*
 *   Copyright (C) International Business Machines Corp., 2000-2004
 *   Portions Copyright (C) Christoph Hellwig, 2001-2002
 *
 *   This program is free software;  you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
Dave Kleikamp's avatar
Dave Kleikamp committed
7
 *   the Free Software Foundation; either version 2 of the License, or
Linus Torvalds's avatar
Linus Torvalds committed
8
 *   (at your option) any later version.
Dave Kleikamp's avatar
Dave Kleikamp committed
9
 *
Linus Torvalds's avatar
Linus Torvalds committed
10 11 12 13 14 15
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 *   the GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
Dave Kleikamp's avatar
Dave Kleikamp committed
16
 *   along with this program;  if not, write to the Free Software
Linus Torvalds's avatar
Linus Torvalds committed
17 18 19 20 21 22 23 24
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#include <linux/fs.h>
#include <linux/module.h>
#include <linux/parser.h>
#include <linux/completion.h>
#include <linux/vfs.h>
25
#include <linux/quotaops.h>
26
#include <linux/mount.h>
Linus Torvalds's avatar
Linus Torvalds committed
27
#include <linux/moduleparam.h>
28
#include <linux/kthread.h>
29
#include <linux/posix_acl.h>
30
#include <linux/buffer_head.h>
31
#include <linux/exportfs.h>
Coly Li's avatar
Coly Li committed
32
#include <linux/crc32.h>
33
#include <linux/slab.h>
Linus Torvalds's avatar
Linus Torvalds committed
34
#include <asm/uaccess.h>
35
#include <linux/seq_file.h>
36
#include <linux/blkdev.h>
Linus Torvalds's avatar
Linus Torvalds committed
37 38 39

#include "jfs_incore.h"
#include "jfs_filsys.h"
40
#include "jfs_inode.h"
Linus Torvalds's avatar
Linus Torvalds committed
41 42 43 44 45 46
#include "jfs_metapage.h"
#include "jfs_superblock.h"
#include "jfs_dmap.h"
#include "jfs_imap.h"
#include "jfs_acl.h"
#include "jfs_debug.h"
47
#include "jfs_xattr.h"
Linus Torvalds's avatar
Linus Torvalds committed
48 49 50 51 52

MODULE_DESCRIPTION("The Journaled Filesystem (JFS)");
MODULE_AUTHOR("Steve Best/Dave Kleikamp/Barry Arndt, IBM");
MODULE_LICENSE("GPL");

53
static struct kmem_cache *jfs_inode_cachep;
Linus Torvalds's avatar
Linus Torvalds committed
54

55
static const struct super_operations jfs_super_operations;
56
static const struct export_operations jfs_export_operations;
Linus Torvalds's avatar
Linus Torvalds committed
57 58 59
static struct file_system_type jfs_fs_type;

#define MAX_COMMIT_THREADS 64
60
static int commit_threads;
Linus Torvalds's avatar
Linus Torvalds committed
61 62 63
module_param(commit_threads, int, 0);
MODULE_PARM_DESC(commit_threads, "Number of commit threads");

64 65 66
static struct task_struct *jfsCommitThread[MAX_COMMIT_THREADS];
struct task_struct *jfsIOthread;
struct task_struct *jfsSyncThread;
Linus Torvalds's avatar
Linus Torvalds committed
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86

#ifdef CONFIG_JFS_DEBUG
int jfsloglevel = JFS_LOGLEVEL_WARN;
module_param(jfsloglevel, int, 0644);
MODULE_PARM_DESC(jfsloglevel, "Specify JFS loglevel (0, 1 or 2)");
#endif

static void jfs_handle_error(struct super_block *sb)
{
	struct jfs_sb_info *sbi = JFS_SBI(sb);

	if (sb->s_flags & MS_RDONLY)
		return;

	updateSuper(sb, FM_DIRTY);

	if (sbi->flag & JFS_ERR_PANIC)
		panic("JFS (device %s): panic forced after error\n",
			sb->s_id);
	else if (sbi->flag & JFS_ERR_REMOUNT_RO) {
87
		jfs_err("ERROR: (device %s): remounting filesystem as read-only\n",
Linus Torvalds's avatar
Linus Torvalds committed
88 89
			sb->s_id);
		sb->s_flags |= MS_RDONLY;
Dave Kleikamp's avatar
Dave Kleikamp committed
90
	}
Linus Torvalds's avatar
Linus Torvalds committed
91 92 93 94

	/* nothing is done for continue beyond marking the superblock dirty */
}

Joe Perches's avatar
Joe Perches committed
95
void jfs_error(struct super_block *sb, const char *fmt, ...)
Linus Torvalds's avatar
Linus Torvalds committed
96
{
Joe Perches's avatar
Joe Perches committed
97
	struct va_format vaf;
Linus Torvalds's avatar
Linus Torvalds committed
98 99
	va_list args;

Joe Perches's avatar
Joe Perches committed
100 101 102 103
	va_start(args, fmt);

	vaf.fmt = fmt;
	vaf.va = &args;
Linus Torvalds's avatar
Linus Torvalds committed
104

105
	pr_err("ERROR: (device %s): %ps: %pV\n",
Joe Perches's avatar
Joe Perches committed
106 107 108
	       sb->s_id, __builtin_return_address(0), &vaf);

	va_end(args);
Linus Torvalds's avatar
Linus Torvalds committed
109 110 111 112 113 114 115 116 117 118 119

	jfs_handle_error(sb);
}

static struct inode *jfs_alloc_inode(struct super_block *sb)
{
	struct jfs_inode_info *jfs_inode;

	jfs_inode = kmem_cache_alloc(jfs_inode_cachep, GFP_NOFS);
	if (!jfs_inode)
		return NULL;
120 121 122
#ifdef CONFIG_QUOTA
	memset(&jfs_inode->i_dquot, 0, sizeof(jfs_inode->i_dquot));
#endif
Linus Torvalds's avatar
Linus Torvalds committed
123 124 125
	return &jfs_inode->vfs_inode;
}

Nick Piggin's avatar
Nick Piggin committed
126 127 128 129 130 131 132
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);
}

Linus Torvalds's avatar
Linus Torvalds committed
133 134 135 136
static void jfs_destroy_inode(struct inode *inode)
{
	struct jfs_inode_info *ji = JFS_IP(inode);

Dave Kleikamp's avatar
Dave Kleikamp committed
137 138
	BUG_ON(!list_empty(&ji->anon_inode_list));

Linus Torvalds's avatar
Linus Torvalds committed
139 140 141 142 143 144 145
	spin_lock_irq(&ji->ag_lock);
	if (ji->active_ag != -1) {
		struct bmap *bmap = JFS_SBI(inode->i_sb)->bmap;
		atomic_dec(&bmap->db_active[ji->active_ag]);
		ji->active_ag = -1;
	}
	spin_unlock_irq(&ji->ag_lock);
Nick Piggin's avatar
Nick Piggin committed
146
	call_rcu(&inode->i_rcu, jfs_i_callback);
Linus Torvalds's avatar
Linus Torvalds committed
147 148
}

149
static int jfs_statfs(struct dentry *dentry, struct kstatfs *buf)
Linus Torvalds's avatar
Linus Torvalds committed
150
{
151
	struct jfs_sb_info *sbi = JFS_SBI(dentry->d_sb);
Linus Torvalds's avatar
Linus Torvalds committed
152 153 154 155 156 157 158 159 160 161 162 163
	s64 maxinodes;
	struct inomap *imap = JFS_IP(sbi->ipimap)->i_imap;

	jfs_info("In jfs_statfs");
	buf->f_type = JFS_SUPER_MAGIC;
	buf->f_bsize = sbi->bsize;
	buf->f_blocks = sbi->bmap->db_mapsize;
	buf->f_bfree = sbi->bmap->db_nfree;
	buf->f_bavail = sbi->bmap->db_nfree;
	/*
	 * If we really return the number of allocated & free inodes, some
	 * applications will fail because they won't see enough free inodes.
164
	 * We'll try to calculate some guess as to how many inodes we can
Linus Torvalds's avatar
Linus Torvalds committed
165 166 167 168 169 170 171 172 173 174 175
	 * really allocate
	 *
	 * buf->f_files = atomic_read(&imap->im_numinos);
	 * buf->f_ffree = atomic_read(&imap->im_numfree);
	 */
	maxinodes = min((s64) atomic_read(&imap->im_numinos) +
			((sbi->bmap->db_nfree >> imap->im_l2nbperiext)
			 << L2INOSPEREXT), (s64) 0xffffffffLL);
	buf->f_files = maxinodes;
	buf->f_ffree = maxinodes - (atomic_read(&imap->im_numinos) -
				    atomic_read(&imap->im_numfree));
Coly Li's avatar
Coly Li committed
176 177 178
	buf->f_fsid.val[0] = (u32)crc32_le(0, sbi->uuid, sizeof(sbi->uuid)/2);
	buf->f_fsid.val[1] = (u32)crc32_le(0, sbi->uuid + sizeof(sbi->uuid)/2,
					sizeof(sbi->uuid)/2);
Linus Torvalds's avatar
Linus Torvalds committed
179 180 181 182 183 184 185 186 187 188 189

	buf->f_namelen = JFS_NAME_MAX;
	return 0;
}

static void jfs_put_super(struct super_block *sb)
{
	struct jfs_sb_info *sbi = JFS_SBI(sb);
	int rc;

	jfs_info("In jfs_put_super");
190

191 192
	dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);

Linus Torvalds's avatar
Linus Torvalds committed
193 194 195
	rc = jfs_umount(sb);
	if (rc)
		jfs_err("jfs_umount failed with return code %d", rc);
196 197

	unload_nls(sbi->nls_tab);
Linus Torvalds's avatar
Linus Torvalds committed
198

199 200 201
	truncate_inode_pages(sbi->direct_inode->i_mapping, 0);
	iput(sbi->direct_inode);

Linus Torvalds's avatar
Linus Torvalds committed
202 203 204 205 206
	kfree(sbi);
}

enum {
	Opt_integrity, Opt_nointegrity, Opt_iocharset, Opt_resize,
207
	Opt_resize_nosize, Opt_errors, Opt_ignore, Opt_err, Opt_quota,
208 209
	Opt_usrquota, Opt_grpquota, Opt_uid, Opt_gid, Opt_umask,
	Opt_discard, Opt_nodiscard, Opt_discard_minblk
Linus Torvalds's avatar
Linus Torvalds committed
210 211
};

212
static const match_table_t tokens = {
Linus Torvalds's avatar
Linus Torvalds committed
213 214 215 216 217 218 219 220
	{Opt_integrity, "integrity"},
	{Opt_nointegrity, "nointegrity"},
	{Opt_iocharset, "iocharset=%s"},
	{Opt_resize, "resize=%u"},
	{Opt_resize_nosize, "resize"},
	{Opt_errors, "errors=%s"},
	{Opt_ignore, "noquota"},
	{Opt_ignore, "quota"},
221 222
	{Opt_usrquota, "usrquota"},
	{Opt_grpquota, "grpquota"},
223 224 225
	{Opt_uid, "uid=%u"},
	{Opt_gid, "gid=%u"},
	{Opt_umask, "umask=%u"},
226 227 228
	{Opt_discard, "discard"},
	{Opt_nodiscard, "nodiscard"},
	{Opt_discard_minblk, "discard=%u"},
Linus Torvalds's avatar
Linus Torvalds committed
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
	{Opt_err, NULL}
};

static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,
			 int *flag)
{
	void *nls_map = (void *)-1;	/* -1: no change;  NULL: none */
	char *p;
	struct jfs_sb_info *sbi = JFS_SBI(sb);

	*newLVSize = 0;

	if (!options)
		return 1;

	while ((p = strsep(&options, ",")) != NULL) {
		substring_t args[MAX_OPT_ARGS];
		int token;
		if (!*p)
			continue;

		token = match_token(p, tokens, args);
		switch (token) {
		case Opt_integrity:
			*flag &= ~JFS_NOINTEGRITY;
			break;
		case Opt_nointegrity:
			*flag |= JFS_NOINTEGRITY;
			break;
		case Opt_ignore:
			/* Silently ignore the quota options */
			/* Don't do anything ;-) */
			break;
		case Opt_iocharset:
			if (nls_map && nls_map != (void *) -1)
				unload_nls(nls_map);
			if (!strcmp(args[0].from, "none"))
				nls_map = NULL;
			else {
				nls_map = load_nls(args[0].from);
				if (!nls_map) {
270
					pr_err("JFS: charset not found\n");
Linus Torvalds's avatar
Linus Torvalds committed
271 272 273 274 275 276 277
					goto cleanup;
				}
			}
			break;
		case Opt_resize:
		{
			char *resize = args[0].from;
278 279 280 281
			int rc = kstrtoll(resize, 0, newLVSize);

			if (rc)
				goto cleanup;
Linus Torvalds's avatar
Linus Torvalds committed
282 283 284 285 286 287 288
			break;
		}
		case Opt_resize_nosize:
		{
			*newLVSize = sb->s_bdev->bd_inode->i_size >>
				sb->s_blocksize_bits;
			if (*newLVSize == 0)
289
				pr_err("JFS: Cannot determine volume size\n");
Linus Torvalds's avatar
Linus Torvalds committed
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
			break;
		}
		case Opt_errors:
		{
			char *errors = args[0].from;
			if (!errors || !*errors)
				goto cleanup;
			if (!strcmp(errors, "continue")) {
				*flag &= ~JFS_ERR_REMOUNT_RO;
				*flag &= ~JFS_ERR_PANIC;
				*flag |= JFS_ERR_CONTINUE;
			} else if (!strcmp(errors, "remount-ro")) {
				*flag &= ~JFS_ERR_CONTINUE;
				*flag &= ~JFS_ERR_PANIC;
				*flag |= JFS_ERR_REMOUNT_RO;
			} else if (!strcmp(errors, "panic")) {
				*flag &= ~JFS_ERR_CONTINUE;
				*flag &= ~JFS_ERR_REMOUNT_RO;
				*flag |= JFS_ERR_PANIC;
			} else {
310
				pr_err("JFS: %s is an invalid error handler\n",
Linus Torvalds's avatar
Linus Torvalds committed
311 312 313 314 315
				       errors);
				goto cleanup;
			}
			break;
		}
316

317
#ifdef CONFIG_QUOTA
318 319 320 321 322 323 324 325 326 327 328
		case Opt_quota:
		case Opt_usrquota:
			*flag |= JFS_USRQUOTA;
			break;
		case Opt_grpquota:
			*flag |= JFS_GRPQUOTA;
			break;
#else
		case Opt_usrquota:
		case Opt_grpquota:
		case Opt_quota:
329
			pr_err("JFS: quota operations not supported\n");
330 331
			break;
#endif
332 333 334
		case Opt_uid:
		{
			char *uid = args[0].from;
335 336 337 338 339
			uid_t val;
			int rc = kstrtouint(uid, 0, &val);

			if (rc)
				goto cleanup;
340 341 342
			sbi->uid = make_kuid(current_user_ns(), val);
			if (!uid_valid(sbi->uid))
				goto cleanup;
343 344
			break;
		}
345

346 347 348
		case Opt_gid:
		{
			char *gid = args[0].from;
349 350 351 352 353
			gid_t val;
			int rc = kstrtouint(gid, 0, &val);

			if (rc)
				goto cleanup;
354 355 356
			sbi->gid = make_kgid(current_user_ns(), val);
			if (!gid_valid(sbi->gid))
				goto cleanup;
357 358
			break;
		}
359

360 361 362
		case Opt_umask:
		{
			char *umask = args[0].from;
363 364 365 366
			int rc = kstrtouint(umask, 8, &sbi->umask);

			if (rc)
				goto cleanup;
367
			if (sbi->umask & ~0777) {
368
				pr_err("JFS: Invalid value of umask\n");
369 370 371 372
				goto cleanup;
			}
			break;
		}
373 374 375 376 377 378 379 380 381

		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;
382
			if (blk_queue_discard(q))
383
				*flag |= JFS_DISCARD;
384 385
			else
				pr_err("JFS: discard option not supported on device\n");
386 387 388 389 390 391 392 393 394 395 396
			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;
397
			int rc;
398 399
			if (blk_queue_discard(q)) {
				*flag |= JFS_DISCARD;
400 401 402 403 404
				rc = kstrtouint(minblks_trim, 0,
						&sbi->minblks_trim);
				if (rc)
					goto cleanup;
			} else
405
				pr_err("JFS: discard option not supported on device\n");
406 407 408
			break;
		}

Linus Torvalds's avatar
Linus Torvalds committed
409
		default:
410 411
			printk("jfs: Unrecognized mount option \"%s\" or missing value\n",
			       p);
Linus Torvalds's avatar
Linus Torvalds committed
412 413 414 415 416 417
			goto cleanup;
		}
	}

	if (nls_map != (void *) -1) {
		/* Discard old (if remount) */
418
		unload_nls(sbi->nls_tab);
Linus Torvalds's avatar
Linus Torvalds committed
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
		sbi->nls_tab = nls_map;
	}
	return 1;

cleanup:
	if (nls_map && nls_map != (void *) -1)
		unload_nls(nls_map);
	return 0;
}

static int jfs_remount(struct super_block *sb, int *flags, char *data)
{
	s64 newLVSize = 0;
	int rc = 0;
	int flag = JFS_SBI(sb)->flag;
434
	int ret;
Linus Torvalds's avatar
Linus Torvalds committed
435

436
	sync_filesystem(sb);
437
	if (!parse_options(data, sb, &newLVSize, &flag))
Linus Torvalds's avatar
Linus Torvalds committed
438
		return -EINVAL;
Jan Blunck's avatar
Jan Blunck committed
439

Linus Torvalds's avatar
Linus Torvalds committed
440 441
	if (newLVSize) {
		if (sb->s_flags & MS_RDONLY) {
442
			pr_err("JFS: resize requires volume to be mounted read-write\n");
Linus Torvalds's avatar
Linus Torvalds committed
443 444 445
			return -EROFS;
		}
		rc = jfs_extendfs(sb, newLVSize, 0);
Jan Blunck's avatar
Jan Blunck committed
446
		if (rc)
Linus Torvalds's avatar
Linus Torvalds committed
447 448 449 450
			return rc;
	}

	if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) {
451 452 453 454 455 456
		/*
		 * Invalidate any previously read metadata.  fsck may have
		 * changed the on-disk data since we mounted r/o
		 */
		truncate_inode_pages(JFS_SBI(sb)->direct_inode->i_mapping, 0);

Linus Torvalds's avatar
Linus Torvalds committed
457
		JFS_SBI(sb)->flag = flag;
458
		ret = jfs_mount_rw(sb, 1);
459 460 461 462

		/* mark the fs r/w for quota activity */
		sb->s_flags &= ~MS_RDONLY;

463
		dquot_resume(sb, -1);
464
		return ret;
Linus Torvalds's avatar
Linus Torvalds committed
465 466
	}
	if ((!(sb->s_flags & MS_RDONLY)) && (*flags & MS_RDONLY)) {
467
		rc = dquot_suspend(sb, -1);
468
		if (rc < 0)
469
			return rc;
Linus Torvalds's avatar
Linus Torvalds committed
470 471 472 473 474 475 476
		rc = jfs_umount_rw(sb);
		JFS_SBI(sb)->flag = flag;
		return rc;
	}
	if ((JFS_SBI(sb)->flag & JFS_NOINTEGRITY) != (flag & JFS_NOINTEGRITY))
		if (!(sb->s_flags & MS_RDONLY)) {
			rc = jfs_umount_rw(sb);
Jan Blunck's avatar
Jan Blunck committed
477
			if (rc)
Linus Torvalds's avatar
Linus Torvalds committed
478
				return rc;
Jan Blunck's avatar
Jan Blunck committed
479

Linus Torvalds's avatar
Linus Torvalds committed
480
			JFS_SBI(sb)->flag = flag;
481 482
			ret = jfs_mount_rw(sb, 1);
			return ret;
Linus Torvalds's avatar
Linus Torvalds committed
483 484 485 486 487 488 489 490 491 492 493 494
		}
	JFS_SBI(sb)->flag = flag;

	return 0;
}

static int jfs_fill_super(struct super_block *sb, void *data, int silent)
{
	struct jfs_sb_info *sbi;
	struct inode *inode;
	int rc;
	s64 newLVSize = 0;
495
	int flag, ret = -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
496 497 498

	jfs_info("In jfs_read_super: s_flags=0x%lx", sb->s_flags);

499
	sbi = kzalloc(sizeof(struct jfs_sb_info), GFP_KERNEL);
Jan Blunck's avatar
Jan Blunck committed
500
	if (!sbi)
501
		return -ENOMEM;
Jan Blunck's avatar
Jan Blunck committed
502

Linus Torvalds's avatar
Linus Torvalds committed
503
	sb->s_fs_info = sbi;
504
	sb->s_max_links = JFS_LINK_MAX;
Linus Torvalds's avatar
Linus Torvalds committed
505
	sbi->sb = sb;
506 507 508
	sbi->uid = INVALID_UID;
	sbi->gid = INVALID_GID;
	sbi->umask = -1;
Linus Torvalds's avatar
Linus Torvalds committed
509 510 511 512

	/* initialize the mount flag and determine the default error handler */
	flag = JFS_ERR_REMOUNT_RO;

513 514
	if (!parse_options((char *) data, sb, &newLVSize, &flag))
		goto out_kfree;
Linus Torvalds's avatar
Linus Torvalds committed
515 516 517 518 519 520 521
	sbi->flag = flag;

#ifdef CONFIG_JFS_POSIX_ACL
	sb->s_flags |= MS_POSIXACL;
#endif

	if (newLVSize) {
522
		pr_err("resize option for remount only\n");
523
		goto out_kfree;
Linus Torvalds's avatar
Linus Torvalds committed
524 525 526 527 528 529 530 531 532 533 534 535
	}

	/*
	 * Initialize blocksize to 4K.
	 */
	sb_set_blocksize(sb, PSIZE);

	/*
	 * Set method vectors.
	 */
	sb->s_op = &jfs_super_operations;
	sb->s_export_op = &jfs_export_operations;
536
	sb->s_xattr = jfs_xattr_handlers;
537 538
#ifdef CONFIG_QUOTA
	sb->dq_op = &dquot_operations;
539
	sb->s_qcop = &dquot_quotactl_ops;
540
	sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP;
541
#endif
Linus Torvalds's avatar
Linus Torvalds committed
542

543 544 545 546
	/*
	 * Initialize direct-mapping inode/address-space
	 */
	inode = new_inode(sb);
547 548
	if (inode == NULL) {
		ret = -ENOMEM;
549
		goto out_unload;
550
	}
551 552 553
	inode->i_ino = 0;
	inode->i_size = sb->s_bdev->bd_inode->i_size;
	inode->i_mapping->a_ops = &jfs_metapage_aops;
Al Viro's avatar
Al Viro committed
554
	hlist_add_fake(&inode->i_hash);
555 556 557 558
	mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);

	sbi->direct_inode = inode;

Linus Torvalds's avatar
Linus Torvalds committed
559 560
	rc = jfs_mount(sb);
	if (rc) {
561
		if (!silent)
Linus Torvalds's avatar
Linus Torvalds committed
562
			jfs_err("jfs_mount failed w/return code = %d", rc);
563
		goto out_mount_failed;
Linus Torvalds's avatar
Linus Torvalds committed
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
	}
	if (sb->s_flags & MS_RDONLY)
		sbi->log = NULL;
	else {
		rc = jfs_mount_rw(sb, 0);
		if (rc) {
			if (!silent) {
				jfs_err("jfs_mount_rw failed, return code = %d",
					rc);
			}
			goto out_no_rw;
		}
	}

	sb->s_magic = JFS_SUPER_MAGIC;

580 581 582
	if (sbi->mntflag & JFS_OS2)
		sb->s_d_op = &jfs_ci_dentry_operations;

583 584 585
	inode = jfs_iget(sb, ROOT_I);
	if (IS_ERR(inode)) {
		ret = PTR_ERR(inode);
586
		goto out_no_rw;
587
	}
588
	sb->s_root = d_make_root(inode);
Linus Torvalds's avatar
Linus Torvalds committed
589 590 591 592 593 594 595 596 597 598
	if (!sb->s_root)
		goto out_no_root;

	/* logical blocks are represented by 40 bits in pxd_t, etc. */
	sb->s_maxbytes = ((u64) sb->s_blocksize) << 40;
#if BITS_PER_LONG == 32
	/*
	 * Page cache is indexed by long.
	 * I would use MAX_LFS_FILESIZE, but it's only half as big
	 */
599 600
	sb->s_maxbytes = min(((u64) PAGE_CACHE_SIZE << 32) - 1,
			     (u64)sb->s_maxbytes);
Linus Torvalds's avatar
Linus Torvalds committed
601 602 603 604 605
#endif
	sb->s_time_gran = 1;
	return 0;

out_no_root:
606
	jfs_err("jfs_read_super: get root dentry failed");
Linus Torvalds's avatar
Linus Torvalds committed
607 608 609

out_no_rw:
	rc = jfs_umount(sb);
610
	if (rc)
Linus Torvalds's avatar
Linus Torvalds committed
611
		jfs_err("jfs_umount failed with return code %d", rc);
612
out_mount_failed:
613
	filemap_write_and_wait(sbi->direct_inode->i_mapping);
614 615 616 617
	truncate_inode_pages(sbi->direct_inode->i_mapping, 0);
	make_bad_inode(sbi->direct_inode);
	iput(sbi->direct_inode);
	sbi->direct_inode = NULL;
618
out_unload:
619
	unload_nls(sbi->nls_tab);
620
out_kfree:
Linus Torvalds's avatar
Linus Torvalds committed
621
	kfree(sbi);
622
	return ret;
Linus Torvalds's avatar
Linus Torvalds committed
623 624
}

625
static int jfs_freeze(struct super_block *sb)
Linus Torvalds's avatar
Linus Torvalds committed
626 627 628
{
	struct jfs_sb_info *sbi = JFS_SBI(sb);
	struct jfs_log *log = sbi->log;
629
	int rc = 0;
Linus Torvalds's avatar
Linus Torvalds committed
630 631 632

	if (!(sb->s_flags & MS_RDONLY)) {
		txQuiesce(sb);
633 634
		rc = lmLogShutdown(log);
		if (rc) {
Joe Perches's avatar
Joe Perches committed
635
			jfs_error(sb, "lmLogShutdown failed\n");
636 637 638 639 640 641 642 643 644 645 646 647 648 649 650

			/* 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.
			 */
		}
Linus Torvalds's avatar
Linus Torvalds committed
651
	}
652
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
653 654
}

655
static int jfs_unfreeze(struct super_block *sb)
Linus Torvalds's avatar
Linus Torvalds committed
656 657 658 659 660 661
{
	struct jfs_sb_info *sbi = JFS_SBI(sb);
	struct jfs_log *log = sbi->log;
	int rc = 0;

	if (!(sb->s_flags & MS_RDONLY)) {
662 663
		rc = updateSuper(sb, FM_MOUNT);
		if (rc) {
Joe Perches's avatar
Joe Perches committed
664
			jfs_error(sb, "updateSuper failed\n");
665 666 667 668
			goto out;
		}
		rc = lmLogInit(log);
		if (rc)
Joe Perches's avatar
Joe Perches committed
669
			jfs_error(sb, "lmLogInit failed\n");
670 671
out:
		txResume(sb);
Linus Torvalds's avatar
Linus Torvalds committed
672
	}
673
	return rc;
Linus Torvalds's avatar
Linus Torvalds committed
674 675
}

Al Viro's avatar
Al Viro committed
676 677
static struct dentry *jfs_do_mount(struct file_system_type *fs_type,
	int flags, const char *dev_name, void *data)
Linus Torvalds's avatar
Linus Torvalds committed
678
{
Al Viro's avatar
Al Viro committed
679
	return mount_bdev(fs_type, flags, dev_name, data, jfs_fill_super);
Linus Torvalds's avatar
Linus Torvalds committed
680 681 682 683 684 685 686
}

static int jfs_sync_fs(struct super_block *sb, int wait)
{
	struct jfs_log *log = JFS_SBI(sb)->log;

	/* log == NULL indicates read-only mount */
687
	if (log) {
688 689 690 691 692
		/*
		 * Write quota structures to quota file, sync_blockdev() will
		 * write them to disk later
		 */
		dquot_writeback_dquots(sb, -1);
Linus Torvalds's avatar
Linus Torvalds committed
693
		jfs_flush_journal(log, wait);
694
		jfs_syncpt(log, 0);
695
	}
Linus Torvalds's avatar
Linus Torvalds committed
696 697 698 699

	return 0;
}

700
static int jfs_show_options(struct seq_file *seq, struct dentry *root)
701
{
702
	struct jfs_sb_info *sbi = JFS_SBI(root->d_sb);
703

704 705 706 707
	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));
708 709
	if (sbi->umask != -1)
		seq_printf(seq, ",umask=%03o", sbi->umask);
710 711
	if (sbi->flag & JFS_NOINTEGRITY)
		seq_puts(seq, ",nointegrity");
712 713
	if (sbi->flag & JFS_DISCARD)
		seq_printf(seq, ",discard=%u", sbi->minblks_trim);
Miklos Szeredi's avatar
Miklos Szeredi committed
714 715 716 717 718 719
	if (sbi->nls_tab)
		seq_printf(seq, ",iocharset=%s", sbi->nls_tab->charset);
	if (sbi->flag & JFS_ERR_CONTINUE)
		seq_printf(seq, ",errors=continue");
	if (sbi->flag & JFS_ERR_PANIC)
		seq_printf(seq, ",errors=panic");
720

721
#ifdef CONFIG_QUOTA
722 723 724 725 726 727 728 729 730 731
	if (sbi->flag & JFS_USRQUOTA)
		seq_puts(seq, ",usrquota");

	if (sbi->flag & JFS_GRPQUOTA)
		seq_puts(seq, ",grpquota");
#endif

	return 0;
}

732 733 734 735
#ifdef CONFIG_QUOTA

/* Read data from quotafile - avoid pagecache and such because we cannot afford
 * acquiring the locks... As quota files are never truncated and quota code
Lucas De Marchi's avatar
Lucas De Marchi committed
736
 * itself serializes the operations (and no one else should touch the files)
737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800
 * 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)
{
	struct inode *inode = sb_dqopt(sb)->files[type];
	sector_t blk = off >> sb->s_blocksize_bits;
	int err = 0;
	int offset = off & (sb->s_blocksize - 1);
	int tocopy;
	size_t toread;
	struct buffer_head tmp_bh;
	struct buffer_head *bh;
	loff_t i_size = i_size_read(inode);

	if (off > i_size)
		return 0;
	if (off+len > i_size)
		len = i_size-off;
	toread = len;
	while (toread > 0) {
		tocopy = sb->s_blocksize - offset < toread ?
				sb->s_blocksize - offset : toread;

		tmp_bh.b_state = 0;
		tmp_bh.b_size = 1 << inode->i_blkbits;
		err = jfs_get_block(inode, blk, &tmp_bh, 0);
		if (err)
			return err;
		if (!buffer_mapped(&tmp_bh))	/* A hole? */
			memset(data, 0, tocopy);
		else {
			bh = sb_bread(sb, tmp_bh.b_blocknr);
			if (!bh)
				return -EIO;
			memcpy(data, bh->b_data+offset, tocopy);
			brelse(bh);
		}
		offset = 0;
		toread -= tocopy;
		data += tocopy;
		blk++;
	}
	return len;
}

/* Write to quotafile */
static ssize_t jfs_quota_write(struct super_block *sb, int type,
			       const char *data, size_t len, loff_t off)
{
	struct inode *inode = sb_dqopt(sb)->files[type];
	sector_t blk = off >> sb->s_blocksize_bits;
	int err = 0;
	int offset = off & (sb->s_blocksize - 1);
	int tocopy;
	size_t towrite = len;
	struct buffer_head tmp_bh;
	struct buffer_head *bh;

	mutex_lock(&inode->i_mutex);
	while (towrite > 0) {
		tocopy = sb->s_blocksize - offset < towrite ?
				sb->s_blocksize - offset : towrite;

		tmp_bh.b_state = 0;
801
		tmp_bh.b_size = 1 << inode->i_blkbits;
802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825
		err = jfs_get_block(inode, blk, &tmp_bh, 1);
		if (err)
			goto out;
		if (offset || tocopy != sb->s_blocksize)
			bh = sb_bread(sb, tmp_bh.b_blocknr);
		else
			bh = sb_getblk(sb, tmp_bh.b_blocknr);
		if (!bh) {
			err = -EIO;
			goto out;
		}
		lock_buffer(bh);
		memcpy(bh->b_data+offset, data, tocopy);
		flush_dcache_page(bh->b_page);
		set_buffer_uptodate(bh);
		mark_buffer_dirty(bh);
		unlock_buffer(bh);
		brelse(bh);
		offset = 0;
		towrite -= tocopy;
		data += tocopy;
		blk++;
	}
out:
826 827
	if (len == towrite) {
		mutex_unlock(&inode->i_mutex);
828
		return err;
829
	}
830 831 832 833 834 835 836 837 838
	if (inode->i_size < off+len-towrite)
		i_size_write(inode, off+len-towrite);
	inode->i_version++;
	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
	mark_inode_dirty(inode);
	mutex_unlock(&inode->i_mutex);
	return len - towrite;
}

839 840 841 842
static struct dquot **jfs_get_dquots(struct inode *inode)
{
	return JFS_IP(inode)->i_dquot;
}
843 844
#endif

845
static const struct super_operations jfs_super_operations = {
Linus Torvalds's avatar
Linus Torvalds committed
846 847 848 849
	.alloc_inode	= jfs_alloc_inode,
	.destroy_inode	= jfs_destroy_inode,
	.dirty_inode	= jfs_dirty_inode,
	.write_inode	= jfs_write_inode,
Al Viro's avatar
Al Viro committed
850
	.evict_inode	= jfs_evict_inode,
Linus Torvalds's avatar
Linus Torvalds committed
851 852
	.put_super	= jfs_put_super,
	.sync_fs	= jfs_sync_fs,
853 854
	.freeze_fs	= jfs_freeze,
	.unfreeze_fs	= jfs_unfreeze,
Linus Torvalds's avatar
Linus Torvalds committed
855 856
	.statfs		= jfs_statfs,
	.remount_fs	= jfs_remount,
857 858 859 860
	.show_options	= jfs_show_options,
#ifdef CONFIG_QUOTA
	.quota_read	= jfs_quota_read,
	.quota_write	= jfs_quota_write,
861
	.get_dquots	= jfs_get_dquots,
862
#endif
Linus Torvalds's avatar
Linus Torvalds committed
863 864
};

865
static const struct export_operations jfs_export_operations = {
Christoph Hellwig's avatar
Christoph Hellwig committed
866 867
	.fh_to_dentry	= jfs_fh_to_dentry,
	.fh_to_parent	= jfs_fh_to_parent,
Linus Torvalds's avatar
Linus Torvalds committed
868 869 870 871 872 873
	.get_parent	= jfs_get_parent,
};

static struct file_system_type jfs_fs_type = {
	.owner		= THIS_MODULE,
	.name		= "jfs",
Al Viro's avatar
Al Viro committed
874
	.mount		= jfs_do_mount,
Linus Torvalds's avatar
Linus Torvalds committed
875 876 877
	.kill_sb	= kill_block_super,
	.fs_flags	= FS_REQUIRES_DEV,
};
878
MODULE_ALIAS_FS("jfs");
Linus Torvalds's avatar
Linus Torvalds committed
879

880
static void init_once(void *foo)
Linus Torvalds's avatar
Linus Torvalds committed
881 882 883
{
	struct jfs_inode_info *jfs_ip = (struct jfs_inode_info *) foo;

884 885 886 887 888 889 890 891
	memset(jfs_ip, 0, sizeof(struct jfs_inode_info));
	INIT_LIST_HEAD(&jfs_ip->anon_inode_list);
	init_rwsem(&jfs_ip->rdwrlock);
	mutex_init(&jfs_ip->commit_mutex);
	init_rwsem(&jfs_ip->xattr_sem);
	spin_lock_init(&jfs_ip->ag_lock);
	jfs_ip->active_ag = -1;
	inode_init_once(&jfs_ip->vfs_inode);
Linus Torvalds's avatar
Linus Torvalds committed
892 893 894 895 896 897 898 899
}

static int __init init_jfs_fs(void)
{
	int i;
	int rc;

	jfs_inode_cachep =
Dave Kleikamp's avatar
Dave Kleikamp committed
900
	    kmem_cache_create("jfs_ip", sizeof(struct jfs_inode_info), 0,
901
			    SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
902
			    init_once);
Linus Torvalds's avatar
Linus Torvalds committed
903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926
	if (jfs_inode_cachep == NULL)
		return -ENOMEM;

	/*
	 * Metapage initialization
	 */
	rc = metapage_init();
	if (rc) {
		jfs_err("metapage_init failed w/rc = %d", rc);
		goto free_slab;
	}

	/*
	 * Transaction Manager initialization
	 */
	rc = txInit();
	if (rc) {
		jfs_err("txInit failed w/rc = %d", rc);
		goto free_metapage;
	}

	/*
	 * I/O completion thread (endio)
	 */
927 928 929 930
	jfsIOthread = kthread_run(jfsIOWait, NULL, "jfsIO");
	if (IS_ERR(jfsIOthread)) {
		rc = PTR_ERR(jfsIOthread);
		jfs_err("init_jfs_fs: fork failed w/rc = %d", rc);
Linus Torvalds's avatar
Linus Torvalds committed
931 932 933 934 935 936 937 938 939
		goto end_txmngr;
	}

	if (commit_threads < 1)
		commit_threads = num_online_cpus();
	if (commit_threads > MAX_COMMIT_THREADS)
		commit_threads = MAX_COMMIT_THREADS;

	for (i = 0; i < commit_threads; i++) {
940 941
		jfsCommitThread[i] = kthread_run(jfs_lazycommit, NULL,
						 "jfsCommit");
942 943 944
		if (IS_ERR(jfsCommitThread[i])) {
			rc = PTR_ERR(jfsCommitThread[i]);
			jfs_err("init_jfs_fs: fork failed w/rc = %d", rc);
Linus Torvalds's avatar
Linus Torvalds committed
945 946 947 948 949
			commit_threads = i;
			goto kill_committask;
		}
	}

950 951 952 953
	jfsSyncThread = kthread_run(jfs_sync, NULL, "jfsSync");
	if (IS_ERR(jfsSyncThread)) {
		rc = PTR_ERR(jfsSyncThread);
		jfs_err("init_jfs_fs: fork failed w/rc = %d", rc);
Linus Torvalds's avatar
Linus Torvalds committed
954 955 956 957 958 959 960
		goto kill_committask;
	}

#ifdef PROC_FS_JFS
	jfs_proc_init();
#endif

961 962 963
	rc = register_filesystem(&jfs_fs_type);
	if (!rc)
		return 0;
Linus Torvalds's avatar
Linus Torvalds committed
964

965 966 967 968
#ifdef PROC_FS_JFS
	jfs_proc_clean();
#endif
	kthread_stop(jfsSyncThread);
Linus Torvalds's avatar
Linus Torvalds committed
969 970
kill_committask:
	for (i = 0; i < commit_threads; i++)
971 972
		kthread_stop(jfsCommitThread[i]);
	kthread_stop(jfsIOthread);
Linus Torvalds's avatar
Linus Torvalds committed
973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989
end_txmngr:
	txExit();
free_metapage:
	metapage_exit();
free_slab:
	kmem_cache_destroy(jfs_inode_cachep);
	return rc;
}

static void __exit exit_jfs_fs(void)
{
	int i;

	jfs_info("exit_jfs_fs called");

	txExit();
	metapage_exit();
990 991

	kthread_stop(jfsIOthread);
Linus Torvalds's avatar
Linus Torvalds committed
992
	for (i = 0; i < commit_threads; i++)
993 994
		kthread_stop(jfsCommitThread[i]);
	kthread_stop(jfsSyncThread);
Linus Torvalds's avatar
Linus Torvalds committed
995 996 997 998
#ifdef PROC_FS_JFS
	jfs_proc_clean();
#endif
	unregister_filesystem(&jfs_fs_type);
999 1000 1001 1002 1003 1004

	/*
	 * Make sure all delayed rcu free inodes are flushed before we
	 * destroy cache.
	 */
	rcu_barrier();
Linus Torvalds's avatar
Linus Torvalds committed
1005 1006 1007 1008 1009
	kmem_cache_destroy(jfs_inode_cachep);
}

module_init(init_jfs_fs)
module_exit(exit_jfs_fs)