super.c 22.5 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>
Christoph Hellwig's avatar
Christoph Hellwig committed
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
47
48
49
50
51
#include "jfs_metapage.h"
#include "jfs_superblock.h"
#include "jfs_dmap.h"
#include "jfs_imap.h"
#include "jfs_acl.h"
#include "jfs_debug.h"

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

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

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

#define MAX_COMMIT_THREADS 64
static int commit_threads = 0;
module_param(commit_threads, int, 0);
MODULE_PARM_DESC(commit_threads, "Number of commit threads");

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

#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) {
		jfs_err("ERROR: (device %s): remounting filesystem "
			"as read-only\n",
			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
95
96
97
98
99
100

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

void jfs_error(struct super_block *sb, const char * function, ...)
{
	static char error_buf[256];
	va_list args;

	va_start(args, function);
101
	vsnprintf(error_buf, sizeof(error_buf), function, args);
Linus Torvalds's avatar
Linus Torvalds committed
102
103
	va_end(args);

104
	pr_err("ERROR: (device %s): %s\n", sb->s_id, error_buf);
Linus Torvalds's avatar
Linus Torvalds committed
105
106
107
108
109
110
111
112
113
114
115
116
117
118

	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;
	return &jfs_inode->vfs_inode;
}

Nick Piggin's avatar
Nick Piggin committed
119
120
121
122
123
124
125
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
126
127
128
129
static void jfs_destroy_inode(struct inode *inode)
{
	struct jfs_inode_info *ji = JFS_IP(inode);

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

Linus Torvalds's avatar
Linus Torvalds committed
132
133
134
135
136
137
138
	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
139
	call_rcu(&inode->i_rcu, jfs_i_callback);
Linus Torvalds's avatar
Linus Torvalds committed
140
141
}

142
static int jfs_statfs(struct dentry *dentry, struct kstatfs *buf)
Linus Torvalds's avatar
Linus Torvalds committed
143
{
144
	struct jfs_sb_info *sbi = JFS_SBI(dentry->d_sb);
Linus Torvalds's avatar
Linus Torvalds committed
145
146
147
148
149
150
151
152
153
154
155
156
	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.
157
	 * We'll try to calculate some guess as to how many inodes we can
Linus Torvalds's avatar
Linus Torvalds committed
158
159
160
161
162
163
164
165
166
167
168
	 * 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
169
170
171
	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
172
173
174
175
176
177
178
179
180
181
182

	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");
183

184
185
	dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);

Linus Torvalds's avatar
Linus Torvalds committed
186
187
188
	rc = jfs_umount(sb);
	if (rc)
		jfs_err("jfs_umount failed with return code %d", rc);
189
190

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

192
193
194
	truncate_inode_pages(sbi->direct_inode->i_mapping, 0);
	iput(sbi->direct_inode);

Linus Torvalds's avatar
Linus Torvalds committed
195
196
197
198
199
	kfree(sbi);
}

enum {
	Opt_integrity, Opt_nointegrity, Opt_iocharset, Opt_resize,
200
	Opt_resize_nosize, Opt_errors, Opt_ignore, Opt_err, Opt_quota,
201
202
	Opt_usrquota, Opt_grpquota, Opt_uid, Opt_gid, Opt_umask,
	Opt_discard, Opt_nodiscard, Opt_discard_minblk
Linus Torvalds's avatar
Linus Torvalds committed
203
204
};

205
static const match_table_t tokens = {
Linus Torvalds's avatar
Linus Torvalds committed
206
207
208
209
210
211
212
213
	{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"},
214
215
	{Opt_usrquota, "usrquota"},
	{Opt_grpquota, "grpquota"},
216
217
218
	{Opt_uid, "uid=%u"},
	{Opt_gid, "gid=%u"},
	{Opt_umask, "umask=%u"},
219
220
221
	{Opt_discard, "discard"},
	{Opt_nodiscard, "nodiscard"},
	{Opt_discard_minblk, "discard=%u"},
Linus Torvalds's avatar
Linus Torvalds committed
222
223
224
225
226
227
228
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
	{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) {
263
					pr_err("JFS: charset not found\n");
Linus Torvalds's avatar
Linus Torvalds committed
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
					goto cleanup;
				}
			}
			break;
		case Opt_resize:
		{
			char *resize = args[0].from;
			*newLVSize = simple_strtoull(resize, &resize, 0);
			break;
		}
		case Opt_resize_nosize:
		{
			*newLVSize = sb->s_bdev->bd_inode->i_size >>
				sb->s_blocksize_bits;
			if (*newLVSize == 0)
279
				pr_err("JFS: Cannot determine volume size\n");
Linus Torvalds's avatar
Linus Torvalds committed
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
			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 {
300
				pr_err("JFS: %s is an invalid error handler\n",
Linus Torvalds's avatar
Linus Torvalds committed
301
302
303
304
305
				       errors);
				goto cleanup;
			}
			break;
		}
306

307
#ifdef CONFIG_QUOTA
308
309
310
311
312
313
314
315
316
317
318
		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:
319
			pr_err("JFS: quota operations not supported\n");
320
321
			break;
#endif
322
323
324
		case Opt_uid:
		{
			char *uid = args[0].from;
325
326
327
328
			uid_t val = simple_strtoul(uid, &uid, 0);
			sbi->uid = make_kuid(current_user_ns(), val);
			if (!uid_valid(sbi->uid))
				goto cleanup;
329
330
			break;
		}
331

332
333
334
		case Opt_gid:
		{
			char *gid = args[0].from;
335
336
337
338
			gid_t val = simple_strtoul(gid, &gid, 0);
			sbi->gid = make_kgid(current_user_ns(), val);
			if (!gid_valid(sbi->gid))
				goto cleanup;
339
340
			break;
		}
341

342
343
344
345
346
		case Opt_umask:
		{
			char *umask = args[0].from;
			sbi->umask = simple_strtoul(umask, &umask, 8);
			if (sbi->umask & ~0777) {
347
				pr_err("JFS: Invalid value of umask\n");
348
349
350
351
				goto cleanup;
			}
			break;
		}
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388

		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;
			if (blk_queue_discard(q)) {
				*flag |= JFS_DISCARD;
				sbi->minblks_trim = simple_strtoull(
					minblks_trim, &minblks_trim, 0);
			} else {
				pr_err("JFS: discard option " \
					"not supported on device\n");
			}
			break;
		}

Linus Torvalds's avatar
Linus Torvalds committed
389
390
391
392
393
394
395
396
397
		default:
			printk("jfs: Unrecognized mount option \"%s\" "
					" or missing value\n", p);
			goto cleanup;
		}
	}

	if (nls_map != (void *) -1) {
		/* Discard old (if remount) */
398
		unload_nls(sbi->nls_tab);
Linus Torvalds's avatar
Linus Torvalds committed
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
		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;
414
	int ret;
Linus Torvalds's avatar
Linus Torvalds committed
415
416
417
418

	if (!parse_options(data, sb, &newLVSize, &flag)) {
		return -EINVAL;
	}
Jan Blunck's avatar
Jan Blunck committed
419

Linus Torvalds's avatar
Linus Torvalds committed
420
421
	if (newLVSize) {
		if (sb->s_flags & MS_RDONLY) {
422
423
			pr_err("JFS: resize requires volume" \
				" to be mounted read-write\n");
Linus Torvalds's avatar
Linus Torvalds committed
424
425
426
			return -EROFS;
		}
		rc = jfs_extendfs(sb, newLVSize, 0);
Jan Blunck's avatar
Jan Blunck committed
427
		if (rc)
Linus Torvalds's avatar
Linus Torvalds committed
428
429
430
431
			return rc;
	}

	if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) {
432
433
434
435
436
437
		/*
		 * 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
438
		JFS_SBI(sb)->flag = flag;
439
		ret = jfs_mount_rw(sb, 1);
440
441
442
443

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

444
		dquot_resume(sb, -1);
445
		return ret;
Linus Torvalds's avatar
Linus Torvalds committed
446
447
	}
	if ((!(sb->s_flags & MS_RDONLY)) && (*flags & MS_RDONLY)) {
448
449
450
		rc = dquot_suspend(sb, -1);
		if (rc < 0) {
			return rc;
451
		}
Linus Torvalds's avatar
Linus Torvalds committed
452
453
454
455
456
457
458
		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
459
			if (rc)
Linus Torvalds's avatar
Linus Torvalds committed
460
				return rc;
Jan Blunck's avatar
Jan Blunck committed
461

Linus Torvalds's avatar
Linus Torvalds committed
462
			JFS_SBI(sb)->flag = flag;
463
464
			ret = jfs_mount_rw(sb, 1);
			return ret;
Linus Torvalds's avatar
Linus Torvalds committed
465
466
467
468
469
470
471
472
473
474
475
476
		}
	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;
477
	int flag, ret = -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
478
479
480

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

Jan Blunck's avatar
Jan Blunck committed
481
	if (!new_valid_dev(sb->s_bdev->bd_dev))
Linus Torvalds's avatar
Linus Torvalds committed
482
483
		return -EOVERFLOW;

Eric Sesterhenn's avatar
Eric Sesterhenn committed
484
	sbi = kzalloc(sizeof (struct jfs_sb_info), GFP_KERNEL);
Jan Blunck's avatar
Jan Blunck committed
485
	if (!sbi)
486
		return -ENOMEM;
Jan Blunck's avatar
Jan Blunck committed
487

Linus Torvalds's avatar
Linus Torvalds committed
488
	sb->s_fs_info = sbi;
489
	sb->s_max_links = JFS_LINK_MAX;
Linus Torvalds's avatar
Linus Torvalds committed
490
	sbi->sb = sb;
491
492
493
	sbi->uid = INVALID_UID;
	sbi->gid = INVALID_GID;
	sbi->umask = -1;
Linus Torvalds's avatar
Linus Torvalds committed
494
495
496
497

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

498
499
	if (!parse_options((char *) data, sb, &newLVSize, &flag))
		goto out_kfree;
Linus Torvalds's avatar
Linus Torvalds committed
500
501
502
503
504
505
506
	sbi->flag = flag;

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

	if (newLVSize) {
507
		pr_err("resize option for remount only\n");
508
		goto out_kfree;
Linus Torvalds's avatar
Linus Torvalds committed
509
510
511
512
513
514
515
516
517
518
519
520
	}

	/*
	 * 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;
521
522
#ifdef CONFIG_QUOTA
	sb->dq_op = &dquot_operations;
523
	sb->s_qcop = &dquot_quotactl_ops;
524
#endif
Linus Torvalds's avatar
Linus Torvalds committed
525

526
527
528
529
	/*
	 * Initialize direct-mapping inode/address-space
	 */
	inode = new_inode(sb);
530
531
	if (inode == NULL) {
		ret = -ENOMEM;
532
		goto out_unload;
533
	}
534
535
536
	inode->i_ino = 0;
	inode->i_size = sb->s_bdev->bd_inode->i_size;
	inode->i_mapping->a_ops = &jfs_metapage_aops;
537
	insert_inode_hash(inode);
538
539
540
541
	mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);

	sbi->direct_inode = inode;

Linus Torvalds's avatar
Linus Torvalds committed
542
543
544
545
546
	rc = jfs_mount(sb);
	if (rc) {
		if (!silent) {
			jfs_err("jfs_mount failed w/return code = %d", rc);
		}
547
		goto out_mount_failed;
Linus Torvalds's avatar
Linus Torvalds committed
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
	}
	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;

564
565
566
	if (sbi->mntflag & JFS_OS2)
		sb->s_d_op = &jfs_ci_dentry_operations;

567
568
569
	inode = jfs_iget(sb, ROOT_I);
	if (IS_ERR(inode)) {
		ret = PTR_ERR(inode);
570
		goto out_no_rw;
571
	}
572
	sb->s_root = d_make_root(inode);
Linus Torvalds's avatar
Linus Torvalds committed
573
574
575
576
577
578
579
580
581
582
	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
	 */
Alan Cox's avatar
Alan Cox committed
583
	sb->s_maxbytes = min(((u64) PAGE_CACHE_SIZE << 32) - 1, (u64)sb->s_maxbytes);
Linus Torvalds's avatar
Linus Torvalds committed
584
585
586
587
588
#endif
	sb->s_time_gran = 1;
	return 0;

out_no_root:
589
	jfs_err("jfs_read_super: get root dentry failed");
Linus Torvalds's avatar
Linus Torvalds committed
590
591
592
593
594
595

out_no_rw:
	rc = jfs_umount(sb);
	if (rc) {
		jfs_err("jfs_umount failed with return code %d", rc);
	}
596
out_mount_failed:
597
	filemap_write_and_wait(sbi->direct_inode->i_mapping);
598
599
600
601
	truncate_inode_pages(sbi->direct_inode->i_mapping, 0);
	make_bad_inode(sbi->direct_inode);
	iput(sbi->direct_inode);
	sbi->direct_inode = NULL;
602
out_unload:
Linus Torvalds's avatar
Linus Torvalds committed
603
604
	if (sbi->nls_tab)
		unload_nls(sbi->nls_tab);
605
out_kfree:
Linus Torvalds's avatar
Linus Torvalds committed
606
	kfree(sbi);
607
	return ret;
Linus Torvalds's avatar
Linus Torvalds committed
608
609
}

610
static int jfs_freeze(struct super_block *sb)
Linus Torvalds's avatar
Linus Torvalds committed
611
612
613
614
615
616
617
618
619
{
	struct jfs_sb_info *sbi = JFS_SBI(sb);
	struct jfs_log *log = sbi->log;

	if (!(sb->s_flags & MS_RDONLY)) {
		txQuiesce(sb);
		lmLogShutdown(log);
		updateSuper(sb, FM_CLEAN);
	}
620
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
621
622
}

623
static int jfs_unfreeze(struct super_block *sb)
Linus Torvalds's avatar
Linus Torvalds committed
624
625
626
627
628
629
630
631
632
633
634
635
{
	struct jfs_sb_info *sbi = JFS_SBI(sb);
	struct jfs_log *log = sbi->log;
	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);
	}
636
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
637
638
}

Al Viro's avatar
Al Viro committed
639
640
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
641
{
Al Viro's avatar
Al Viro committed
642
	return mount_bdev(fs_type, flags, dev_name, data, jfs_fill_super);
Linus Torvalds's avatar
Linus Torvalds committed
643
644
645
646
647
648
649
}

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 */
650
	if (log) {
651
652
653
654
655
		/*
		 * 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
656
		jfs_flush_journal(log, wait);
657
		jfs_syncpt(log, 0);
658
	}
Linus Torvalds's avatar
Linus Torvalds committed
659
660
661
662

	return 0;
}

663
static int jfs_show_options(struct seq_file *seq, struct dentry *root)
664
{
665
	struct jfs_sb_info *sbi = JFS_SBI(root->d_sb);
666

667
668
669
670
	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));
671
672
	if (sbi->umask != -1)
		seq_printf(seq, ",umask=%03o", sbi->umask);
673
674
	if (sbi->flag & JFS_NOINTEGRITY)
		seq_puts(seq, ",nointegrity");
675
676
	if (sbi->flag & JFS_DISCARD)
		seq_printf(seq, ",discard=%u", sbi->minblks_trim);
Miklos Szeredi's avatar
Miklos Szeredi committed
677
678
679
680
681
682
	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");
683

684
#ifdef CONFIG_QUOTA
685
686
687
688
689
690
691
692
693
694
	if (sbi->flag & JFS_USRQUOTA)
		seq_puts(seq, ",usrquota");

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

	return 0;
}

695
696
697
698
#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
699
 * itself serializes the operations (and no one else should touch the files)
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
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
 * 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;
764
		tmp_bh.b_size = 1 << inode->i_blkbits;
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
		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:
789
790
	if (len == towrite) {
		mutex_unlock(&inode->i_mutex);
791
		return err;
792
	}
793
794
795
796
797
798
799
800
801
802
803
	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;
}

#endif

804
static const struct super_operations jfs_super_operations = {
Linus Torvalds's avatar
Linus Torvalds committed
805
806
807
808
	.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
809
	.evict_inode	= jfs_evict_inode,
Linus Torvalds's avatar
Linus Torvalds committed
810
811
	.put_super	= jfs_put_super,
	.sync_fs	= jfs_sync_fs,
812
813
	.freeze_fs	= jfs_freeze,
	.unfreeze_fs	= jfs_unfreeze,
Linus Torvalds's avatar
Linus Torvalds committed
814
815
	.statfs		= jfs_statfs,
	.remount_fs	= jfs_remount,
816
817
818
819
820
	.show_options	= jfs_show_options,
#ifdef CONFIG_QUOTA
	.quota_read	= jfs_quota_read,
	.quota_write	= jfs_quota_write,
#endif
Linus Torvalds's avatar
Linus Torvalds committed
821
822
};

823
static const struct export_operations jfs_export_operations = {
Christoph Hellwig's avatar
Christoph Hellwig committed
824
825
	.fh_to_dentry	= jfs_fh_to_dentry,
	.fh_to_parent	= jfs_fh_to_parent,
Linus Torvalds's avatar
Linus Torvalds committed
826
827
828
829
830
831
	.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
832
	.mount		= jfs_do_mount,
Linus Torvalds's avatar
Linus Torvalds committed
833
834
835
836
	.kill_sb	= kill_block_super,
	.fs_flags	= FS_REQUIRES_DEV,
};

837
static void init_once(void *foo)
Linus Torvalds's avatar
Linus Torvalds committed
838
839
840
{
	struct jfs_inode_info *jfs_ip = (struct jfs_inode_info *) foo;

841
842
843
844
845
846
847
848
	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
849
850
851
852
853
854
855
856
}

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

	jfs_inode_cachep =
Dave Kleikamp's avatar
Dave Kleikamp committed
857
	    kmem_cache_create("jfs_ip", sizeof(struct jfs_inode_info), 0,
858
			    SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
859
			    init_once);
Linus Torvalds's avatar
Linus Torvalds committed
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
	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)
	 */
Christoph Hellwig's avatar
Christoph Hellwig committed
884
885
886
887
	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
888
889
890
891
892
893
894
895
896
		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++) {
Christoph Hellwig's avatar
Christoph Hellwig committed
897
898
899
900
		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);
Linus Torvalds's avatar
Linus Torvalds committed
901
902
903
904
905
			commit_threads = i;
			goto kill_committask;
		}
	}

Christoph Hellwig's avatar
Christoph Hellwig committed
906
907
908
909
	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
910
911
912
913
914
915
916
		goto kill_committask;
	}

#ifdef PROC_FS_JFS
	jfs_proc_init();
#endif

917
918
919
	rc = register_filesystem(&jfs_fs_type);
	if (!rc)
		return 0;
Linus Torvalds's avatar
Linus Torvalds committed
920

921
922
923
924
#ifdef PROC_FS_JFS
	jfs_proc_clean();
#endif
	kthread_stop(jfsSyncThread);
Linus Torvalds's avatar
Linus Torvalds committed
925
926
kill_committask:
	for (i = 0; i < commit_threads; i++)
Christoph Hellwig's avatar
Christoph Hellwig committed
927
928
		kthread_stop(jfsCommitThread[i]);
	kthread_stop(jfsIOthread);
Linus Torvalds's avatar
Linus Torvalds committed
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
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();
Christoph Hellwig's avatar
Christoph Hellwig committed
946
947

	kthread_stop(jfsIOthread);
Linus Torvalds's avatar
Linus Torvalds committed
948
	for (i = 0; i < commit_threads; i++)
Christoph Hellwig's avatar
Christoph Hellwig committed
949
950
		kthread_stop(jfsCommitThread[i]);
	kthread_stop(jfsSyncThread);
Linus Torvalds's avatar
Linus Torvalds committed
951
952
953
954
#ifdef PROC_FS_JFS
	jfs_proc_clean();
#endif
	unregister_filesystem(&jfs_fs_type);
955
956
957
958
959
960

	/*
	 * Make sure all delayed rcu free inodes are flushed before we
	 * destroy cache.
	 */
	rcu_barrier();
Linus Torvalds's avatar
Linus Torvalds committed
961
962
963
964
965
	kmem_cache_destroy(jfs_inode_cachep);
}

module_init(init_jfs_fs)
module_exit(exit_jfs_fs)