Merge git://git.infradead.org/mtd-2.6
[pandora-kernel.git] / fs / romfs / inode.c
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;
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         i->i_uid = i->i_gid = 0;
528
529         /* Precalculate the data offset */
530         ino = romfs_strnlen(i, ino+ROMFH_SIZE, ROMFS_MAXFN);
531         if (ino >= 0)
532                 ino = ((ROMFH_SIZE+ino+1+ROMFH_PAD)&ROMFH_MASK);
533         else
534                 ino = 0;
535
536         ROMFS_I(i)->i_metasize = ino;
537         ROMFS_I(i)->i_dataoffset = ino+(i->i_ino&ROMFH_MASK);
538
539         /* Compute permissions */
540         ino = romfs_modemap[nextfh & ROMFH_TYPE];
541         /* only "normal" files have ops */
542         switch (nextfh & ROMFH_TYPE) {
543                 case 1:
544                         i->i_size = ROMFS_I(i)->i_metasize;
545                         i->i_op = &romfs_dir_inode_operations;
546                         i->i_fop = &romfs_dir_operations;
547                         if (nextfh & ROMFH_EXEC)
548                                 ino |= S_IXUGO;
549                         i->i_mode = ino;
550                         break;
551                 case 2:
552                         i->i_fop = &generic_ro_fops;
553                         i->i_data.a_ops = &romfs_aops;
554                         if (nextfh & ROMFH_EXEC)
555                                 ino |= S_IXUGO;
556                         i->i_mode = ino;
557                         break;
558                 case 3:
559                         i->i_op = &page_symlink_inode_operations;
560                         i->i_data.a_ops = &romfs_aops;
561                         i->i_mode = ino | S_IRWXUGO;
562                         break;
563                 default:
564                         /* depending on MBZ for sock/fifos */
565                         nextfh = be32_to_cpu(ri.spec);
566                         init_special_inode(i, ino,
567                                         MKDEV(nextfh>>16,nextfh&0xffff));
568         }
569         unlock_new_inode(i);
570         return i;
571 }
572
573 static struct kmem_cache * romfs_inode_cachep;
574
575 static struct inode *romfs_alloc_inode(struct super_block *sb)
576 {
577         struct romfs_inode_info *ei;
578         ei = kmem_cache_alloc(romfs_inode_cachep, GFP_KERNEL);
579         if (!ei)
580                 return NULL;
581         return &ei->vfs_inode;
582 }
583
584 static void romfs_destroy_inode(struct inode *inode)
585 {
586         kmem_cache_free(romfs_inode_cachep, ROMFS_I(inode));
587 }
588
589 static void init_once(void *foo)
590 {
591         struct romfs_inode_info *ei = foo;
592
593         inode_init_once(&ei->vfs_inode);
594 }
595
596 static int init_inodecache(void)
597 {
598         romfs_inode_cachep = kmem_cache_create("romfs_inode_cache",
599                                              sizeof(struct romfs_inode_info),
600                                              0, (SLAB_RECLAIM_ACCOUNT|
601                                                 SLAB_MEM_SPREAD),
602                                              init_once);
603         if (romfs_inode_cachep == NULL)
604                 return -ENOMEM;
605         return 0;
606 }
607
608 static void destroy_inodecache(void)
609 {
610         kmem_cache_destroy(romfs_inode_cachep);
611 }
612
613 static int romfs_remount(struct super_block *sb, int *flags, char *data)
614 {
615         *flags |= MS_RDONLY;
616         return 0;
617 }
618
619 static const struct super_operations romfs_ops = {
620         .alloc_inode    = romfs_alloc_inode,
621         .destroy_inode  = romfs_destroy_inode,
622         .statfs         = romfs_statfs,
623         .remount_fs     = romfs_remount,
624 };
625
626 static int romfs_get_sb(struct file_system_type *fs_type,
627         int flags, const char *dev_name, void *data, struct vfsmount *mnt)
628 {
629         return get_sb_bdev(fs_type, flags, dev_name, data, romfs_fill_super,
630                            mnt);
631 }
632
633 static struct file_system_type romfs_fs_type = {
634         .owner          = THIS_MODULE,
635         .name           = "romfs",
636         .get_sb         = romfs_get_sb,
637         .kill_sb        = kill_block_super,
638         .fs_flags       = FS_REQUIRES_DEV,
639 };
640
641 static int __init init_romfs_fs(void)
642 {
643         int err = init_inodecache();
644         if (err)
645                 goto out1;
646         err = register_filesystem(&romfs_fs_type);
647         if (err)
648                 goto out;
649         return 0;
650 out:
651         destroy_inodecache();
652 out1:
653         return err;
654 }
655
656 static void __exit exit_romfs_fs(void)
657 {
658         unregister_filesystem(&romfs_fs_type);
659         destroy_inodecache();
660 }
661
662 /* Yes, works even as a module... :) */
663
664 module_init(init_romfs_fs)
665 module_exit(exit_romfs_fs)
666 MODULE_LICENSE("GPL");