diff options
Diffstat (limited to 'fs/romfs/inode.c')
-rw-r--r-- | fs/romfs/inode.c | 665 |
1 files changed, 0 insertions, 665 deletions
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c deleted file mode 100644 index 98a232f7196b..000000000000 --- a/fs/romfs/inode.c +++ /dev/null | |||
@@ -1,665 +0,0 @@ | |||
1 | /* | ||
2 | * ROMFS file system, Linux implementation | ||
3 | * | ||
4 | * Copyright (C) 1997-1999 Janos Farkas <chexum@shadow.banki.hu> | ||
5 | * | ||
6 | * Using parts of the minix filesystem | ||
7 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
8 | * | ||
9 | * and parts of the affs filesystem additionally | ||
10 | * Copyright (C) 1993 Ray Burr | ||
11 | * Copyright (C) 1996 Hans-Joachim Widmaier | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version | ||
16 | * 2 of the License, or (at your option) any later version. | ||
17 | * | ||
18 | * Changes | ||
19 | * Changed for 2.1.19 modules | ||
20 | * Jan 1997 Initial release | ||
21 | * Jun 1997 2.1.43+ changes | ||
22 | * Proper page locking in readpage | ||
23 | * Changed to work with 2.1.45+ fs | ||
24 | * Jul 1997 Fixed follow_link | ||
25 | * 2.1.47 | ||
26 | * lookup shouldn't return -ENOENT | ||
27 | * from Horst von Brand: | ||
28 | * fail on wrong checksum | ||
29 | * double unlock_super was possible | ||
30 | * correct namelen for statfs | ||
31 | * spotted by Bill Hawes: | ||
32 | * readlink shouldn't iput() | ||
33 | * Jun 1998 2.1.106 from Avery Pennarun: glibc scandir() | ||
34 | * exposed a problem in readdir | ||
35 | * 2.1.107 code-freeze spellchecker run | ||
36 | * Aug 1998 2.1.118+ VFS changes | ||
37 | * Sep 1998 2.1.122 another VFS change (follow_link) | ||
38 | * Apr 1999 2.2.7 no more EBADF checking in | ||
39 | * lookup/readdir, use ERR_PTR | ||
40 | * Jun 1999 2.3.6 d_alloc_root use changed | ||
41 | * 2.3.9 clean up usage of ENOENT/negative | ||
42 | * dentries in lookup | ||
43 | * clean up page flags setting | ||
44 | * (error, uptodate, locking) in | ||
45 | * in readpage | ||
46 | * use init_special_inode for | ||
47 | * fifos/sockets (and streamline) in | ||
48 | * read_inode, fix _ops table order | ||
49 | * Aug 1999 2.3.16 __initfunc() => __init change | ||
50 | * Oct 1999 2.3.24 page->owner hack obsoleted | ||
51 | * Nov 1999 2.3.27 2.3.25+ page->offset => index change | ||
52 | */ | ||
53 | |||
54 | /* todo: | ||
55 | * - see Documentation/filesystems/romfs.txt | ||
56 | * - use allocated, not stack memory for file names? | ||
57 | * - considering write access... | ||
58 | * - network (tftp) files? | ||
59 | * - merge back some _op tables | ||
60 | */ | ||
61 | |||
62 | /* | ||
63 | * Sorry about some optimizations and for some goto's. I just wanted | ||
64 | * to squeeze some more bytes out of this code.. :) | ||
65 | */ | ||
66 | |||
67 | #include <linux/module.h> | ||
68 | #include <linux/types.h> | ||
69 | #include <linux/errno.h> | ||
70 | #include <linux/slab.h> | ||
71 | #include <linux/romfs_fs.h> | ||
72 | #include <linux/fs.h> | ||
73 | #include <linux/init.h> | ||
74 | #include <linux/pagemap.h> | ||
75 | #include <linux/smp_lock.h> | ||
76 | #include <linux/buffer_head.h> | ||
77 | #include <linux/vfs.h> | ||
78 | |||
79 | #include <asm/uaccess.h> | ||
80 | |||
81 | struct romfs_inode_info { | ||
82 | unsigned long i_metasize; /* size of non-data area */ | ||
83 | unsigned long i_dataoffset; /* from the start of fs */ | ||
84 | struct inode vfs_inode; | ||
85 | }; | ||
86 | |||
87 | static struct inode *romfs_iget(struct super_block *, unsigned long); | ||
88 | |||
89 | /* instead of private superblock data */ | ||
90 | static inline unsigned long romfs_maxsize(struct super_block *sb) | ||
91 | { | ||
92 | return (unsigned long)sb->s_fs_info; | ||
93 | } | ||
94 | |||
95 | static inline struct romfs_inode_info *ROMFS_I(struct inode *inode) | ||
96 | { | ||
97 | return container_of(inode, struct romfs_inode_info, vfs_inode); | ||
98 | } | ||
99 | |||
100 | static __u32 | ||
101 | romfs_checksum(void *data, int size) | ||
102 | { | ||
103 | __u32 sum; | ||
104 | __be32 *ptr; | ||
105 | |||
106 | sum = 0; ptr = data; | ||
107 | size>>=2; | ||
108 | while (size>0) { | ||
109 | sum += be32_to_cpu(*ptr++); | ||
110 | size--; | ||
111 | } | ||
112 | return sum; | ||
113 | } | ||
114 | |||
115 | static const struct super_operations romfs_ops; | ||
116 | |||
117 | static int romfs_fill_super(struct super_block *s, void *data, int silent) | ||
118 | { | ||
119 | struct buffer_head *bh; | ||
120 | struct romfs_super_block *rsb; | ||
121 | struct inode *root; | ||
122 | int sz, ret = -EINVAL; | ||
123 | |||
124 | /* I would parse the options here, but there are none.. :) */ | ||
125 | |||
126 | sb_set_blocksize(s, ROMBSIZE); | ||
127 | s->s_maxbytes = 0xFFFFFFFF; | ||
128 | |||
129 | bh = sb_bread(s, 0); | ||
130 | if (!bh) { | ||
131 | /* XXX merge with other printk? */ | ||
132 | printk ("romfs: unable to read superblock\n"); | ||
133 | goto outnobh; | ||
134 | } | ||
135 | |||
136 | rsb = (struct romfs_super_block *)bh->b_data; | ||
137 | sz = be32_to_cpu(rsb->size); | ||
138 | if (rsb->word0 != ROMSB_WORD0 || rsb->word1 != ROMSB_WORD1 | ||
139 | || sz < ROMFH_SIZE) { | ||
140 | if (!silent) | ||
141 | printk ("VFS: Can't find a romfs filesystem on dev " | ||
142 | "%s.\n", s->s_id); | ||
143 | goto out; | ||
144 | } | ||
145 | if (romfs_checksum(rsb, min_t(int, sz, 512))) { | ||
146 | printk ("romfs: bad initial checksum on dev " | ||
147 | "%s.\n", s->s_id); | ||
148 | goto out; | ||
149 | } | ||
150 | |||
151 | s->s_magic = ROMFS_MAGIC; | ||
152 | s->s_fs_info = (void *)(long)sz; | ||
153 | |||
154 | s->s_flags |= MS_RDONLY; | ||
155 | |||
156 | /* Find the start of the fs */ | ||
157 | sz = (ROMFH_SIZE + | ||
158 | strnlen(rsb->name, ROMFS_MAXFN) + 1 + ROMFH_PAD) | ||
159 | & ROMFH_MASK; | ||
160 | |||
161 | s->s_op = &romfs_ops; | ||
162 | root = romfs_iget(s, sz); | ||
163 | if (IS_ERR(root)) { | ||
164 | ret = PTR_ERR(root); | ||
165 | goto out; | ||
166 | } | ||
167 | |||
168 | ret = -ENOMEM; | ||
169 | s->s_root = d_alloc_root(root); | ||
170 | if (!s->s_root) | ||
171 | goto outiput; | ||
172 | |||
173 | brelse(bh); | ||
174 | return 0; | ||
175 | |||
176 | outiput: | ||
177 | iput(root); | ||
178 | out: | ||
179 | brelse(bh); | ||
180 | outnobh: | ||
181 | return ret; | ||
182 | } | ||
183 | |||
184 | /* That's simple too. */ | ||
185 | |||
186 | static int | ||
187 | romfs_statfs(struct dentry *dentry, struct kstatfs *buf) | ||
188 | { | ||
189 | buf->f_type = ROMFS_MAGIC; | ||
190 | buf->f_bsize = ROMBSIZE; | ||
191 | buf->f_bfree = buf->f_bavail = buf->f_ffree; | ||
192 | buf->f_blocks = (romfs_maxsize(dentry->d_sb)+ROMBSIZE-1)>>ROMBSBITS; | ||
193 | buf->f_namelen = ROMFS_MAXFN; | ||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | /* some helper routines */ | ||
198 | |||
199 | static int | ||
200 | romfs_strnlen(struct inode *i, unsigned long offset, unsigned long count) | ||
201 | { | ||
202 | struct buffer_head *bh; | ||
203 | unsigned long avail, maxsize, res; | ||
204 | |||
205 | maxsize = romfs_maxsize(i->i_sb); | ||
206 | if (offset >= maxsize) | ||
207 | return -1; | ||
208 | |||
209 | /* strnlen is almost always valid */ | ||
210 | if (count > maxsize || offset+count > maxsize) | ||
211 | count = maxsize-offset; | ||
212 | |||
213 | bh = sb_bread(i->i_sb, offset>>ROMBSBITS); | ||
214 | if (!bh) | ||
215 | return -1; /* error */ | ||
216 | |||
217 | avail = ROMBSIZE - (offset & ROMBMASK); | ||
218 | maxsize = min_t(unsigned long, count, avail); | ||
219 | res = strnlen(((char *)bh->b_data)+(offset&ROMBMASK), maxsize); | ||
220 | brelse(bh); | ||
221 | |||
222 | if (res < maxsize) | ||
223 | return res; /* found all of it */ | ||
224 | |||
225 | while (res < count) { | ||
226 | offset += maxsize; | ||
227 | |||
228 | bh = sb_bread(i->i_sb, offset>>ROMBSBITS); | ||
229 | if (!bh) | ||
230 | return -1; | ||
231 | maxsize = min_t(unsigned long, count - res, ROMBSIZE); | ||
232 | avail = strnlen(bh->b_data, maxsize); | ||
233 | res += avail; | ||
234 | brelse(bh); | ||
235 | if (avail < maxsize) | ||
236 | return res; | ||
237 | } | ||
238 | return res; | ||
239 | } | ||
240 | |||
241 | static int | ||
242 | romfs_copyfrom(struct inode *i, void *dest, unsigned long offset, unsigned long count) | ||
243 | { | ||
244 | struct buffer_head *bh; | ||
245 | unsigned long avail, maxsize, res; | ||
246 | |||
247 | maxsize = romfs_maxsize(i->i_sb); | ||
248 | if (offset >= maxsize || count > maxsize || offset+count>maxsize) | ||
249 | return -1; | ||
250 | |||
251 | bh = sb_bread(i->i_sb, offset>>ROMBSBITS); | ||
252 | if (!bh) | ||
253 | return -1; /* error */ | ||
254 | |||
255 | avail = ROMBSIZE - (offset & ROMBMASK); | ||
256 | maxsize = min_t(unsigned long, count, avail); | ||
257 | memcpy(dest, ((char *)bh->b_data) + (offset & ROMBMASK), maxsize); | ||
258 | brelse(bh); | ||
259 | |||
260 | res = maxsize; /* all of it */ | ||
261 | |||
262 | while (res < count) { | ||
263 | offset += maxsize; | ||
264 | dest += maxsize; | ||
265 | |||
266 | bh = sb_bread(i->i_sb, offset>>ROMBSBITS); | ||
267 | if (!bh) | ||
268 | return -1; | ||
269 | maxsize = min_t(unsigned long, count - res, ROMBSIZE); | ||
270 | memcpy(dest, bh->b_data, maxsize); | ||
271 | brelse(bh); | ||
272 | res += maxsize; | ||
273 | } | ||
274 | return res; | ||
275 | } | ||
276 | |||
277 | static unsigned char romfs_dtype_table[] = { | ||
278 | DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_SOCK, DT_FIFO | ||
279 | }; | ||
280 | |||
281 | static int | ||
282 | romfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | ||
283 | { | ||
284 | struct inode *i = filp->f_path.dentry->d_inode; | ||
285 | struct romfs_inode ri; | ||
286 | unsigned long offset, maxoff; | ||
287 | int j, ino, nextfh; | ||
288 | int stored = 0; | ||
289 | char fsname[ROMFS_MAXFN]; /* XXX dynamic? */ | ||
290 | |||
291 | lock_kernel(); | ||
292 | |||
293 | maxoff = romfs_maxsize(i->i_sb); | ||
294 | |||
295 | offset = filp->f_pos; | ||
296 | if (!offset) { | ||
297 | offset = i->i_ino & ROMFH_MASK; | ||
298 | if (romfs_copyfrom(i, &ri, offset, ROMFH_SIZE) <= 0) | ||
299 | goto out; | ||
300 | offset = be32_to_cpu(ri.spec) & ROMFH_MASK; | ||
301 | } | ||
302 | |||
303 | /* Not really failsafe, but we are read-only... */ | ||
304 | for(;;) { | ||
305 | if (!offset || offset >= maxoff) { | ||
306 | offset = maxoff; | ||
307 | filp->f_pos = offset; | ||
308 | goto out; | ||
309 | } | ||
310 | filp->f_pos = offset; | ||
311 | |||
312 | /* Fetch inode info */ | ||
313 | if (romfs_copyfrom(i, &ri, offset, ROMFH_SIZE) <= 0) | ||
314 | goto out; | ||
315 | |||
316 | j = romfs_strnlen(i, offset+ROMFH_SIZE, sizeof(fsname)-1); | ||
317 | if (j < 0) | ||
318 | goto out; | ||
319 | |||
320 | fsname[j]=0; | ||
321 | romfs_copyfrom(i, fsname, offset+ROMFH_SIZE, j); | ||
322 | |||
323 | ino = offset; | ||
324 | nextfh = be32_to_cpu(ri.next); | ||
325 | if ((nextfh & ROMFH_TYPE) == ROMFH_HRD) | ||
326 | ino = be32_to_cpu(ri.spec); | ||
327 | if (filldir(dirent, fsname, j, offset, ino, | ||
328 | romfs_dtype_table[nextfh & ROMFH_TYPE]) < 0) { | ||
329 | goto out; | ||
330 | } | ||
331 | stored++; | ||
332 | offset = nextfh & ROMFH_MASK; | ||
333 | } | ||
334 | out: | ||
335 | unlock_kernel(); | ||
336 | return stored; | ||
337 | } | ||
338 | |||
339 | static struct dentry * | ||
340 | romfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | ||
341 | { | ||
342 | unsigned long offset, maxoff; | ||
343 | long res; | ||
344 | int fslen; | ||
345 | struct inode *inode = NULL; | ||
346 | char fsname[ROMFS_MAXFN]; /* XXX dynamic? */ | ||
347 | struct romfs_inode ri; | ||
348 | const char *name; /* got from dentry */ | ||
349 | int len; | ||
350 | |||
351 | res = -EACCES; /* placeholder for "no data here" */ | ||
352 | offset = dir->i_ino & ROMFH_MASK; | ||
353 | lock_kernel(); | ||
354 | if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0) | ||
355 | goto error; | ||
356 | |||
357 | maxoff = romfs_maxsize(dir->i_sb); | ||
358 | offset = be32_to_cpu(ri.spec) & ROMFH_MASK; | ||
359 | |||
360 | /* OK, now find the file whose name is in "dentry" in the | ||
361 | * directory specified by "dir". */ | ||
362 | |||
363 | name = dentry->d_name.name; | ||
364 | len = dentry->d_name.len; | ||
365 | |||
366 | for(;;) { | ||
367 | if (!offset || offset >= maxoff) | ||
368 | goto success; /* negative success */ | ||
369 | if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0) | ||
370 | goto error; | ||
371 | |||
372 | /* try to match the first 16 bytes of name */ | ||
373 | fslen = romfs_strnlen(dir, offset+ROMFH_SIZE, ROMFH_SIZE); | ||
374 | if (len < ROMFH_SIZE) { | ||
375 | if (len == fslen) { | ||
376 | /* both are shorter, and same size */ | ||
377 | romfs_copyfrom(dir, fsname, offset+ROMFH_SIZE, len+1); | ||
378 | if (strncmp (name, fsname, len) == 0) | ||
379 | break; | ||
380 | } | ||
381 | } else if (fslen >= ROMFH_SIZE) { | ||
382 | /* both are longer; XXX optimize max size */ | ||
383 | fslen = romfs_strnlen(dir, offset+ROMFH_SIZE, sizeof(fsname)-1); | ||
384 | if (len == fslen) { | ||
385 | romfs_copyfrom(dir, fsname, offset+ROMFH_SIZE, len+1); | ||
386 | if (strncmp(name, fsname, len) == 0) | ||
387 | break; | ||
388 | } | ||
389 | } | ||
390 | /* next entry */ | ||
391 | offset = be32_to_cpu(ri.next) & ROMFH_MASK; | ||
392 | } | ||
393 | |||
394 | /* Hard link handling */ | ||
395 | if ((be32_to_cpu(ri.next) & ROMFH_TYPE) == ROMFH_HRD) | ||
396 | offset = be32_to_cpu(ri.spec) & ROMFH_MASK; | ||
397 | |||
398 | inode = romfs_iget(dir->i_sb, offset); | ||
399 | if (IS_ERR(inode)) { | ||
400 | res = PTR_ERR(inode); | ||
401 | goto error; | ||
402 | } | ||
403 | |||
404 | success: | ||
405 | d_add(dentry, inode); | ||
406 | res = 0; | ||
407 | error: | ||
408 | unlock_kernel(); | ||
409 | return ERR_PTR(res); | ||
410 | } | ||
411 | |||
412 | /* | ||
413 | * Ok, we do readpage, to be able to execute programs. Unfortunately, | ||
414 | * we can't use bmap, since we may have looser alignments. | ||
415 | */ | ||
416 | |||
417 | static int | ||
418 | romfs_readpage(struct file *file, struct page * page) | ||
419 | { | ||
420 | struct inode *inode = page->mapping->host; | ||
421 | loff_t offset, size; | ||
422 | unsigned long filled; | ||
423 | void *buf; | ||
424 | int result = -EIO; | ||
425 | |||
426 | page_cache_get(page); | ||
427 | lock_kernel(); | ||
428 | buf = kmap(page); | ||
429 | if (!buf) | ||
430 | goto err_out; | ||
431 | |||
432 | /* 32 bit warning -- but not for us :) */ | ||
433 | offset = page_offset(page); | ||
434 | size = i_size_read(inode); | ||
435 | filled = 0; | ||
436 | result = 0; | ||
437 | if (offset < size) { | ||
438 | unsigned long readlen; | ||
439 | |||
440 | size -= offset; | ||
441 | readlen = size > PAGE_SIZE ? PAGE_SIZE : size; | ||
442 | |||
443 | filled = romfs_copyfrom(inode, buf, ROMFS_I(inode)->i_dataoffset+offset, readlen); | ||
444 | |||
445 | if (filled != readlen) { | ||
446 | SetPageError(page); | ||
447 | filled = 0; | ||
448 | result = -EIO; | ||
449 | } | ||
450 | } | ||
451 | |||
452 | if (filled < PAGE_SIZE) | ||
453 | memset(buf + filled, 0, PAGE_SIZE-filled); | ||
454 | |||
455 | if (!result) | ||
456 | SetPageUptodate(page); | ||
457 | flush_dcache_page(page); | ||
458 | |||
459 | unlock_page(page); | ||
460 | |||
461 | kunmap(page); | ||
462 | err_out: | ||
463 | page_cache_release(page); | ||
464 | unlock_kernel(); | ||
465 | |||
466 | return result; | ||
467 | } | ||
468 | |||
469 | /* Mapping from our types to the kernel */ | ||
470 | |||
471 | static const struct address_space_operations romfs_aops = { | ||
472 | .readpage = romfs_readpage | ||
473 | }; | ||
474 | |||
475 | static const struct file_operations romfs_dir_operations = { | ||
476 | .read = generic_read_dir, | ||
477 | .readdir = romfs_readdir, | ||
478 | }; | ||
479 | |||
480 | static const struct inode_operations romfs_dir_inode_operations = { | ||
481 | .lookup = romfs_lookup, | ||
482 | }; | ||
483 | |||
484 | static mode_t romfs_modemap[] = | ||
485 | { | ||
486 | 0, S_IFDIR+0644, S_IFREG+0644, S_IFLNK+0777, | ||
487 | S_IFBLK+0600, S_IFCHR+0600, S_IFSOCK+0644, S_IFIFO+0644 | ||
488 | }; | ||
489 | |||
490 | static struct inode * | ||
491 | romfs_iget(struct super_block *sb, unsigned long ino) | ||
492 | { | ||
493 | int nextfh, ret; | ||
494 | struct romfs_inode ri; | ||
495 | struct inode *i; | ||
496 | |||
497 | ino &= ROMFH_MASK; | ||
498 | i = iget_locked(sb, ino); | ||
499 | if (!i) | ||
500 | return ERR_PTR(-ENOMEM); | ||
501 | if (!(i->i_state & I_NEW)) | ||
502 | return i; | ||
503 | |||
504 | i->i_mode = 0; | ||
505 | |||
506 | /* Loop for finding the real hard link */ | ||
507 | for(;;) { | ||
508 | if (romfs_copyfrom(i, &ri, ino, ROMFH_SIZE) <= 0) { | ||
509 | printk(KERN_ERR "romfs: read error for inode 0x%lx\n", | ||
510 | ino); | ||
511 | iget_failed(i); | ||
512 | return ERR_PTR(-EIO); | ||
513 | } | ||
514 | /* XXX: do romfs_checksum here too (with name) */ | ||
515 | |||
516 | nextfh = be32_to_cpu(ri.next); | ||
517 | if ((nextfh & ROMFH_TYPE) != ROMFH_HRD) | ||
518 | break; | ||
519 | |||
520 | ino = be32_to_cpu(ri.spec) & ROMFH_MASK; | ||
521 | } | ||
522 | |||
523 | i->i_nlink = 1; /* Hard to decide.. */ | ||
524 | i->i_size = be32_to_cpu(ri.size); | ||
525 | i->i_mtime.tv_sec = i->i_atime.tv_sec = i->i_ctime.tv_sec = 0; | ||
526 | i->i_mtime.tv_nsec = i->i_atime.tv_nsec = i->i_ctime.tv_nsec = 0; | ||
527 | |||
528 | /* Precalculate the data offset */ | ||
529 | ret = romfs_strnlen(i, ino + ROMFH_SIZE, ROMFS_MAXFN); | ||
530 | if (ret >= 0) | ||
531 | ino = (ROMFH_SIZE + ret + 1 + ROMFH_PAD) & ROMFH_MASK; | ||
532 | else | ||
533 | ino = 0; | ||
534 | |||
535 | ROMFS_I(i)->i_metasize = ino; | ||
536 | ROMFS_I(i)->i_dataoffset = ino+(i->i_ino&ROMFH_MASK); | ||
537 | |||
538 | /* Compute permissions */ | ||
539 | ino = romfs_modemap[nextfh & ROMFH_TYPE]; | ||
540 | /* only "normal" files have ops */ | ||
541 | switch (nextfh & ROMFH_TYPE) { | ||
542 | case 1: | ||
543 | i->i_size = ROMFS_I(i)->i_metasize; | ||
544 | i->i_op = &romfs_dir_inode_operations; | ||
545 | i->i_fop = &romfs_dir_operations; | ||
546 | if (nextfh & ROMFH_EXEC) | ||
547 | ino |= S_IXUGO; | ||
548 | i->i_mode = ino; | ||
549 | break; | ||
550 | case 2: | ||
551 | i->i_fop = &generic_ro_fops; | ||
552 | i->i_data.a_ops = &romfs_aops; | ||
553 | if (nextfh & ROMFH_EXEC) | ||
554 | ino |= S_IXUGO; | ||
555 | i->i_mode = ino; | ||
556 | break; | ||
557 | case 3: | ||
558 | i->i_op = &page_symlink_inode_operations; | ||
559 | i->i_data.a_ops = &romfs_aops; | ||
560 | i->i_mode = ino | S_IRWXUGO; | ||
561 | break; | ||
562 | default: | ||
563 | /* depending on MBZ for sock/fifos */ | ||
564 | nextfh = be32_to_cpu(ri.spec); | ||
565 | init_special_inode(i, ino, | ||
566 | MKDEV(nextfh>>16,nextfh&0xffff)); | ||
567 | } | ||
568 | unlock_new_inode(i); | ||
569 | return i; | ||
570 | } | ||
571 | |||
572 | static struct kmem_cache * romfs_inode_cachep; | ||
573 | |||
574 | static struct inode *romfs_alloc_inode(struct super_block *sb) | ||
575 | { | ||
576 | struct romfs_inode_info *ei; | ||
577 | ei = kmem_cache_alloc(romfs_inode_cachep, GFP_KERNEL); | ||
578 | if (!ei) | ||
579 | return NULL; | ||
580 | return &ei->vfs_inode; | ||
581 | } | ||
582 | |||
583 | static void romfs_destroy_inode(struct inode *inode) | ||
584 | { | ||
585 | kmem_cache_free(romfs_inode_cachep, ROMFS_I(inode)); | ||
586 | } | ||
587 | |||
588 | static void init_once(void *foo) | ||
589 | { | ||
590 | struct romfs_inode_info *ei = foo; | ||
591 | |||
592 | inode_init_once(&ei->vfs_inode); | ||
593 | } | ||
594 | |||
595 | static int init_inodecache(void) | ||
596 | { | ||
597 | romfs_inode_cachep = kmem_cache_create("romfs_inode_cache", | ||
598 | sizeof(struct romfs_inode_info), | ||
599 | 0, (SLAB_RECLAIM_ACCOUNT| | ||
600 | SLAB_MEM_SPREAD), | ||
601 | init_once); | ||
602 | if (romfs_inode_cachep == NULL) | ||
603 | return -ENOMEM; | ||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | static void destroy_inodecache(void) | ||
608 | { | ||
609 | kmem_cache_destroy(romfs_inode_cachep); | ||
610 | } | ||
611 | |||
612 | static int romfs_remount(struct super_block *sb, int *flags, char *data) | ||
613 | { | ||
614 | *flags |= MS_RDONLY; | ||
615 | return 0; | ||
616 | } | ||
617 | |||
618 | static const struct super_operations romfs_ops = { | ||
619 | .alloc_inode = romfs_alloc_inode, | ||
620 | .destroy_inode = romfs_destroy_inode, | ||
621 | .statfs = romfs_statfs, | ||
622 | .remount_fs = romfs_remount, | ||
623 | }; | ||
624 | |||
625 | static int romfs_get_sb(struct file_system_type *fs_type, | ||
626 | int flags, const char *dev_name, void *data, struct vfsmount *mnt) | ||
627 | { | ||
628 | return get_sb_bdev(fs_type, flags, dev_name, data, romfs_fill_super, | ||
629 | mnt); | ||
630 | } | ||
631 | |||
632 | static struct file_system_type romfs_fs_type = { | ||
633 | .owner = THIS_MODULE, | ||
634 | .name = "romfs", | ||
635 | .get_sb = romfs_get_sb, | ||
636 | .kill_sb = kill_block_super, | ||
637 | .fs_flags = FS_REQUIRES_DEV, | ||
638 | }; | ||
639 | |||
640 | static int __init init_romfs_fs(void) | ||
641 | { | ||
642 | int err = init_inodecache(); | ||
643 | if (err) | ||
644 | goto out1; | ||
645 | err = register_filesystem(&romfs_fs_type); | ||
646 | if (err) | ||
647 | goto out; | ||
648 | return 0; | ||
649 | out: | ||
650 | destroy_inodecache(); | ||
651 | out1: | ||
652 | return err; | ||
653 | } | ||
654 | |||
655 | static void __exit exit_romfs_fs(void) | ||
656 | { | ||
657 | unregister_filesystem(&romfs_fs_type); | ||
658 | destroy_inodecache(); | ||
659 | } | ||
660 | |||
661 | /* Yes, works even as a module... :) */ | ||
662 | |||
663 | module_init(init_romfs_fs) | ||
664 | module_exit(exit_romfs_fs) | ||
665 | MODULE_LICENSE("GPL"); | ||