Blame view

fs/jffs2/super.c 10.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   * JFFS2 -- Journalling Flash File System, Version 2.
   *
c00c310ea   David Woodhouse   [JFFS2] Tidy up l...
4
   * Copyright © 2001-2007 Red Hat, Inc.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
6
7
8
9
   *
   * Created by David Woodhouse <dwmw2@infradead.org>
   *
   * For licensing information, see the file 'LICENCE' in this directory.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
13
14
15
16
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/slab.h>
  #include <linux/init.h>
  #include <linux/list.h>
  #include <linux/fs.h>
9c74034f8   Artem Bityutskiy   [MTD] return erro...
17
  #include <linux/err.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
  #include <linux/mount.h>
92abc475d   Andres Salomon   jffs2: implement ...
19
  #include <linux/parser.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
  #include <linux/jffs2.h>
  #include <linux/pagemap.h>
acaebfd8a   David Howells   [MTD] generalise ...
22
  #include <linux/mtd/super.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
  #include <linux/ctype.h>
  #include <linux/namei.h>
92abc475d   Andres Salomon   jffs2: implement ...
25
  #include <linux/seq_file.h>
5f556aab9   David Woodhouse   [JFFS2] Reinstate...
26
  #include <linux/exportfs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
30
  #include "compr.h"
  #include "nodelist.h"
  
  static void jffs2_put_super(struct super_block *);
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
31
  static struct kmem_cache *jffs2_inode_cachep;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
34
  
  static struct inode *jffs2_alloc_inode(struct super_block *sb)
  {
4e571aba7   David Woodhouse   [JFFS2] Clean up ...
35
36
37
38
  	struct jffs2_inode_info *f;
  
  	f = kmem_cache_alloc(jffs2_inode_cachep, GFP_KERNEL);
  	if (!f)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
  		return NULL;
4e571aba7   David Woodhouse   [JFFS2] Clean up ...
40
  	return &f->vfs_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
  }
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
42
  static void jffs2_i_callback(struct rcu_head *head)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
  {
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
44
  	struct inode *inode = container_of(head, struct inode, i_rcu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
  	kmem_cache_free(jffs2_inode_cachep, JFFS2_INODE_INFO(inode));
  }
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
47
48
49
50
  static void jffs2_destroy_inode(struct inode *inode)
  {
  	call_rcu(&inode->i_rcu, jffs2_i_callback);
  }
51cc50685   Alexey Dobriyan   SL*B: drop kmem c...
51
  static void jffs2_i_init_once(void *foo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
  {
4e571aba7   David Woodhouse   [JFFS2] Clean up ...
53
  	struct jffs2_inode_info *f = foo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54

4e571aba7   David Woodhouse   [JFFS2] Clean up ...
55
56
  	mutex_init(&f->sem);
  	inode_init_once(&f->vfs_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
  }
01ba68757   Christoph Hellwig   jffs2: move jffs2...
58
59
60
  static void jffs2_write_super(struct super_block *sb)
  {
  	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
ebc1ac164   Christoph Hellwig   ->write_super loc...
61
62
  
  	lock_super(sb);
01ba68757   Christoph Hellwig   jffs2: move jffs2...
63
  	sb->s_dirt = 0;
ebc1ac164   Christoph Hellwig   ->write_super loc...
64
65
66
  	if (!(sb->s_flags & MS_RDONLY)) {
  		D1(printk(KERN_DEBUG "jffs2_write_super()
  "));
ebc1ac164   Christoph Hellwig   ->write_super loc...
67
68
  		jffs2_flush_wbuf_gc(c, 0);
  	}
01ba68757   Christoph Hellwig   jffs2: move jffs2...
69

ebc1ac164   Christoph Hellwig   ->write_super loc...
70
  	unlock_super(sb);
01ba68757   Christoph Hellwig   jffs2: move jffs2...
71
  }
92abc475d   Andres Salomon   jffs2: implement ...
72
73
74
75
76
  static const char *jffs2_compr_name(unsigned int compr)
  {
  	switch (compr) {
  	case JFFS2_COMPR_MODE_NONE:
  		return "none";
123005f3c   Andres Salomon   jffs2: add compr=...
77
78
79
80
81
82
83
84
  #ifdef CONFIG_JFFS2_LZO
  	case JFFS2_COMPR_MODE_FORCELZO:
  		return "lzo";
  #endif
  #ifdef CONFIG_JFFS2_ZLIB
  	case JFFS2_COMPR_MODE_FORCEZLIB:
  		return "zlib";
  #endif
92abc475d   Andres Salomon   jffs2: implement ...
85
86
87
88
89
90
  	default:
  		/* should never happen; programmer error */
  		WARN_ON(1);
  		return "";
  	}
  }
34c80b1d9   Al Viro   vfs: switch ->sho...
91
  static int jffs2_show_options(struct seq_file *s, struct dentry *root)
92abc475d   Andres Salomon   jffs2: implement ...
92
  {
34c80b1d9   Al Viro   vfs: switch ->sho...
93
  	struct jffs2_sb_info *c = JFFS2_SB_INFO(root->d_sb);
92abc475d   Andres Salomon   jffs2: implement ...
94
95
96
97
98
99
100
  	struct jffs2_mount_opts *opts = &c->mount_opts;
  
  	if (opts->override_compr)
  		seq_printf(s, ",compr=%s", jffs2_compr_name(opts->compr));
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
102
103
  static int jffs2_sync_fs(struct super_block *sb, int wait)
  {
  	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
d579ed00a   Christoph Hellwig   jffs2: call jffs2...
104
  	jffs2_write_super(sb);
ced220703   David Woodhouse   [JFFS2] semaphore...
105
  	mutex_lock(&c->alloc_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
  	jffs2_flush_wbuf_pad(c);
ced220703   David Woodhouse   [JFFS2] semaphore...
107
  	mutex_unlock(&c->alloc_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
  	return 0;
  }
5f556aab9   David Woodhouse   [JFFS2] Reinstate...
110
111
112
113
114
115
116
117
118
119
120
121
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
  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
  ",
  		    f->inocache->ino, pino);
  
  	return d_obtain_alias(jffs2_iget(child->d_inode->i_sb, pino));
  }
ac4cfdd6d   Alexey Dobriyan   const: mark remai...
150
  static const struct export_operations jffs2_export_ops = {
5f556aab9   David Woodhouse   [JFFS2] Reinstate...
151
152
153
154
  	.get_parent = jffs2_get_parent,
  	.fh_to_dentry = jffs2_fh_to_dentry,
  	.fh_to_parent = jffs2_fh_to_parent,
  };
92abc475d   Andres Salomon   jffs2: implement ...
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
  /*
   * 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;
123005f3c   Andres Salomon   jffs2: add compr=...
192
  			if (!strcmp(name, "none"))
92abc475d   Andres Salomon   jffs2: implement ...
193
  				c->mount_opts.compr = JFFS2_COMPR_MODE_NONE;
123005f3c   Andres Salomon   jffs2: add compr=...
194
195
196
197
198
199
200
201
202
203
204
205
206
207
  #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;
92abc475d   Andres Salomon   jffs2: implement ...
208
209
  			}
  			kfree(name);
123005f3c   Andres Salomon   jffs2: add compr=...
210
  			c->mount_opts.override_compr = true;
92abc475d   Andres Salomon   jffs2: implement ...
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
  			break;
  		default:
  			printk(KERN_ERR "JFFS2 Error: unrecognized mount option '%s' or missing value
  ",
  					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);
  }
ee9b6d61a   Josef 'Jeff' Sipek   [PATCH] Mark stru...
234
  static const struct super_operations jffs2_super_operations =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
236
237
  {
  	.alloc_inode =	jffs2_alloc_inode,
  	.destroy_inode =jffs2_destroy_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
239
240
241
  	.put_super =	jffs2_put_super,
  	.write_super =	jffs2_write_super,
  	.statfs =	jffs2_statfs,
  	.remount_fs =	jffs2_remount_fs,
b57922d97   Al Viro   convert remaining...
242
  	.evict_inode =	jffs2_evict_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
  	.dirty_inode =	jffs2_dirty_inode,
92abc475d   Andres Salomon   jffs2: implement ...
244
  	.show_options =	jffs2_show_options,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
246
  	.sync_fs =	jffs2_sync_fs,
  };
acaebfd8a   David Howells   [MTD] generalise ...
247
248
249
250
  /*
   * fill in the superblock
   */
  static int jffs2_fill_super(struct super_block *sb, void *data, int silent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
  	struct jffs2_sb_info *c;
db7192221   Jan Blunck   BKL: Explicitly a...
253
  	int ret;
acaebfd8a   David Howells   [MTD] generalise ...
254
255
256
257
  	D1(printk(KERN_DEBUG "jffs2_get_sb_mtd():"
  		  " New superblock for device %d (\"%s\")
  ",
  		  sb->s_mtd->index, sb->s_mtd->name));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258

f8314dc60   Panagiotis Issaris   [PATCH] fs: Conve...
259
  	c = kzalloc(sizeof(*c), GFP_KERNEL);
1a028dd2d   Arnd Bergmann   BKL: Remove BKL f...
260
  	if (!c)
454e2398b   David Howells   [PATCH] VFS: Perm...
261
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262

acaebfd8a   David Howells   [MTD] generalise ...
263
264
265
  	c->mtd = sb->s_mtd;
  	c->os_priv = sb;
  	sb->s_fs_info = c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266

92abc475d   Andres Salomon   jffs2: implement ...
267
268
269
270
271
  	ret = jffs2_parse_options(c, data);
  	if (ret) {
  		kfree(c);
  		return -EINVAL;
  	}
acaebfd8a   David Howells   [MTD] generalise ...
272
273
  	/* Initialize JFFS2 superblock locks, the further initialization will
  	 * be done later */
ced220703   David Woodhouse   [JFFS2] semaphore...
274
275
  	mutex_init(&c->alloc_sem);
  	mutex_init(&c->erase_free_sem);
b62205986   Artem B. Bityuckiy   [JFFS2] Init lock...
276
277
278
279
  	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);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
  	sb->s_op = &jffs2_super_operations;
5f556aab9   David Woodhouse   [JFFS2] Reinstate...
281
  	sb->s_export_op = &jffs2_export_ops;
acaebfd8a   David Howells   [MTD] generalise ...
282
  	sb->s_flags = sb->s_flags | MS_NOATIME;
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
283
284
285
286
  	sb->s_xattr = jffs2_xattr_handlers;
  #ifdef CONFIG_JFFS2_FS_POSIX_ACL
  	sb->s_flags |= MS_POSIXACL;
  #endif
db7192221   Jan Blunck   BKL: Explicitly a...
287
  	ret = jffs2_do_fill_super(sb, data, silent);
db7192221   Jan Blunck   BKL: Explicitly a...
288
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
  }
848b83a59   Al Viro   convert get_sb_mt...
290
  static struct dentry *jffs2_mount(struct file_system_type *fs_type,
454e2398b   David Howells   [PATCH] VFS: Perm...
291
  			int flags, const char *dev_name,
848b83a59   Al Viro   convert get_sb_mt...
292
  			void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
  {
848b83a59   Al Viro   convert get_sb_mt...
294
  	return mount_mtd(fs_type, flags, dev_name, data, jffs2_fill_super);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
296
297
298
299
300
301
302
  }
  
  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()
  "));
8c85e1251   Christoph Hellwig   remove ->write_su...
303
304
  	if (sb->s_dirt)
  		jffs2_write_super(sb);
ced220703   David Woodhouse   [JFFS2] semaphore...
305
  	mutex_lock(&c->alloc_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
  	jffs2_flush_wbuf_pad(c);
ced220703   David Woodhouse   [JFFS2] semaphore...
307
  	mutex_unlock(&c->alloc_sem);
e631ddba5   Ferenc Havasi   [JFFS2] Add erase...
308
309
  
  	jffs2_sum_exit(c);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
311
  	jffs2_free_ino_caches(c);
  	jffs2_free_raw_node_refs(c);
4ce1f5621   Ferenc Havasi   [JFFS2] Remove su...
312
  	if (jffs2_blocks_use_vmalloc(c))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
314
315
316
317
  		vfree(c->blocks);
  	else
  		kfree(c->blocks);
  	jffs2_flash_cleanup(c);
  	kfree(c->inocache_list);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
318
  	jffs2_clear_xattr_subsystem(c);
327cf2922   Artem Bityutskiy   mtd: do not use m...
319
  	mtd_sync(c->mtd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320
321
322
323
324
325
326
  	D1(printk(KERN_DEBUG "jffs2_put_super returning
  "));
  }
  
  static void jffs2_kill_sb(struct super_block *sb)
  {
  	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
a69dde91e   Artem B. Bityuckiy   [JFFS2] Kill GC t...
327
328
  	if (!(sb->s_flags & MS_RDONLY))
  		jffs2_stop_garbage_collect_thread(c);
acaebfd8a   David Howells   [MTD] generalise ...
329
  	kill_mtd_super(sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
331
332
333
334
335
  	kfree(c);
  }
  
  static struct file_system_type jffs2_fs_type = {
  	.owner =	THIS_MODULE,
  	.name =		"jffs2",
848b83a59   Al Viro   convert get_sb_mt...
336
  	.mount =	jffs2_mount,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
338
339
340
341
342
  	.kill_sb =	jffs2_kill_sb,
  };
  
  static int __init init_jffs2_fs(void)
  {
  	int ret;
3e68fbb59   David Woodhouse   [JFFS2] Don't pac...
343
344
345
346
347
348
349
  	/* 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. */
2ecd05ae6   Alexey Dobriyan   [PATCH] fs/*: use...
350
351
352
353
  	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);
3e68fbb59   David Woodhouse   [JFFS2] Don't pac...
354

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
  	printk(KERN_INFO "JFFS2 version 2.2."
2f82ce1eb   Andrew Victor   [JFFS2] Use a sin...
356
  #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
358
  	       " (NAND)"
  #endif
e631ddba5   Ferenc Havasi   [JFFS2] Add erase...
359
360
361
  #ifdef CONFIG_JFFS2_SUMMARY
  	       " (SUMMARY) "
  #endif
c00c310ea   David Woodhouse   [JFFS2] Tidy up l...
362
363
  	       " © 2001-2006 Red Hat, Inc.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
365
366
  
  	jffs2_inode_cachep = kmem_cache_create("jffs2_i",
  					     sizeof(struct jffs2_inode_info),
fffb60f93   Paul Jackson   [PATCH] cpuset me...
367
368
  					     0, (SLAB_RECLAIM_ACCOUNT|
  						SLAB_MEM_SPREAD),
20c2df83d   Paul Mundt   mm: Remove slab d...
369
  					     jffs2_i_init_once);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
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
  	if (!jffs2_inode_cachep) {
  		printk(KERN_ERR "JFFS2 error: Failed to initialise inode cache
  ");
  		return -ENOMEM;
  	}
  	ret = jffs2_compressors_init();
  	if (ret) {
  		printk(KERN_ERR "JFFS2 error: Failed to initialise compressors
  ");
  		goto out;
  	}
  	ret = jffs2_create_slab_caches();
  	if (ret) {
  		printk(KERN_ERR "JFFS2 error: Failed to initialise slab caches
  ");
  		goto out_compressors;
  	}
  	ret = register_filesystem(&jffs2_fs_type);
  	if (ret) {
  		printk(KERN_ERR "JFFS2 error: Failed to register filesystem
  ");
  		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.");
182ec4eee   Thomas Gleixner   [JFFS2] Clean up ...
417
  MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
  		       // the sake of this tag. It's Free Software.