super.c 15.1 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 *  linux/fs/affs/inode.c
 *
 *  (c) 1996  Hans-Joachim Widmaier - Rewritten
 *
 *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
 *
 *  (C) 1992  Eric Youngdale Modified for ISO 9660 filesystem.
 *
 *  (C) 1991  Linus Torvalds - minix filesystem
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/statfs.h>
#include <linux/parser.h>
17
#include <linux/magic.h>
A
Alexey Dobriyan 已提交
18
#include <linux/sched.h>
19
#include <linux/slab.h>
20
#include <linux/writeback.h>
L
Linus Torvalds 已提交
21 22
#include "affs.h"

23
static int affs_statfs(struct dentry *dentry, struct kstatfs *buf);
L
Linus Torvalds 已提交
24 25
static int affs_remount (struct super_block *sb, int *flags, char *data);

C
Christoph Hellwig 已提交
26
static void
A
Artem Bityutskiy 已提交
27
affs_commit_super(struct super_block *sb, int wait)
C
Christoph Hellwig 已提交
28 29 30 31 32
{
	struct affs_sb_info *sbi = AFFS_SB(sb);
	struct buffer_head *bh = sbi->s_root_bh;
	struct affs_root_tail *tail = AFFS_ROOT_TAIL(sb, bh);

A
Artem Bityutskiy 已提交
33
	lock_buffer(bh);
C
Christoph Hellwig 已提交
34 35
	secs_to_datestamp(get_seconds(), &tail->disk_change);
	affs_fix_checksum(sb, bh);
A
Artem Bityutskiy 已提交
36 37
	unlock_buffer(bh);

C
Christoph Hellwig 已提交
38
	mark_buffer_dirty(bh);
39 40
	if (wait)
		sync_dirty_buffer(bh);
C
Christoph Hellwig 已提交
41 42
}

L
Linus Torvalds 已提交
43 44 45 46
static void
affs_put_super(struct super_block *sb)
{
	struct affs_sb_info *sbi = AFFS_SB(sb);
F
Fabian Frederick 已提交
47
	pr_debug("%s()\n", __func__);
L
Linus Torvalds 已提交
48

49
	cancel_delayed_work_sync(&sbi->sb_work);
L
Linus Torvalds 已提交
50 51
}

C
Christoph Hellwig 已提交
52 53 54
static int
affs_sync_fs(struct super_block *sb, int wait)
{
A
Artem Bityutskiy 已提交
55
	affs_commit_super(sb, wait);
C
Christoph Hellwig 已提交
56 57 58
	return 0;
}

59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
static void flush_superblock(struct work_struct *work)
{
	struct affs_sb_info *sbi;
	struct super_block *sb;

	sbi = container_of(work, struct affs_sb_info, sb_work.work);
	sb = sbi->sb;

	spin_lock(&sbi->work_lock);
	sbi->work_queued = 0;
	spin_unlock(&sbi->work_lock);

	affs_commit_super(sb, 1);
}

void affs_mark_sb_dirty(struct super_block *sb)
{
	struct affs_sb_info *sbi = AFFS_SB(sb);
	unsigned long delay;

	if (sb->s_flags & MS_RDONLY)
	       return;

	spin_lock(&sbi->work_lock);
	if (!sbi->work_queued) {
	       delay = msecs_to_jiffies(dirty_writeback_interval * 10);
	       queue_delayed_work(system_long_wq, &sbi->sb_work, delay);
	       sbi->work_queued = 1;
	}
	spin_unlock(&sbi->work_lock);
}

91
static struct kmem_cache * affs_inode_cachep;
L
Linus Torvalds 已提交
92 93 94

static struct inode *affs_alloc_inode(struct super_block *sb)
{
95 96 97 98
	struct affs_inode_info *i;

	i = kmem_cache_alloc(affs_inode_cachep, GFP_KERNEL);
	if (!i)
L
Linus Torvalds 已提交
99
		return NULL;
100 101 102 103 104 105 106

	i->vfs_inode.i_version = 1;
	i->i_lc = NULL;
	i->i_ext_bh = NULL;
	i->i_pa_cnt = 0;

	return &i->vfs_inode;
L
Linus Torvalds 已提交
107 108
}

N
Nick Piggin 已提交
109
static void affs_i_callback(struct rcu_head *head)
L
Linus Torvalds 已提交
110
{
N
Nick Piggin 已提交
111
	struct inode *inode = container_of(head, struct inode, i_rcu);
L
Linus Torvalds 已提交
112 113 114
	kmem_cache_free(affs_inode_cachep, AFFS_I(inode));
}

N
Nick Piggin 已提交
115 116 117 118 119
static void affs_destroy_inode(struct inode *inode)
{
	call_rcu(&inode->i_rcu, affs_i_callback);
}

120
static void init_once(void *foo)
L
Linus Torvalds 已提交
121 122 123
{
	struct affs_inode_info *ei = (struct affs_inode_info *) foo;

124 125
	sema_init(&ei->i_link_lock, 1);
	sema_init(&ei->i_ext_lock, 1);
C
Christoph Lameter 已提交
126
	inode_init_once(&ei->vfs_inode);
L
Linus Torvalds 已提交
127 128
}

129
static int __init init_inodecache(void)
L
Linus Torvalds 已提交
130 131 132
{
	affs_inode_cachep = kmem_cache_create("affs_inode_cache",
					     sizeof(struct affs_inode_info),
133 134
					     0, (SLAB_RECLAIM_ACCOUNT|
						SLAB_MEM_SPREAD),
135
					     init_once);
L
Linus Torvalds 已提交
136 137 138 139 140 141 142
	if (affs_inode_cachep == NULL)
		return -ENOMEM;
	return 0;
}

static void destroy_inodecache(void)
{
143 144 145 146 147
	/*
	 * Make sure all delayed rcu free inodes are flushed before we
	 * destroy cache.
	 */
	rcu_barrier();
148
	kmem_cache_destroy(affs_inode_cachep);
L
Linus Torvalds 已提交
149 150
}

151
static const struct super_operations affs_sops = {
L
Linus Torvalds 已提交
152 153 154
	.alloc_inode	= affs_alloc_inode,
	.destroy_inode	= affs_destroy_inode,
	.write_inode	= affs_write_inode,
A
Al Viro 已提交
155
	.evict_inode	= affs_evict_inode,
L
Linus Torvalds 已提交
156
	.put_super	= affs_put_super,
C
Christoph Hellwig 已提交
157
	.sync_fs	= affs_sync_fs,
L
Linus Torvalds 已提交
158 159
	.statfs		= affs_statfs,
	.remount_fs	= affs_remount,
M
Miklos Szeredi 已提交
160
	.show_options	= generic_show_options,
L
Linus Torvalds 已提交
161 162 163
};

enum {
164
	Opt_bs, Opt_mode, Opt_mufs, Opt_notruncate, Opt_prefix, Opt_protect,
L
Linus Torvalds 已提交
165 166 167 168
	Opt_reserved, Opt_root, Opt_setgid, Opt_setuid,
	Opt_verbose, Opt_volume, Opt_ignore, Opt_err,
};

169
static const match_table_t tokens = {
L
Linus Torvalds 已提交
170 171 172
	{Opt_bs, "bs=%u"},
	{Opt_mode, "mode=%o"},
	{Opt_mufs, "mufs"},
173
	{Opt_notruncate, "nofilenametruncate"},
L
Linus Torvalds 已提交
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
	{Opt_prefix, "prefix=%s"},
	{Opt_protect, "protect"},
	{Opt_reserved, "reserved=%u"},
	{Opt_root, "root=%u"},
	{Opt_setgid, "setgid=%u"},
	{Opt_setuid, "setuid=%u"},
	{Opt_verbose, "verbose"},
	{Opt_volume, "volume=%s"},
	{Opt_ignore, "grpquota"},
	{Opt_ignore, "noquota"},
	{Opt_ignore, "quota"},
	{Opt_ignore, "usrquota"},
	{Opt_err, NULL},
};

static int
190
parse_options(char *options, kuid_t *uid, kgid_t *gid, int *mode, int *reserved, s32 *root,
L
Linus Torvalds 已提交
191 192 193 194 195 196 197
		int *blocksize, char **prefix, char *volume, unsigned long *mount_opts)
{
	char *p;
	substring_t args[MAX_OPT_ARGS];

	/* Fill in defaults */

198 199
	*uid        = current_uid();
	*gid        = current_gid();
L
Linus Torvalds 已提交
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
	*reserved   = 2;
	*root       = -1;
	*blocksize  = -1;
	volume[0]   = ':';
	volume[1]   = 0;
	*mount_opts = 0;
	if (!options)
		return 1;

	while ((p = strsep(&options, ",")) != NULL) {
		int token, n, option;
		if (!*p)
			continue;

		token = match_token(p, tokens, args);
		switch (token) {
		case Opt_bs:
			if (match_int(&args[0], &n))
A
Al Viro 已提交
218
				return 0;
L
Linus Torvalds 已提交
219 220
			if (n != 512 && n != 1024 && n != 2048
			    && n != 4096) {
221
				pr_warn("Invalid blocksize (512, 1024, 2048, 4096 allowed)\n");
L
Linus Torvalds 已提交
222 223 224 225 226 227
				return 0;
			}
			*blocksize = n;
			break;
		case Opt_mode:
			if (match_octal(&args[0], &option))
A
Al Viro 已提交
228
				return 0;
L
Linus Torvalds 已提交
229 230 231 232 233 234
			*mode = option & 0777;
			*mount_opts |= SF_SETMODE;
			break;
		case Opt_mufs:
			*mount_opts |= SF_MUFS;
			break;
235 236 237
		case Opt_notruncate:
			*mount_opts |= SF_NO_TRUNCATE;
			break;
L
Linus Torvalds 已提交
238 239 240 241 242 243 244 245 246 247 248
		case Opt_prefix:
			*prefix = match_strdup(&args[0]);
			if (!*prefix)
				return 0;
			*mount_opts |= SF_PREFIX;
			break;
		case Opt_protect:
			*mount_opts |= SF_IMMUTABLE;
			break;
		case Opt_reserved:
			if (match_int(&args[0], reserved))
A
Al Viro 已提交
249
				return 0;
L
Linus Torvalds 已提交
250 251 252
			break;
		case Opt_root:
			if (match_int(&args[0], root))
A
Al Viro 已提交
253
				return 0;
L
Linus Torvalds 已提交
254 255 256
			break;
		case Opt_setgid:
			if (match_int(&args[0], &option))
A
Al Viro 已提交
257
				return 0;
258 259 260
			*gid = make_kgid(current_user_ns(), option);
			if (!gid_valid(*gid))
				return 0;
L
Linus Torvalds 已提交
261 262 263 264
			*mount_opts |= SF_SETGID;
			break;
		case Opt_setuid:
			if (match_int(&args[0], &option))
A
Al Viro 已提交
265
				return 0;
266 267 268
			*uid = make_kuid(current_user_ns(), option);
			if (!uid_valid(*uid))
				return 0;
L
Linus Torvalds 已提交
269 270 271 272 273 274 275
			*mount_opts |= SF_SETUID;
			break;
		case Opt_verbose:
			*mount_opts |= SF_VERBOSE;
			break;
		case Opt_volume: {
			char *vol = match_strdup(&args[0]);
J
Jim Meyering 已提交
276 277
			if (!vol)
				return 0;
L
Linus Torvalds 已提交
278 279 280 281 282 283 284 285
			strlcpy(volume, vol, 32);
			kfree(vol);
			break;
		}
		case Opt_ignore:
		 	/* Silently ignore the quota options */
			break;
		default:
286 287
			pr_warn("Unrecognized mount option \"%s\" or missing value\n",
				p);
L
Linus Torvalds 已提交
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
			return 0;
		}
	}
	return 1;
}

/* This function definitely needs to be split up. Some fine day I'll
 * hopefully have the guts to do so. Until then: sorry for the mess.
 */

static int affs_fill_super(struct super_block *sb, void *data, int silent)
{
	struct affs_sb_info	*sbi;
	struct buffer_head	*root_bh = NULL;
	struct buffer_head	*boot_bh;
	struct inode		*root_inode = NULL;
	s32			 root_block;
	int			 size, blocksize;
	u32			 chksum;
	int			 num_bm;
	int			 i, j;
309 310
	kuid_t			 uid;
	kgid_t			 gid;
L
Linus Torvalds 已提交
311 312 313
	int			 reserved;
	unsigned long		 mount_flags;
	int			 tmp_flags;	/* fix remount prototype... */
A
Al Viro 已提交
314
	u8			 sig[4];
315
	int			 ret;
L
Linus Torvalds 已提交
316

M
Miklos Szeredi 已提交
317 318
	save_mount_options(sb, data);

F
Fabian Frederick 已提交
319
	pr_debug("read_super(%s)\n", data ? (const char *)data : "no options");
L
Linus Torvalds 已提交
320 321 322 323 324

	sb->s_magic             = AFFS_SUPER_MAGIC;
	sb->s_op                = &affs_sops;
	sb->s_flags |= MS_NODIRATIME;

325
	sbi = kzalloc(sizeof(struct affs_sb_info), GFP_KERNEL);
L
Linus Torvalds 已提交
326 327
	if (!sbi)
		return -ENOMEM;
J
Jan Blunck 已提交
328

L
Linus Torvalds 已提交
329
	sb->s_fs_info = sbi;
330
	sbi->sb = sb;
331
	mutex_init(&sbi->s_bmlock);
332
	spin_lock_init(&sbi->symlink_lock);
333 334
	spin_lock_init(&sbi->work_lock);
	INIT_DELAYED_WORK(&sbi->sb_work, flush_superblock);
L
Linus Torvalds 已提交
335 336 337 338

	if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block,
				&blocksize,&sbi->s_prefix,
				sbi->s_volume, &mount_flags)) {
339
		pr_err("Error parsing options\n");
L
Linus Torvalds 已提交
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
		return -EINVAL;
	}
	/* N.B. after this point s_prefix must be released */

	sbi->s_flags   = mount_flags;
	sbi->s_mode    = i;
	sbi->s_uid     = uid;
	sbi->s_gid     = gid;
	sbi->s_reserved= reserved;

	/* Get the size of the device in 512-byte blocks.
	 * If we later see that the partition uses bigger
	 * blocks, we will have to change it.
	 */

	size = sb->s_bdev->bd_inode->i_size >> 9;
F
Fabian Frederick 已提交
356
	pr_debug("initial blocksize=%d, #blocks=%d\n", 512, size);
L
Linus Torvalds 已提交
357 358 359 360 361 362 363 364 365 366

	affs_set_blocksize(sb, PAGE_SIZE);
	/* Try to find root block. Its location depends on the block size. */

	i = 512;
	j = 4096;
	if (blocksize > 0) {
		i = j = blocksize;
		size = size / (blocksize / 512);
	}
367
	for (blocksize = i; blocksize <= j; blocksize <<= 1, size >>= 1) {
L
Linus Torvalds 已提交
368 369 370
		sbi->s_root_block = root_block;
		if (root_block < 0)
			sbi->s_root_block = (reserved + size - 1) / 2;
F
Fabian Frederick 已提交
371
		pr_debug("setting blocksize to %d\n", blocksize);
L
Linus Torvalds 已提交
372 373 374 375 376 377 378 379 380 381 382 383 384 385
		affs_set_blocksize(sb, blocksize);
		sbi->s_partition_size = size;

		/* The root block location that was calculated above is not
		 * correct if the partition size is an odd number of 512-
		 * byte blocks, which will be rounded down to a number of
		 * 1024-byte blocks, and if there were an even number of
		 * reserved blocks. Ideally, all partition checkers should
		 * report the real number of blocks of the real blocksize,
		 * but since this just cannot be done, we have to try to
		 * find the root block anyways. In the above case, it is one
		 * block behind the calculated one. So we check this one, too.
		 */
		for (num_bm = 0; num_bm < 2; num_bm++) {
F
Fabian Frederick 已提交
386
			pr_debug("Dev %s, trying root=%u, bs=%d, "
L
Linus Torvalds 已提交
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
				"size=%d, reserved=%d\n",
				sb->s_id,
				sbi->s_root_block + num_bm,
				blocksize, size, reserved);
			root_bh = affs_bread(sb, sbi->s_root_block + num_bm);
			if (!root_bh)
				continue;
			if (!affs_checksum_block(sb, root_bh) &&
			    be32_to_cpu(AFFS_ROOT_HEAD(root_bh)->ptype) == T_SHORT &&
			    be32_to_cpu(AFFS_ROOT_TAIL(sb, root_bh)->stype) == ST_ROOT) {
				sbi->s_hashsize    = blocksize / 4 - 56;
				sbi->s_root_block += num_bm;
				goto got_root;
			}
			affs_brelse(root_bh);
			root_bh = NULL;
		}
	}
	if (!silent)
406
		pr_err("No valid root block on device %s\n", sb->s_id);
407
	return -EINVAL;
L
Linus Torvalds 已提交
408 409 410

	/* N.B. after this point bh must be released */
got_root:
411 412
	/* Keep super block in cache */
	sbi->s_root_bh = root_bh;
L
Linus Torvalds 已提交
413 414 415 416 417
	root_block = sbi->s_root_block;

	/* Find out which kind of FS we have */
	boot_bh = sb_bread(sb, 0);
	if (!boot_bh) {
418
		pr_err("Cannot read boot block\n");
419
		return -EINVAL;
L
Linus Torvalds 已提交
420
	}
A
Al Viro 已提交
421
	memcpy(sig, boot_bh->b_data, 4);
L
Linus Torvalds 已提交
422
	brelse(boot_bh);
A
Al Viro 已提交
423
	chksum = be32_to_cpu(*(__be32 *)sig);
L
Linus Torvalds 已提交
424 425 426 427 428 429 430

	/* Dircache filesystems are compatible with non-dircache ones
	 * when reading. As long as they aren't supported, writing is
	 * not recommended.
	 */
	if ((chksum == FS_DCFFS || chksum == MUFS_DCFFS || chksum == FS_DCOFS
	     || chksum == MUFS_DCOFS) && !(sb->s_flags & MS_RDONLY)) {
431
		pr_notice("Dircache FS - mounting %s read only\n", sb->s_id);
L
Linus Torvalds 已提交
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
		sb->s_flags |= MS_RDONLY;
	}
	switch (chksum) {
		case MUFS_FS:
		case MUFS_INTLFFS:
		case MUFS_DCFFS:
			sbi->s_flags |= SF_MUFS;
			/* fall thru */
		case FS_INTLFFS:
		case FS_DCFFS:
			sbi->s_flags |= SF_INTL;
			break;
		case MUFS_FFS:
			sbi->s_flags |= SF_MUFS;
			break;
		case FS_FFS:
			break;
		case MUFS_OFS:
			sbi->s_flags |= SF_MUFS;
			/* fall thru */
		case FS_OFS:
			sbi->s_flags |= SF_OFS;
			sb->s_flags |= MS_NOEXEC;
			break;
		case MUFS_DCOFS:
		case MUFS_INTLOFS:
			sbi->s_flags |= SF_MUFS;
		case FS_DCOFS:
		case FS_INTLOFS:
			sbi->s_flags |= SF_INTL | SF_OFS;
			sb->s_flags |= MS_NOEXEC;
			break;
		default:
465 466
			pr_err("Unknown filesystem on device %s: %08X\n",
			       sb->s_id, chksum);
467
			return -EINVAL;
L
Linus Torvalds 已提交
468 469 470
	}

	if (mount_flags & SF_VERBOSE) {
A
Al Viro 已提交
471
		u8 len = AFFS_ROOT_TAIL(sb, root_bh)->disk_name[0];
472
		pr_notice("Mounting volume \"%.*s\": Type=%.3s\\%c, Blocksize=%d\n",
A
Al Viro 已提交
473
			len > 31 ? 31 : len,
L
Linus Torvalds 已提交
474
			AFFS_ROOT_TAIL(sb, root_bh)->disk_name + 1,
A
Al Viro 已提交
475
			sig, sig[3] + '0', blocksize);
L
Linus Torvalds 已提交
476 477 478 479 480 481 482 483 484
	}

	sb->s_flags |= MS_NODEV | MS_NOSUID;

	sbi->s_data_blksize = sb->s_blocksize;
	if (sbi->s_flags & SF_OFS)
		sbi->s_data_blksize -= 24;

	tmp_flags = sb->s_flags;
485 486 487
	ret = affs_init_bitmap(sb, &tmp_flags);
	if (ret)
		return ret;
L
Linus Torvalds 已提交
488 489 490 491
	sb->s_flags = tmp_flags;

	/* set up enough so that it can read an inode */

492
	root_inode = affs_iget(sb, root_block);
493 494
	if (IS_ERR(root_inode))
		return PTR_ERR(root_inode);
495

A
Al Viro 已提交
496 497 498 499 500
	if (AFFS_SB(sb)->s_flags & SF_INTL)
		sb->s_d_op = &affs_intl_dentry_operations;
	else
		sb->s_d_op = &affs_dentry_operations;

501
	sb->s_root = d_make_root(root_inode);
L
Linus Torvalds 已提交
502
	if (!sb->s_root) {
503
		pr_err("AFFS: Get root inode failed\n");
504
		return -ENOMEM;
L
Linus Torvalds 已提交
505 506
	}

F
Fabian Frederick 已提交
507
	pr_debug("s_flags=%lX\n", sb->s_flags);
L
Linus Torvalds 已提交
508 509 510 511 512 513 514 515
	return 0;
}

static int
affs_remount(struct super_block *sb, int *flags, char *data)
{
	struct affs_sb_info	*sbi = AFFS_SB(sb);
	int			 blocksize;
516 517
	kuid_t			 uid;
	kgid_t			 gid;
L
Linus Torvalds 已提交
518 519 520 521 522
	int			 mode;
	int			 reserved;
	int			 root_block;
	unsigned long		 mount_flags;
	int			 res = 0;
M
Miklos Szeredi 已提交
523
	char			*new_opts = kstrdup(data, GFP_KERNEL);
524 525
	char			 volume[32];
	char			*prefix = NULL;
L
Linus Torvalds 已提交
526

F
Fabian Frederick 已提交
527
	pr_debug("%s(flags=0x%x,opts=\"%s\")\n", __func__, *flags, data);
L
Linus Torvalds 已提交
528

529
	sync_filesystem(sb);
L
Linus Torvalds 已提交
530 531
	*flags |= MS_NODIRATIME;

532
	memcpy(volume, sbi->s_volume, 32);
M
Miklos Szeredi 已提交
533
	if (!parse_options(data, &uid, &gid, &mode, &reserved, &root_block,
534
			   &blocksize, &prefix, volume,
M
Miklos Szeredi 已提交
535
			   &mount_flags)) {
536
		kfree(prefix);
M
Miklos Szeredi 已提交
537
		kfree(new_opts);
L
Linus Torvalds 已提交
538
		return -EINVAL;
M
Miklos Szeredi 已提交
539
	}
J
Jan Blunck 已提交
540

541
	flush_delayed_work(&sbi->sb_work);
542
	replace_mount_options(sb, new_opts);
M
Miklos Szeredi 已提交
543

L
Linus Torvalds 已提交
544 545 546 547
	sbi->s_flags = mount_flags;
	sbi->s_mode  = mode;
	sbi->s_uid   = uid;
	sbi->s_gid   = gid;
548 549 550 551 552 553 554 555
	/* protect against readers */
	spin_lock(&sbi->symlink_lock);
	if (prefix) {
		kfree(sbi->s_prefix);
		sbi->s_prefix = prefix;
	}
	memcpy(sbi->s_volume, volume, 32);
	spin_unlock(&sbi->symlink_lock);
L
Linus Torvalds 已提交
556

J
Jan Blunck 已提交
557
	if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
L
Linus Torvalds 已提交
558
		return 0;
J
Jan Blunck 已提交
559

560
	if (*flags & MS_RDONLY)
L
Linus Torvalds 已提交
561
		affs_free_bitmap(sb);
562
	else
L
Linus Torvalds 已提交
563 564 565 566 567 568
		res = affs_init_bitmap(sb, flags);

	return res;
}

static int
569
affs_statfs(struct dentry *dentry, struct kstatfs *buf)
L
Linus Torvalds 已提交
570
{
571
	struct super_block *sb = dentry->d_sb;
L
Linus Torvalds 已提交
572
	int		 free;
C
Coly Li 已提交
573
	u64		 id = huge_encode_dev(sb->s_bdev->bd_dev);
L
Linus Torvalds 已提交
574

F
Fabian Frederick 已提交
575 576 577
	pr_debug("%s() partsize=%d, reserved=%d\n",
		 __func__, AFFS_SB(sb)->s_partition_size,
		 AFFS_SB(sb)->s_reserved);
L
Linus Torvalds 已提交
578 579 580 581 582 583 584

	free          = affs_count_free_blocks(sb);
	buf->f_type    = AFFS_SUPER_MAGIC;
	buf->f_bsize   = sb->s_blocksize;
	buf->f_blocks  = AFFS_SB(sb)->s_partition_size - AFFS_SB(sb)->s_reserved;
	buf->f_bfree   = free;
	buf->f_bavail  = free;
C
Coly Li 已提交
585 586 587
	buf->f_fsid.val[0] = (u32)id;
	buf->f_fsid.val[1] = (u32)(id >> 32);
	buf->f_namelen = 30;
L
Linus Torvalds 已提交
588 589 590
	return 0;
}

A
Al Viro 已提交
591 592
static struct dentry *affs_mount(struct file_system_type *fs_type,
	int flags, const char *dev_name, void *data)
L
Linus Torvalds 已提交
593
{
A
Al Viro 已提交
594
	return mount_bdev(fs_type, flags, dev_name, data, affs_fill_super);
L
Linus Torvalds 已提交
595 596
}

597 598 599 600 601 602 603 604 605 606 607 608
static void affs_kill_sb(struct super_block *sb)
{
	struct affs_sb_info *sbi = AFFS_SB(sb);
	kill_block_super(sb);
	if (sbi) {
		affs_free_bitmap(sb);
		affs_brelse(sbi->s_root_bh);
		kfree(sbi->s_prefix);
		kfree(sbi);
	}
}

L
Linus Torvalds 已提交
609 610 611
static struct file_system_type affs_fs_type = {
	.owner		= THIS_MODULE,
	.name		= "affs",
A
Al Viro 已提交
612
	.mount		= affs_mount,
613
	.kill_sb	= affs_kill_sb,
L
Linus Torvalds 已提交
614 615
	.fs_flags	= FS_REQUIRES_DEV,
};
616
MODULE_ALIAS_FS("affs");
L
Linus Torvalds 已提交
617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643

static int __init init_affs_fs(void)
{
	int err = init_inodecache();
	if (err)
		goto out1;
	err = register_filesystem(&affs_fs_type);
	if (err)
		goto out;
	return 0;
out:
	destroy_inodecache();
out1:
	return err;
}

static void __exit exit_affs_fs(void)
{
	unregister_filesystem(&affs_fs_type);
	destroy_inodecache();
}

MODULE_DESCRIPTION("Amiga filesystem support for Linux");
MODULE_LICENSE("GPL");

module_init(init_affs_fs)
module_exit(exit_affs_fs)