Merge branch 'sched/for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip...
[linux-2.6] / 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, avail, readlen;
422         void *buf;
423         int result = -EIO;
424
425         page_cache_get(page);
426         lock_kernel();
427         buf = kmap(page);
428         if (!buf)
429                 goto err_out;
430
431         /* 32 bit warning -- but not for us :) */
432         offset = page_offset(page);
433         if (offset < i_size_read(inode)) {
434                 avail = inode->i_size-offset;
435                 readlen = min_t(unsigned long, avail, PAGE_SIZE);
436                 if (romfs_copyfrom(inode, buf, ROMFS_I(inode)->i_dataoffset+offset, readlen) == readlen) {
437                         if (readlen < PAGE_SIZE) {
438                                 memset(buf + readlen,0,PAGE_SIZE-readlen);
439                         }
440                         SetPageUptodate(page);
441                         result = 0;
442                 }
443         }
444         if (result) {
445                 memset(buf, 0, PAGE_SIZE);
446                 SetPageError(page);
447         }
448         flush_dcache_page(page);
449
450         unlock_page(page);
451
452         kunmap(page);
453 err_out:
454         page_cache_release(page);
455         unlock_kernel();
456
457         return result;
458 }
459
460 /* Mapping from our types to the kernel */
461
462 static const struct address_space_operations romfs_aops = {
463         .readpage = romfs_readpage
464 };
465
466 static const struct file_operations romfs_dir_operations = {
467         .read           = generic_read_dir,
468         .readdir        = romfs_readdir,
469 };
470
471 static const struct inode_operations romfs_dir_inode_operations = {
472         .lookup         = romfs_lookup,
473 };
474
475 static mode_t romfs_modemap[] =
476 {
477         0, S_IFDIR+0644, S_IFREG+0644, S_IFLNK+0777,
478         S_IFBLK+0600, S_IFCHR+0600, S_IFSOCK+0644, S_IFIFO+0644
479 };
480
481 static struct inode *
482 romfs_iget(struct super_block *sb, unsigned long ino)
483 {
484         int nextfh;
485         struct romfs_inode ri;
486         struct inode *i;
487
488         ino &= ROMFH_MASK;
489         i = iget_locked(sb, ino);
490         if (!i)
491                 return ERR_PTR(-ENOMEM);
492         if (!(i->i_state & I_NEW))
493                 return i;
494
495         i->i_mode = 0;
496
497         /* Loop for finding the real hard link */
498         for(;;) {
499                 if (romfs_copyfrom(i, &ri, ino, ROMFH_SIZE) <= 0) {
500                         printk(KERN_ERR "romfs: read error for inode 0x%lx\n",
501                                 ino);
502                         iget_failed(i);
503                         return ERR_PTR(-EIO);
504                 }
505                 /* XXX: do romfs_checksum here too (with name) */
506
507                 nextfh = be32_to_cpu(ri.next);
508                 if ((nextfh & ROMFH_TYPE) != ROMFH_HRD)
509                         break;
510
511                 ino = be32_to_cpu(ri.spec) & ROMFH_MASK;
512         }
513
514         i->i_nlink = 1;         /* Hard to decide.. */
515         i->i_size = be32_to_cpu(ri.size);
516         i->i_mtime.tv_sec = i->i_atime.tv_sec = i->i_ctime.tv_sec = 0;
517         i->i_mtime.tv_nsec = i->i_atime.tv_nsec = i->i_ctime.tv_nsec = 0;
518         i->i_uid = i->i_gid = 0;
519
520         /* Precalculate the data offset */
521         ino = romfs_strnlen(i, ino+ROMFH_SIZE, ROMFS_MAXFN);
522         if (ino >= 0)
523                 ino = ((ROMFH_SIZE+ino+1+ROMFH_PAD)&ROMFH_MASK);
524         else
525                 ino = 0;
526
527         ROMFS_I(i)->i_metasize = ino;
528         ROMFS_I(i)->i_dataoffset = ino+(i->i_ino&ROMFH_MASK);
529
530         /* Compute permissions */
531         ino = romfs_modemap[nextfh & ROMFH_TYPE];
532         /* only "normal" files have ops */
533         switch (nextfh & ROMFH_TYPE) {
534                 case 1:
535                         i->i_size = ROMFS_I(i)->i_metasize;
536                         i->i_op = &romfs_dir_inode_operations;
537                         i->i_fop = &romfs_dir_operations;
538                         if (nextfh & ROMFH_EXEC)
539                                 ino |= S_IXUGO;
540                         i->i_mode = ino;
541                         break;
542                 case 2:
543                         i->i_fop = &generic_ro_fops;
544                         i->i_data.a_ops = &romfs_aops;
545                         if (nextfh & ROMFH_EXEC)
546                                 ino |= S_IXUGO;
547                         i->i_mode = ino;
548                         break;
549                 case 3:
550                         i->i_op = &page_symlink_inode_operations;
551                         i->i_data.a_ops = &romfs_aops;
552                         i->i_mode = ino | S_IRWXUGO;
553                         break;
554                 default:
555                         /* depending on MBZ for sock/fifos */
556                         nextfh = be32_to_cpu(ri.spec);
557                         init_special_inode(i, ino,
558                                         MKDEV(nextfh>>16,nextfh&0xffff));
559         }
560         unlock_new_inode(i);
561         return i;
562 }
563
564 static struct kmem_cache * romfs_inode_cachep;
565
566 static struct inode *romfs_alloc_inode(struct super_block *sb)
567 {
568         struct romfs_inode_info *ei;
569         ei = kmem_cache_alloc(romfs_inode_cachep, GFP_KERNEL);
570         if (!ei)
571                 return NULL;
572         return &ei->vfs_inode;
573 }
574
575 static void romfs_destroy_inode(struct inode *inode)
576 {
577         kmem_cache_free(romfs_inode_cachep, ROMFS_I(inode));
578 }
579
580 static void init_once(struct kmem_cache *cachep, void *foo)
581 {
582         struct romfs_inode_info *ei = foo;
583
584         inode_init_once(&ei->vfs_inode);
585 }
586
587 static int init_inodecache(void)
588 {
589         romfs_inode_cachep = kmem_cache_create("romfs_inode_cache",
590                                              sizeof(struct romfs_inode_info),
591                                              0, (SLAB_RECLAIM_ACCOUNT|
592                                                 SLAB_MEM_SPREAD),
593                                              init_once);
594         if (romfs_inode_cachep == NULL)
595                 return -ENOMEM;
596         return 0;
597 }
598
599 static void destroy_inodecache(void)
600 {
601         kmem_cache_destroy(romfs_inode_cachep);
602 }
603
604 static int romfs_remount(struct super_block *sb, int *flags, char *data)
605 {
606         *flags |= MS_RDONLY;
607         return 0;
608 }
609
610 static const struct super_operations romfs_ops = {
611         .alloc_inode    = romfs_alloc_inode,
612         .destroy_inode  = romfs_destroy_inode,
613         .statfs         = romfs_statfs,
614         .remount_fs     = romfs_remount,
615 };
616
617 static int romfs_get_sb(struct file_system_type *fs_type,
618         int flags, const char *dev_name, void *data, struct vfsmount *mnt)
619 {
620         return get_sb_bdev(fs_type, flags, dev_name, data, romfs_fill_super,
621                            mnt);
622 }
623
624 static struct file_system_type romfs_fs_type = {
625         .owner          = THIS_MODULE,
626         .name           = "romfs",
627         .get_sb         = romfs_get_sb,
628         .kill_sb        = kill_block_super,
629         .fs_flags       = FS_REQUIRES_DEV,
630 };
631
632 static int __init init_romfs_fs(void)
633 {
634         int err = init_inodecache();
635         if (err)
636                 goto out1;
637         err = register_filesystem(&romfs_fs_type);
638         if (err)
639                 goto out;
640         return 0;
641 out:
642         destroy_inodecache();
643 out1:
644         return err;
645 }
646
647 static void __exit exit_romfs_fs(void)
648 {
649         unregister_filesystem(&romfs_fs_type);
650         destroy_inodecache();
651 }
652
653 /* Yes, works even as a module... :) */
654
655 module_init(init_romfs_fs)
656 module_exit(exit_romfs_fs)
657 MODULE_LICENSE("GPL");