diff options
Diffstat (limited to 'fs/romfs/super.c')
-rw-r--r-- | fs/romfs/super.c | 648 |
1 files changed, 648 insertions, 0 deletions
diff --git a/fs/romfs/super.c b/fs/romfs/super.c new file mode 100644 index 000000000000..1e548a4975ba --- /dev/null +++ b/fs/romfs/super.c | |||
@@ -0,0 +1,648 @@ | |||
1 | /* Block- or MTD-based romfs | ||
2 | * | ||
3 | * Copyright © 2007 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * Derived from: ROMFS file system, Linux implementation | ||
7 | * | ||
8 | * Copyright © 1997-1999 Janos Farkas <chexum@shadow.banki.hu> | ||
9 | * | ||
10 | * Using parts of the minix filesystem | ||
11 | * Copyright © 1991, 1992 Linus Torvalds | ||
12 | * | ||
13 | * and parts of the affs filesystem additionally | ||
14 | * Copyright © 1993 Ray Burr | ||
15 | * Copyright © 1996 Hans-Joachim Widmaier | ||
16 | * | ||
17 | * Changes | ||
18 | * Changed for 2.1.19 modules | ||
19 | * Jan 1997 Initial release | ||
20 | * Jun 1997 2.1.43+ changes | ||
21 | * Proper page locking in readpage | ||
22 | * Changed to work with 2.1.45+ fs | ||
23 | * Jul 1997 Fixed follow_link | ||
24 | * 2.1.47 | ||
25 | * lookup shouldn't return -ENOENT | ||
26 | * from Horst von Brand: | ||
27 | * fail on wrong checksum | ||
28 | * double unlock_super was possible | ||
29 | * correct namelen for statfs | ||
30 | * spotted by Bill Hawes: | ||
31 | * readlink shouldn't iput() | ||
32 | * Jun 1998 2.1.106 from Avery Pennarun: glibc scandir() | ||
33 | * exposed a problem in readdir | ||
34 | * 2.1.107 code-freeze spellchecker run | ||
35 | * Aug 1998 2.1.118+ VFS changes | ||
36 | * Sep 1998 2.1.122 another VFS change (follow_link) | ||
37 | * Apr 1999 2.2.7 no more EBADF checking in | ||
38 | * lookup/readdir, use ERR_PTR | ||
39 | * Jun 1999 2.3.6 d_alloc_root use changed | ||
40 | * 2.3.9 clean up usage of ENOENT/negative | ||
41 | * dentries in lookup | ||
42 | * clean up page flags setting | ||
43 | * (error, uptodate, locking) in | ||
44 | * in readpage | ||
45 | * use init_special_inode for | ||
46 | * fifos/sockets (and streamline) in | ||
47 | * read_inode, fix _ops table order | ||
48 | * Aug 1999 2.3.16 __initfunc() => __init change | ||
49 | * Oct 1999 2.3.24 page->owner hack obsoleted | ||
50 | * Nov 1999 2.3.27 2.3.25+ page->offset => index change | ||
51 | * | ||
52 | * | ||
53 | * This program is free software; you can redistribute it and/or | ||
54 | * modify it under the terms of the GNU General Public Licence | ||
55 | * as published by the Free Software Foundation; either version | ||
56 | * 2 of the Licence, or (at your option) any later version. | ||
57 | */ | ||
58 | |||
59 | #include <linux/module.h> | ||
60 | #include <linux/string.h> | ||
61 | #include <linux/fs.h> | ||
62 | #include <linux/time.h> | ||
63 | #include <linux/slab.h> | ||
64 | #include <linux/init.h> | ||
65 | #include <linux/blkdev.h> | ||
66 | #include <linux/parser.h> | ||
67 | #include <linux/mount.h> | ||
68 | #include <linux/namei.h> | ||
69 | #include <linux/statfs.h> | ||
70 | #include <linux/mtd/super.h> | ||
71 | #include <linux/ctype.h> | ||
72 | #include <linux/highmem.h> | ||
73 | #include <linux/pagemap.h> | ||
74 | #include <linux/uaccess.h> | ||
75 | #include "internal.h" | ||
76 | |||
77 | static struct kmem_cache *romfs_inode_cachep; | ||
78 | |||
79 | static const umode_t romfs_modemap[8] = { | ||
80 | 0, /* hard link */ | ||
81 | S_IFDIR | 0644, /* directory */ | ||
82 | S_IFREG | 0644, /* regular file */ | ||
83 | S_IFLNK | 0777, /* symlink */ | ||
84 | S_IFBLK | 0600, /* blockdev */ | ||
85 | S_IFCHR | 0600, /* chardev */ | ||
86 | S_IFSOCK | 0644, /* socket */ | ||
87 | S_IFIFO | 0644 /* FIFO */ | ||
88 | }; | ||
89 | |||
90 | static const unsigned char romfs_dtype_table[] = { | ||
91 | DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_SOCK, DT_FIFO | ||
92 | }; | ||
93 | |||
94 | static struct inode *romfs_iget(struct super_block *sb, unsigned long pos); | ||
95 | |||
96 | /* | ||
97 | * read a page worth of data from the image | ||
98 | */ | ||
99 | static int romfs_readpage(struct file *file, struct page *page) | ||
100 | { | ||
101 | struct inode *inode = page->mapping->host; | ||
102 | loff_t offset, size; | ||
103 | unsigned long fillsize, pos; | ||
104 | void *buf; | ||
105 | int ret; | ||
106 | |||
107 | buf = kmap(page); | ||
108 | if (!buf) | ||
109 | return -ENOMEM; | ||
110 | |||
111 | /* 32 bit warning -- but not for us :) */ | ||
112 | offset = page_offset(page); | ||
113 | size = i_size_read(inode); | ||
114 | fillsize = 0; | ||
115 | ret = 0; | ||
116 | if (offset < size) { | ||
117 | size -= offset; | ||
118 | fillsize = size > PAGE_SIZE ? PAGE_SIZE : size; | ||
119 | |||
120 | pos = ROMFS_I(inode)->i_dataoffset + offset; | ||
121 | |||
122 | ret = romfs_dev_read(inode->i_sb, pos, buf, fillsize); | ||
123 | if (ret < 0) { | ||
124 | SetPageError(page); | ||
125 | fillsize = 0; | ||
126 | ret = -EIO; | ||
127 | } | ||
128 | } | ||
129 | |||
130 | if (fillsize < PAGE_SIZE) | ||
131 | memset(buf + fillsize, 0, PAGE_SIZE - fillsize); | ||
132 | if (ret == 0) | ||
133 | SetPageUptodate(page); | ||
134 | |||
135 | flush_dcache_page(page); | ||
136 | kunmap(page); | ||
137 | unlock_page(page); | ||
138 | return ret; | ||
139 | } | ||
140 | |||
141 | static const struct address_space_operations romfs_aops = { | ||
142 | .readpage = romfs_readpage | ||
143 | }; | ||
144 | |||
145 | /* | ||
146 | * read the entries from a directory | ||
147 | */ | ||
148 | static int romfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | ||
149 | { | ||
150 | struct inode *i = filp->f_dentry->d_inode; | ||
151 | struct romfs_inode ri; | ||
152 | unsigned long offset, maxoff; | ||
153 | int j, ino, nextfh; | ||
154 | int stored = 0; | ||
155 | char fsname[ROMFS_MAXFN]; /* XXX dynamic? */ | ||
156 | int ret; | ||
157 | |||
158 | maxoff = romfs_maxsize(i->i_sb); | ||
159 | |||
160 | offset = filp->f_pos; | ||
161 | if (!offset) { | ||
162 | offset = i->i_ino & ROMFH_MASK; | ||
163 | ret = romfs_dev_read(i->i_sb, offset, &ri, ROMFH_SIZE); | ||
164 | if (ret < 0) | ||
165 | goto out; | ||
166 | offset = be32_to_cpu(ri.spec) & ROMFH_MASK; | ||
167 | } | ||
168 | |||
169 | /* Not really failsafe, but we are read-only... */ | ||
170 | for (;;) { | ||
171 | if (!offset || offset >= maxoff) { | ||
172 | offset = maxoff; | ||
173 | filp->f_pos = offset; | ||
174 | goto out; | ||
175 | } | ||
176 | filp->f_pos = offset; | ||
177 | |||
178 | /* Fetch inode info */ | ||
179 | ret = romfs_dev_read(i->i_sb, offset, &ri, ROMFH_SIZE); | ||
180 | if (ret < 0) | ||
181 | goto out; | ||
182 | |||
183 | j = romfs_dev_strnlen(i->i_sb, offset + ROMFH_SIZE, | ||
184 | sizeof(fsname) - 1); | ||
185 | if (j < 0) | ||
186 | goto out; | ||
187 | |||
188 | ret = romfs_dev_read(i->i_sb, offset + ROMFH_SIZE, fsname, j); | ||
189 | if (ret < 0) | ||
190 | goto out; | ||
191 | fsname[j] = '\0'; | ||
192 | |||
193 | ino = offset; | ||
194 | nextfh = be32_to_cpu(ri.next); | ||
195 | if ((nextfh & ROMFH_TYPE) == ROMFH_HRD) | ||
196 | ino = be32_to_cpu(ri.spec); | ||
197 | if (filldir(dirent, fsname, j, offset, ino, | ||
198 | romfs_dtype_table[nextfh & ROMFH_TYPE]) < 0) | ||
199 | goto out; | ||
200 | |||
201 | stored++; | ||
202 | offset = nextfh & ROMFH_MASK; | ||
203 | } | ||
204 | |||
205 | out: | ||
206 | return stored; | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | * look up an entry in a directory | ||
211 | */ | ||
212 | static struct dentry *romfs_lookup(struct inode *dir, struct dentry *dentry, | ||
213 | struct nameidata *nd) | ||
214 | { | ||
215 | unsigned long offset, maxoff; | ||
216 | struct inode *inode; | ||
217 | struct romfs_inode ri; | ||
218 | const char *name; /* got from dentry */ | ||
219 | int len, ret; | ||
220 | |||
221 | offset = dir->i_ino & ROMFH_MASK; | ||
222 | ret = romfs_dev_read(dir->i_sb, offset, &ri, ROMFH_SIZE); | ||
223 | if (ret < 0) | ||
224 | goto error; | ||
225 | |||
226 | /* search all the file entries in the list starting from the one | ||
227 | * pointed to by the directory's special data */ | ||
228 | maxoff = romfs_maxsize(dir->i_sb); | ||
229 | offset = be32_to_cpu(ri.spec) & ROMFH_MASK; | ||
230 | |||
231 | name = dentry->d_name.name; | ||
232 | len = dentry->d_name.len; | ||
233 | |||
234 | for (;;) { | ||
235 | if (!offset || offset >= maxoff) | ||
236 | goto out0; | ||
237 | |||
238 | ret = romfs_dev_read(dir->i_sb, offset, &ri, sizeof(ri)); | ||
239 | if (ret < 0) | ||
240 | goto error; | ||
241 | |||
242 | /* try to match the first 16 bytes of name */ | ||
243 | ret = romfs_dev_strncmp(dir->i_sb, offset + ROMFH_SIZE, name, | ||
244 | len); | ||
245 | if (ret < 0) | ||
246 | goto error; | ||
247 | if (ret == 1) | ||
248 | break; | ||
249 | |||
250 | /* next entry */ | ||
251 | offset = be32_to_cpu(ri.next) & ROMFH_MASK; | ||
252 | } | ||
253 | |||
254 | /* Hard link handling */ | ||
255 | if ((be32_to_cpu(ri.next) & ROMFH_TYPE) == ROMFH_HRD) | ||
256 | offset = be32_to_cpu(ri.spec) & ROMFH_MASK; | ||
257 | |||
258 | inode = romfs_iget(dir->i_sb, offset); | ||
259 | if (IS_ERR(inode)) { | ||
260 | ret = PTR_ERR(inode); | ||
261 | goto error; | ||
262 | } | ||
263 | goto outi; | ||
264 | |||
265 | /* | ||
266 | * it's a bit funky, _lookup needs to return an error code | ||
267 | * (negative) or a NULL, both as a dentry. ENOENT should not | ||
268 | * be returned, instead we need to create a negative dentry by | ||
269 | * d_add(dentry, NULL); and return 0 as no error. | ||
270 | * (Although as I see, it only matters on writable file | ||
271 | * systems). | ||
272 | */ | ||
273 | out0: | ||
274 | inode = NULL; | ||
275 | outi: | ||
276 | d_add(dentry, inode); | ||
277 | ret = 0; | ||
278 | error: | ||
279 | return ERR_PTR(ret); | ||
280 | } | ||
281 | |||
282 | static const struct file_operations romfs_dir_operations = { | ||
283 | .read = generic_read_dir, | ||
284 | .readdir = romfs_readdir, | ||
285 | }; | ||
286 | |||
287 | static struct inode_operations romfs_dir_inode_operations = { | ||
288 | .lookup = romfs_lookup, | ||
289 | }; | ||
290 | |||
291 | /* | ||
292 | * get a romfs inode based on its position in the image (which doubles as the | ||
293 | * inode number) | ||
294 | */ | ||
295 | static struct inode *romfs_iget(struct super_block *sb, unsigned long pos) | ||
296 | { | ||
297 | struct romfs_inode_info *inode; | ||
298 | struct romfs_inode ri; | ||
299 | struct inode *i; | ||
300 | unsigned long nlen; | ||
301 | unsigned nextfh, ret; | ||
302 | umode_t mode; | ||
303 | |||
304 | /* we might have to traverse a chain of "hard link" file entries to get | ||
305 | * to the actual file */ | ||
306 | for (;;) { | ||
307 | ret = romfs_dev_read(sb, pos, &ri, sizeof(ri)); | ||
308 | if (ret < 0) | ||
309 | goto error; | ||
310 | |||
311 | /* XXX: do romfs_checksum here too (with name) */ | ||
312 | |||
313 | nextfh = be32_to_cpu(ri.next); | ||
314 | if ((nextfh & ROMFH_TYPE) != ROMFH_HRD) | ||
315 | break; | ||
316 | |||
317 | pos = be32_to_cpu(ri.spec) & ROMFH_MASK; | ||
318 | } | ||
319 | |||
320 | /* determine the length of the filename */ | ||
321 | nlen = romfs_dev_strnlen(sb, pos + ROMFH_SIZE, ROMFS_MAXFN); | ||
322 | if (IS_ERR_VALUE(nlen)) | ||
323 | goto eio; | ||
324 | |||
325 | /* get an inode for this image position */ | ||
326 | i = iget_locked(sb, pos); | ||
327 | if (!i) | ||
328 | return ERR_PTR(-ENOMEM); | ||
329 | |||
330 | if (!(i->i_state & I_NEW)) | ||
331 | return i; | ||
332 | |||
333 | /* precalculate the data offset */ | ||
334 | inode = ROMFS_I(i); | ||
335 | inode->i_metasize = (ROMFH_SIZE + nlen + 1 + ROMFH_PAD) & ROMFH_MASK; | ||
336 | inode->i_dataoffset = pos + inode->i_metasize; | ||
337 | |||
338 | i->i_nlink = 1; /* Hard to decide.. */ | ||
339 | i->i_size = be32_to_cpu(ri.size); | ||
340 | i->i_mtime.tv_sec = i->i_atime.tv_sec = i->i_ctime.tv_sec = 0; | ||
341 | i->i_mtime.tv_nsec = i->i_atime.tv_nsec = i->i_ctime.tv_nsec = 0; | ||
342 | |||
343 | /* set up mode and ops */ | ||
344 | mode = romfs_modemap[nextfh & ROMFH_TYPE]; | ||
345 | |||
346 | switch (nextfh & ROMFH_TYPE) { | ||
347 | case ROMFH_DIR: | ||
348 | i->i_size = ROMFS_I(i)->i_metasize; | ||
349 | i->i_op = &romfs_dir_inode_operations; | ||
350 | i->i_fop = &romfs_dir_operations; | ||
351 | if (nextfh & ROMFH_EXEC) | ||
352 | mode |= S_IXUGO; | ||
353 | break; | ||
354 | case ROMFH_REG: | ||
355 | i->i_fop = &romfs_ro_fops; | ||
356 | i->i_data.a_ops = &romfs_aops; | ||
357 | if (i->i_sb->s_mtd) | ||
358 | i->i_data.backing_dev_info = | ||
359 | i->i_sb->s_mtd->backing_dev_info; | ||
360 | if (nextfh & ROMFH_EXEC) | ||
361 | mode |= S_IXUGO; | ||
362 | break; | ||
363 | case ROMFH_SYM: | ||
364 | i->i_op = &page_symlink_inode_operations; | ||
365 | i->i_data.a_ops = &romfs_aops; | ||
366 | mode |= S_IRWXUGO; | ||
367 | break; | ||
368 | default: | ||
369 | /* depending on MBZ for sock/fifos */ | ||
370 | nextfh = be32_to_cpu(ri.spec); | ||
371 | init_special_inode(i, mode, MKDEV(nextfh >> 16, | ||
372 | nextfh & 0xffff)); | ||
373 | break; | ||
374 | } | ||
375 | |||
376 | i->i_mode = mode; | ||
377 | |||
378 | unlock_new_inode(i); | ||
379 | return i; | ||
380 | |||
381 | eio: | ||
382 | ret = -EIO; | ||
383 | error: | ||
384 | printk(KERN_ERR "ROMFS: read error for inode 0x%lx\n", pos); | ||
385 | return ERR_PTR(ret); | ||
386 | } | ||
387 | |||
388 | /* | ||
389 | * allocate a new inode | ||
390 | */ | ||
391 | static struct inode *romfs_alloc_inode(struct super_block *sb) | ||
392 | { | ||
393 | struct romfs_inode_info *inode; | ||
394 | inode = kmem_cache_alloc(romfs_inode_cachep, GFP_KERNEL); | ||
395 | return inode ? &inode->vfs_inode : NULL; | ||
396 | } | ||
397 | |||
398 | /* | ||
399 | * return a spent inode to the slab cache | ||
400 | */ | ||
401 | static void romfs_destroy_inode(struct inode *inode) | ||
402 | { | ||
403 | kmem_cache_free(romfs_inode_cachep, ROMFS_I(inode)); | ||
404 | } | ||
405 | |||
406 | /* | ||
407 | * get filesystem statistics | ||
408 | */ | ||
409 | static int romfs_statfs(struct dentry *dentry, struct kstatfs *buf) | ||
410 | { | ||
411 | buf->f_type = ROMFS_MAGIC; | ||
412 | buf->f_namelen = ROMFS_MAXFN; | ||
413 | buf->f_bsize = ROMBSIZE; | ||
414 | buf->f_bfree = buf->f_bavail = buf->f_ffree; | ||
415 | buf->f_blocks = | ||
416 | (romfs_maxsize(dentry->d_sb) + ROMBSIZE - 1) >> ROMBSBITS; | ||
417 | return 0; | ||
418 | } | ||
419 | |||
420 | /* | ||
421 | * remounting must involve read-only | ||
422 | */ | ||
423 | static int romfs_remount(struct super_block *sb, int *flags, char *data) | ||
424 | { | ||
425 | *flags |= MS_RDONLY; | ||
426 | return 0; | ||
427 | } | ||
428 | |||
429 | static const struct super_operations romfs_super_ops = { | ||
430 | .alloc_inode = romfs_alloc_inode, | ||
431 | .destroy_inode = romfs_destroy_inode, | ||
432 | .statfs = romfs_statfs, | ||
433 | .remount_fs = romfs_remount, | ||
434 | }; | ||
435 | |||
436 | /* | ||
437 | * checksum check on part of a romfs filesystem | ||
438 | */ | ||
439 | static __u32 romfs_checksum(const void *data, int size) | ||
440 | { | ||
441 | const __be32 *ptr = data; | ||
442 | __u32 sum; | ||
443 | |||
444 | sum = 0; | ||
445 | size >>= 2; | ||
446 | while (size > 0) { | ||
447 | sum += be32_to_cpu(*ptr++); | ||
448 | size--; | ||
449 | } | ||
450 | return sum; | ||
451 | } | ||
452 | |||
453 | /* | ||
454 | * fill in the superblock | ||
455 | */ | ||
456 | static int romfs_fill_super(struct super_block *sb, void *data, int silent) | ||
457 | { | ||
458 | struct romfs_super_block *rsb; | ||
459 | struct inode *root; | ||
460 | unsigned long pos, img_size; | ||
461 | const char *storage; | ||
462 | size_t len; | ||
463 | int ret; | ||
464 | |||
465 | #ifdef CONFIG_BLOCK | ||
466 | if (!sb->s_mtd) { | ||
467 | sb_set_blocksize(sb, ROMBSIZE); | ||
468 | } else { | ||
469 | sb->s_blocksize = ROMBSIZE; | ||
470 | sb->s_blocksize_bits = blksize_bits(ROMBSIZE); | ||
471 | } | ||
472 | #endif | ||
473 | |||
474 | sb->s_maxbytes = 0xFFFFFFFF; | ||
475 | sb->s_magic = ROMFS_MAGIC; | ||
476 | sb->s_flags |= MS_RDONLY | MS_NOATIME; | ||
477 | sb->s_op = &romfs_super_ops; | ||
478 | |||
479 | /* read the image superblock and check it */ | ||
480 | rsb = kmalloc(512, GFP_KERNEL); | ||
481 | if (!rsb) | ||
482 | return -ENOMEM; | ||
483 | |||
484 | sb->s_fs_info = (void *) 512; | ||
485 | ret = romfs_dev_read(sb, 0, rsb, 512); | ||
486 | if (ret < 0) | ||
487 | goto error_rsb; | ||
488 | |||
489 | img_size = be32_to_cpu(rsb->size); | ||
490 | |||
491 | if (sb->s_mtd && img_size > sb->s_mtd->size) | ||
492 | goto error_rsb_inval; | ||
493 | |||
494 | sb->s_fs_info = (void *) img_size; | ||
495 | |||
496 | if (rsb->word0 != ROMSB_WORD0 || rsb->word1 != ROMSB_WORD1 || | ||
497 | img_size < ROMFH_SIZE) { | ||
498 | if (!silent) | ||
499 | printk(KERN_WARNING "VFS:" | ||
500 | " Can't find a romfs filesystem on dev %s.\n", | ||
501 | sb->s_id); | ||
502 | goto error_rsb_inval; | ||
503 | } | ||
504 | |||
505 | if (romfs_checksum(rsb, min_t(size_t, img_size, 512))) { | ||
506 | printk(KERN_ERR "ROMFS: bad initial checksum on dev %s.\n", | ||
507 | sb->s_id); | ||
508 | goto error_rsb_inval; | ||
509 | } | ||
510 | |||
511 | storage = sb->s_mtd ? "MTD" : "the block layer"; | ||
512 | |||
513 | len = strnlen(rsb->name, ROMFS_MAXFN); | ||
514 | if (!silent) | ||
515 | printk(KERN_NOTICE "ROMFS: Mounting image '%*.*s' through %s\n", | ||
516 | (unsigned) len, (unsigned) len, rsb->name, storage); | ||
517 | |||
518 | kfree(rsb); | ||
519 | rsb = NULL; | ||
520 | |||
521 | /* find the root directory */ | ||
522 | pos = (ROMFH_SIZE + len + 1 + ROMFH_PAD) & ROMFH_MASK; | ||
523 | |||
524 | root = romfs_iget(sb, pos); | ||
525 | if (!root) | ||
526 | goto error; | ||
527 | |||
528 | sb->s_root = d_alloc_root(root); | ||
529 | if (!sb->s_root) | ||
530 | goto error_i; | ||
531 | |||
532 | return 0; | ||
533 | |||
534 | error_i: | ||
535 | iput(root); | ||
536 | error: | ||
537 | return -EINVAL; | ||
538 | error_rsb_inval: | ||
539 | ret = -EINVAL; | ||
540 | error_rsb: | ||
541 | return ret; | ||
542 | } | ||
543 | |||
544 | /* | ||
545 | * get a superblock for mounting | ||
546 | */ | ||
547 | static int romfs_get_sb(struct file_system_type *fs_type, | ||
548 | int flags, const char *dev_name, | ||
549 | void *data, struct vfsmount *mnt) | ||
550 | { | ||
551 | int ret = -EINVAL; | ||
552 | |||
553 | #ifdef CONFIG_ROMFS_ON_MTD | ||
554 | ret = get_sb_mtd(fs_type, flags, dev_name, data, romfs_fill_super, | ||
555 | mnt); | ||
556 | #endif | ||
557 | #ifdef CONFIG_ROMFS_ON_BLOCK | ||
558 | if (ret == -EINVAL) | ||
559 | ret = get_sb_bdev(fs_type, flags, dev_name, data, | ||
560 | romfs_fill_super, mnt); | ||
561 | #endif | ||
562 | return ret; | ||
563 | } | ||
564 | |||
565 | /* | ||
566 | * destroy a romfs superblock in the appropriate manner | ||
567 | */ | ||
568 | static void romfs_kill_sb(struct super_block *sb) | ||
569 | { | ||
570 | #ifdef CONFIG_ROMFS_ON_MTD | ||
571 | if (sb->s_mtd) { | ||
572 | kill_mtd_super(sb); | ||
573 | return; | ||
574 | } | ||
575 | #endif | ||
576 | #ifdef CONFIG_ROMFS_ON_BLOCK | ||
577 | if (sb->s_bdev) { | ||
578 | kill_block_super(sb); | ||
579 | return; | ||
580 | } | ||
581 | #endif | ||
582 | } | ||
583 | |||
584 | static struct file_system_type romfs_fs_type = { | ||
585 | .owner = THIS_MODULE, | ||
586 | .name = "romfs", | ||
587 | .get_sb = romfs_get_sb, | ||
588 | .kill_sb = romfs_kill_sb, | ||
589 | .fs_flags = FS_REQUIRES_DEV, | ||
590 | }; | ||
591 | |||
592 | /* | ||
593 | * inode storage initialiser | ||
594 | */ | ||
595 | static void romfs_i_init_once(void *_inode) | ||
596 | { | ||
597 | struct romfs_inode_info *inode = _inode; | ||
598 | |||
599 | inode_init_once(&inode->vfs_inode); | ||
600 | } | ||
601 | |||
602 | /* | ||
603 | * romfs module initialisation | ||
604 | */ | ||
605 | static int __init init_romfs_fs(void) | ||
606 | { | ||
607 | int ret; | ||
608 | |||
609 | printk(KERN_INFO "ROMFS MTD (C) 2007 Red Hat, Inc.\n"); | ||
610 | |||
611 | romfs_inode_cachep = | ||
612 | kmem_cache_create("romfs_i", | ||
613 | sizeof(struct romfs_inode_info), 0, | ||
614 | SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, | ||
615 | romfs_i_init_once); | ||
616 | |||
617 | if (!romfs_inode_cachep) { | ||
618 | printk(KERN_ERR | ||
619 | "ROMFS error: Failed to initialise inode cache\n"); | ||
620 | return -ENOMEM; | ||
621 | } | ||
622 | ret = register_filesystem(&romfs_fs_type); | ||
623 | if (ret) { | ||
624 | printk(KERN_ERR "ROMFS error: Failed to register filesystem\n"); | ||
625 | goto error_register; | ||
626 | } | ||
627 | return 0; | ||
628 | |||
629 | error_register: | ||
630 | kmem_cache_destroy(romfs_inode_cachep); | ||
631 | return ret; | ||
632 | } | ||
633 | |||
634 | /* | ||
635 | * romfs module removal | ||
636 | */ | ||
637 | static void __exit exit_romfs_fs(void) | ||
638 | { | ||
639 | unregister_filesystem(&romfs_fs_type); | ||
640 | kmem_cache_destroy(romfs_inode_cachep); | ||
641 | } | ||
642 | |||
643 | module_init(init_romfs_fs); | ||
644 | module_exit(exit_romfs_fs); | ||
645 | |||
646 | MODULE_DESCRIPTION("Direct-MTD Capable RomFS"); | ||
647 | MODULE_AUTHOR("Red Hat, Inc."); | ||
648 | MODULE_LICENSE("GPL"); /* Actually dual-licensed, but it doesn't matter for */ | ||