super.c 10.1 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 * JFFS2 -- Journalling Flash File System, Version 2.
 *
4
 * Copyright © 2001-2007 Red Hat, Inc.
L
Linus Torvalds 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * Created by David Woodhouse <dwmw2@infradead.org>
 *
 * For licensing information, see the file 'LICENCE' in this directory.
 *
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/fs.h>
18
#include <linux/err.h>
L
Linus Torvalds 已提交
19
#include <linux/mount.h>
20
#include <linux/parser.h>
L
Linus Torvalds 已提交
21 22
#include <linux/jffs2.h>
#include <linux/pagemap.h>
23
#include <linux/mtd/super.h>
L
Linus Torvalds 已提交
24 25
#include <linux/ctype.h>
#include <linux/namei.h>
26
#include <linux/seq_file.h>
27
#include <linux/exportfs.h>
L
Linus Torvalds 已提交
28 29 30 31 32
#include "compr.h"
#include "nodelist.h"

static void jffs2_put_super(struct super_block *);

33
static struct kmem_cache *jffs2_inode_cachep;
L
Linus Torvalds 已提交
34 35 36

static struct inode *jffs2_alloc_inode(struct super_block *sb)
{
37 38 39 40
	struct jffs2_inode_info *f;

	f = kmem_cache_alloc(jffs2_inode_cachep, GFP_KERNEL);
	if (!f)
L
Linus Torvalds 已提交
41
		return NULL;
42
	return &f->vfs_inode;
L
Linus Torvalds 已提交
43 44
}

N
Nick Piggin 已提交
45
static void jffs2_i_callback(struct rcu_head *head)
L
Linus Torvalds 已提交
46
{
N
Nick Piggin 已提交
47
	struct inode *inode = container_of(head, struct inode, i_rcu);
L
Linus Torvalds 已提交
48 49 50
	kmem_cache_free(jffs2_inode_cachep, JFFS2_INODE_INFO(inode));
}

N
Nick Piggin 已提交
51 52 53 54 55
static void jffs2_destroy_inode(struct inode *inode)
{
	call_rcu(&inode->i_rcu, jffs2_i_callback);
}

56
static void jffs2_i_init_once(void *foo)
L
Linus Torvalds 已提交
57
{
58
	struct jffs2_inode_info *f = foo;
L
Linus Torvalds 已提交
59

60 61
	mutex_init(&f->sem);
	inode_init_once(&f->vfs_inode);
L
Linus Torvalds 已提交
62 63
}

64 65 66
static void jffs2_write_super(struct super_block *sb)
{
	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
67 68

	lock_super(sb);
69 70
	sb->s_dirt = 0;

71 72 73 74
	if (!(sb->s_flags & MS_RDONLY)) {
		D1(printk(KERN_DEBUG "jffs2_write_super()\n"));
		jffs2_flush_wbuf_gc(c, 0);
	}
75

76
	unlock_super(sb);
77 78
}

79 80 81 82 83
static const char *jffs2_compr_name(unsigned int compr)
{
	switch (compr) {
	case JFFS2_COMPR_MODE_NONE:
		return "none";
84 85 86 87 88 89 90 91
#ifdef CONFIG_JFFS2_LZO
	case JFFS2_COMPR_MODE_FORCELZO:
		return "lzo";
#endif
#ifdef CONFIG_JFFS2_ZLIB
	case JFFS2_COMPR_MODE_FORCEZLIB:
		return "zlib";
#endif
92 93 94 95 96 97 98
	default:
		/* should never happen; programmer error */
		WARN_ON(1);
		return "";
	}
}

99
static int jffs2_show_options(struct seq_file *s, struct dentry *root)
100
{
101
	struct jffs2_sb_info *c = JFFS2_SB_INFO(root->d_sb);
102 103 104 105 106 107 108 109
	struct jffs2_mount_opts *opts = &c->mount_opts;

	if (opts->override_compr)
		seq_printf(s, ",compr=%s", jffs2_compr_name(opts->compr));

	return 0;
}

L
Linus Torvalds 已提交
110 111 112 113
static int jffs2_sync_fs(struct super_block *sb, int wait)
{
	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);

114 115
	jffs2_write_super(sb);

116
	mutex_lock(&c->alloc_sem);
L
Linus Torvalds 已提交
117
	jffs2_flush_wbuf_pad(c);
118
	mutex_unlock(&c->alloc_sem);
L
Linus Torvalds 已提交
119 120 121
	return 0;
}

122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
static struct inode *jffs2_nfs_get_inode(struct super_block *sb, uint64_t ino,
					 uint32_t generation)
{
	/* We don't care about i_generation. We'll destroy the flash
	   before we start re-using inode numbers anyway. And even
	   if that wasn't true, we'd have other problems...*/
	return jffs2_iget(sb, ino);
}

static struct dentry *jffs2_fh_to_dentry(struct super_block *sb, struct fid *fid,
					 int fh_len, int fh_type)
{
        return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
                                    jffs2_nfs_get_inode);
}

static struct dentry *jffs2_fh_to_parent(struct super_block *sb, struct fid *fid,
					 int fh_len, int fh_type)
{
        return generic_fh_to_parent(sb, fid, fh_len, fh_type,
                                    jffs2_nfs_get_inode);
}

static struct dentry *jffs2_get_parent(struct dentry *child)
{
	struct jffs2_inode_info *f;
	uint32_t pino;

	BUG_ON(!S_ISDIR(child->d_inode->i_mode));

	f = JFFS2_INODE_INFO(child->d_inode);

	pino = f->inocache->pino_nlink;

	JFFS2_DEBUG("Parent of directory ino #%u is #%u\n",
		    f->inocache->ino, pino);

	return d_obtain_alias(jffs2_iget(child->d_inode->i_sb, pino));
}

162
static const struct export_operations jffs2_export_ops = {
163 164 165 166 167
	.get_parent = jffs2_get_parent,
	.fh_to_dentry = jffs2_fh_to_dentry,
	.fh_to_parent = jffs2_fh_to_parent,
};

168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
/*
 * JFFS2 mount options.
 *
 * Opt_override_compr: override default compressor
 * Opt_err: just end of array marker
 */
enum {
	Opt_override_compr,
	Opt_err,
};

static const match_table_t tokens = {
	{Opt_override_compr, "compr=%s"},
	{Opt_err, NULL},
};

static int jffs2_parse_options(struct jffs2_sb_info *c, char *data)
{
	substring_t args[MAX_OPT_ARGS];
	char *p, *name;

	if (!data)
		return 0;

	while ((p = strsep(&data, ","))) {
		int token;

		if (!*p)
			continue;

		token = match_token(p, tokens, args);
		switch (token) {
		case Opt_override_compr:
			name = match_strdup(&args[0]);

			if (!name)
				return -ENOMEM;
205
			if (!strcmp(name, "none"))
206
				c->mount_opts.compr = JFFS2_COMPR_MODE_NONE;
207 208 209 210 211 212 213 214 215 216 217 218 219 220
#ifdef CONFIG_JFFS2_LZO
			else if (!strcmp(name, "lzo"))
				c->mount_opts.compr = JFFS2_COMPR_MODE_FORCELZO;
#endif
#ifdef CONFIG_JFFS2_ZLIB
			else if (!strcmp(name, "zlib"))
				c->mount_opts.compr =
						JFFS2_COMPR_MODE_FORCEZLIB;
#endif
			else {
				printk(KERN_ERR "JFFS2 Error: unknown compressor \"%s\"",
						name);
				kfree(name);
				return -EINVAL;
221 222
			}
			kfree(name);
223
			c->mount_opts.override_compr = true;
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
			break;
		default:
			printk(KERN_ERR "JFFS2 Error: unrecognized mount option '%s' or missing value\n",
					p);
			return -EINVAL;
		}
	}

	return 0;
}

static int jffs2_remount_fs(struct super_block *sb, int *flags, char *data)
{
	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
	int err;

	err = jffs2_parse_options(c, data);
	if (err)
		return -EINVAL;

	return jffs2_do_remount_fs(sb, flags, data);
}

247
static const struct super_operations jffs2_super_operations =
L
Linus Torvalds 已提交
248 249 250 251 252 253 254
{
	.alloc_inode =	jffs2_alloc_inode,
	.destroy_inode =jffs2_destroy_inode,
	.put_super =	jffs2_put_super,
	.write_super =	jffs2_write_super,
	.statfs =	jffs2_statfs,
	.remount_fs =	jffs2_remount_fs,
255
	.evict_inode =	jffs2_evict_inode,
L
Linus Torvalds 已提交
256
	.dirty_inode =	jffs2_dirty_inode,
257
	.show_options =	jffs2_show_options,
L
Linus Torvalds 已提交
258 259 260
	.sync_fs =	jffs2_sync_fs,
};

261 262 263 264
/*
 * fill in the superblock
 */
static int jffs2_fill_super(struct super_block *sb, void *data, int silent)
L
Linus Torvalds 已提交
265 266
{
	struct jffs2_sb_info *c;
267 268
	int ret;

269 270 271
	D1(printk(KERN_DEBUG "jffs2_get_sb_mtd():"
		  " New superblock for device %d (\"%s\")\n",
		  sb->s_mtd->index, sb->s_mtd->name));
L
Linus Torvalds 已提交
272

273
	c = kzalloc(sizeof(*c), GFP_KERNEL);
A
Arnd Bergmann 已提交
274
	if (!c)
275
		return -ENOMEM;
L
Linus Torvalds 已提交
276

277 278 279
	c->mtd = sb->s_mtd;
	c->os_priv = sb;
	sb->s_fs_info = c;
L
Linus Torvalds 已提交
280

281 282 283 284 285 286
	ret = jffs2_parse_options(c, data);
	if (ret) {
		kfree(c);
		return -EINVAL;
	}

287 288
	/* Initialize JFFS2 superblock locks, the further initialization will
	 * be done later */
289 290
	mutex_init(&c->alloc_sem);
	mutex_init(&c->erase_free_sem);
291 292 293 294 295
	init_waitqueue_head(&c->erase_wait);
	init_waitqueue_head(&c->inocache_wq);
	spin_lock_init(&c->erase_completion_lock);
	spin_lock_init(&c->inocache_lock);

L
Linus Torvalds 已提交
296
	sb->s_op = &jffs2_super_operations;
297
	sb->s_export_op = &jffs2_export_ops;
298
	sb->s_flags = sb->s_flags | MS_NOATIME;
299 300 301 302
	sb->s_xattr = jffs2_xattr_handlers;
#ifdef CONFIG_JFFS2_FS_POSIX_ACL
	sb->s_flags |= MS_POSIXACL;
#endif
303 304
	ret = jffs2_do_fill_super(sb, data, silent);
	return ret;
L
Linus Torvalds 已提交
305 306
}

A
Al Viro 已提交
307
static struct dentry *jffs2_mount(struct file_system_type *fs_type,
308
			int flags, const char *dev_name,
A
Al Viro 已提交
309
			void *data)
L
Linus Torvalds 已提交
310
{
A
Al Viro 已提交
311
	return mount_mtd(fs_type, flags, dev_name, data, jffs2_fill_super);
L
Linus Torvalds 已提交
312 313 314 315 316 317 318 319
}

static void jffs2_put_super (struct super_block *sb)
{
	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);

	D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n"));

320 321 322
	if (sb->s_dirt)
		jffs2_write_super(sb);

323
	mutex_lock(&c->alloc_sem);
L
Linus Torvalds 已提交
324
	jffs2_flush_wbuf_pad(c);
325
	mutex_unlock(&c->alloc_sem);
326 327 328

	jffs2_sum_exit(c);

L
Linus Torvalds 已提交
329 330
	jffs2_free_ino_caches(c);
	jffs2_free_raw_node_refs(c);
331
	if (jffs2_blocks_use_vmalloc(c))
L
Linus Torvalds 已提交
332 333 334 335 336
		vfree(c->blocks);
	else
		kfree(c->blocks);
	jffs2_flash_cleanup(c);
	kfree(c->inocache_list);
337
	jffs2_clear_xattr_subsystem(c);
L
Linus Torvalds 已提交
338 339 340 341 342 343 344 345 346
	if (c->mtd->sync)
		c->mtd->sync(c->mtd);

	D1(printk(KERN_DEBUG "jffs2_put_super returning\n"));
}

static void jffs2_kill_sb(struct super_block *sb)
{
	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
347 348
	if (!(sb->s_flags & MS_RDONLY))
		jffs2_stop_garbage_collect_thread(c);
349
	kill_mtd_super(sb);
L
Linus Torvalds 已提交
350 351 352 353 354 355
	kfree(c);
}

static struct file_system_type jffs2_fs_type = {
	.owner =	THIS_MODULE,
	.name =		"jffs2",
A
Al Viro 已提交
356
	.mount =	jffs2_mount,
L
Linus Torvalds 已提交
357 358 359 360 361 362 363
	.kill_sb =	jffs2_kill_sb,
};

static int __init init_jffs2_fs(void)
{
	int ret;

364 365 366 367 368 369 370
	/* Paranoia checks for on-medium structures. If we ask GCC
	   to pack them with __attribute__((packed)) then it _also_
	   assumes that they're not aligned -- so it emits crappy
	   code on some architectures. Ideally we want an attribute
	   which means just 'no padding', without the alignment
	   thing. But GCC doesn't have that -- we have to just
	   hope the structs are the right sizes, instead. */
A
Alexey Dobriyan 已提交
371 372 373 374
	BUILD_BUG_ON(sizeof(struct jffs2_unknown_node) != 12);
	BUILD_BUG_ON(sizeof(struct jffs2_raw_dirent) != 40);
	BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68);
	BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32);
375

L
Linus Torvalds 已提交
376
	printk(KERN_INFO "JFFS2 version 2.2."
377
#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
L
Linus Torvalds 已提交
378
	       " (NAND)"
379 380 381
#endif
#ifdef CONFIG_JFFS2_SUMMARY
	       " (SUMMARY) "
L
Linus Torvalds 已提交
382
#endif
383
	       " © 2001-2006 Red Hat, Inc.\n");
L
Linus Torvalds 已提交
384 385 386

	jffs2_inode_cachep = kmem_cache_create("jffs2_i",
					     sizeof(struct jffs2_inode_info),
387 388
					     0, (SLAB_RECLAIM_ACCOUNT|
						SLAB_MEM_SPREAD),
389
					     jffs2_i_init_once);
L
Linus Torvalds 已提交
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
	if (!jffs2_inode_cachep) {
		printk(KERN_ERR "JFFS2 error: Failed to initialise inode cache\n");
		return -ENOMEM;
	}
	ret = jffs2_compressors_init();
	if (ret) {
		printk(KERN_ERR "JFFS2 error: Failed to initialise compressors\n");
		goto out;
	}
	ret = jffs2_create_slab_caches();
	if (ret) {
		printk(KERN_ERR "JFFS2 error: Failed to initialise slab caches\n");
		goto out_compressors;
	}
	ret = register_filesystem(&jffs2_fs_type);
	if (ret) {
		printk(KERN_ERR "JFFS2 error: Failed to register filesystem\n");
		goto out_slab;
	}
	return 0;

 out_slab:
	jffs2_destroy_slab_caches();
 out_compressors:
	jffs2_compressors_exit();
 out:
	kmem_cache_destroy(jffs2_inode_cachep);
	return ret;
}

static void __exit exit_jffs2_fs(void)
{
	unregister_filesystem(&jffs2_fs_type);
	jffs2_destroy_slab_caches();
	jffs2_compressors_exit();
	kmem_cache_destroy(jffs2_inode_cachep);
}

module_init(init_jffs2_fs);
module_exit(exit_jffs2_fs);

MODULE_DESCRIPTION("The Journalling Flash File System, v2");
MODULE_AUTHOR("Red Hat, Inc.");
433
MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for
L
Linus Torvalds 已提交
434
		       // the sake of this tag. It's Free Software.