vserver 1.9.3
[linux-2.6.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 /* instead of private superblock data */
88 static inline unsigned long romfs_maxsize(struct super_block *sb)
89 {
90         return (unsigned long)sb->s_fs_info;
91 }
92
93 static inline struct romfs_inode_info *ROMFS_I(struct inode *inode)
94 {
95         return list_entry(inode, struct romfs_inode_info, vfs_inode);
96 }
97
98 static __u32
99 romfs_checksum(void *data, int size)
100 {
101         __u32 sum;
102         __be32 *ptr;
103
104         sum = 0; ptr = data;
105         size>>=2;
106         while (size>0) {
107                 sum += be32_to_cpu(*ptr++);
108                 size--;
109         }
110         return sum;
111 }
112
113 static struct super_operations romfs_ops;
114
115 static int romfs_fill_super(struct super_block *s, void *data, int silent)
116 {
117         struct buffer_head *bh;
118         struct romfs_super_block *rsb;
119         struct inode *root;
120         int sz;
121
122         /* I would parse the options here, but there are none.. :) */
123
124         sb_set_blocksize(s, ROMBSIZE);
125         s->s_maxbytes = 0xFFFFFFFF;
126
127         bh = sb_bread(s, 0);
128         if (!bh) {
129                 /* XXX merge with other printk? */
130                 printk ("romfs: unable to read superblock\n");
131                 goto outnobh;
132         }
133
134         rsb = (struct romfs_super_block *)bh->b_data;
135         sz = be32_to_cpu(rsb->size);
136         if (rsb->word0 != ROMSB_WORD0 || rsb->word1 != ROMSB_WORD1
137            || sz < ROMFH_SIZE) {
138                 if (!silent)
139                         printk ("VFS: Can't find a romfs filesystem on dev "
140                                 "%s.\n", s->s_id);
141                 goto out;
142         }
143         if (romfs_checksum(rsb, min_t(int, sz, 512))) {
144                 printk ("romfs: bad initial checksum on dev "
145                         "%s.\n", s->s_id);
146                 goto out;
147         }
148
149         s->s_magic = ROMFS_MAGIC;
150         s->s_fs_info = (void *)(long)sz;
151
152         s->s_flags |= MS_RDONLY;
153
154         /* Find the start of the fs */
155         sz = (ROMFH_SIZE +
156               strnlen(rsb->name, ROMFS_MAXFN) + 1 + ROMFH_PAD)
157              & ROMFH_MASK;
158
159         s->s_op = &romfs_ops;
160         root = iget(s, sz);
161         if (!root)
162                 goto out;
163
164         s->s_root = d_alloc_root(iget(s, sz));
165
166         if (!s->s_root)
167                 goto outiput;
168
169         brelse(bh);
170         return 0;
171
172 outiput:
173         iput(root);
174 out:
175         brelse(bh);
176 outnobh:
177         return -EINVAL;
178 }
179
180 /* That's simple too. */
181
182 static int
183 romfs_statfs(struct super_block *sb, struct kstatfs *buf)
184 {
185         buf->f_type = ROMFS_MAGIC;
186         buf->f_bsize = ROMBSIZE;
187         buf->f_bfree = buf->f_bavail = buf->f_ffree;
188         buf->f_blocks = (romfs_maxsize(sb)+ROMBSIZE-1)>>ROMBSBITS;
189         buf->f_namelen = ROMFS_MAXFN;
190         return 0;
191 }
192
193 /* some helper routines */
194
195 static int
196 romfs_strnlen(struct inode *i, unsigned long offset, unsigned long count)
197 {
198         struct buffer_head *bh;
199         unsigned long avail, maxsize, res;
200
201         maxsize = romfs_maxsize(i->i_sb);
202         if (offset >= maxsize)
203                 return -1;
204
205         /* strnlen is almost always valid */
206         if (count > maxsize || offset+count > maxsize)
207                 count = maxsize-offset;
208
209         bh = sb_bread(i->i_sb, offset>>ROMBSBITS);
210         if (!bh)
211                 return -1;              /* error */
212
213         avail = ROMBSIZE - (offset & ROMBMASK);
214         maxsize = min_t(unsigned long, count, avail);
215         res = strnlen(((char *)bh->b_data)+(offset&ROMBMASK), maxsize);
216         brelse(bh);
217
218         if (res < maxsize)
219                 return res;             /* found all of it */
220
221         while (res < count) {
222                 offset += maxsize;
223
224                 bh = sb_bread(i->i_sb, offset>>ROMBSBITS);
225                 if (!bh)
226                         return -1;
227                 maxsize = min_t(unsigned long, count - res, ROMBSIZE);
228                 avail = strnlen(bh->b_data, maxsize);
229                 res += avail;
230                 brelse(bh);
231                 if (avail < maxsize)
232                         return res;
233         }
234         return res;
235 }
236
237 static int
238 romfs_copyfrom(struct inode *i, void *dest, unsigned long offset, unsigned long count)
239 {
240         struct buffer_head *bh;
241         unsigned long avail, maxsize, res;
242
243         maxsize = romfs_maxsize(i->i_sb);
244         if (offset >= maxsize || count > maxsize || offset+count>maxsize)
245                 return -1;
246
247         bh = sb_bread(i->i_sb, offset>>ROMBSBITS);
248         if (!bh)
249                 return -1;              /* error */
250
251         avail = ROMBSIZE - (offset & ROMBMASK);
252         maxsize = min_t(unsigned long, count, avail);
253         memcpy(dest, ((char *)bh->b_data) + (offset & ROMBMASK), maxsize);
254         brelse(bh);
255
256         res = maxsize;                  /* all of it */
257
258         while (res < count) {
259                 offset += maxsize;
260                 dest += maxsize;
261
262                 bh = sb_bread(i->i_sb, offset>>ROMBSBITS);
263                 if (!bh)
264                         return -1;
265                 maxsize = min_t(unsigned long, count - res, ROMBSIZE);
266                 memcpy(dest, bh->b_data, maxsize);
267                 brelse(bh);
268                 res += maxsize;
269         }
270         return res;
271 }
272
273 static unsigned char romfs_dtype_table[] = {
274         DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_SOCK, DT_FIFO
275 };
276
277 static int
278 romfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
279 {
280         struct inode *i = filp->f_dentry->d_inode;
281         struct romfs_inode ri;
282         unsigned long offset, maxoff;
283         int j, ino, nextfh;
284         int stored = 0;
285         char fsname[ROMFS_MAXFN];       /* XXX dynamic? */
286
287         lock_kernel();
288
289         maxoff = romfs_maxsize(i->i_sb);
290
291         offset = filp->f_pos;
292         if (!offset) {
293                 offset = i->i_ino & ROMFH_MASK;
294                 if (romfs_copyfrom(i, &ri, offset, ROMFH_SIZE) <= 0)
295                         goto out;
296                 offset = be32_to_cpu(ri.spec) & ROMFH_MASK;
297         }
298
299         /* Not really failsafe, but we are read-only... */
300         for(;;) {
301                 if (!offset || offset >= maxoff) {
302                         offset = maxoff;
303                         filp->f_pos = offset;
304                         goto out;
305                 }
306                 filp->f_pos = offset;
307
308                 /* Fetch inode info */
309                 if (romfs_copyfrom(i, &ri, offset, ROMFH_SIZE) <= 0)
310                         goto out;
311
312                 j = romfs_strnlen(i, offset+ROMFH_SIZE, sizeof(fsname)-1);
313                 if (j < 0)
314                         goto out;
315
316                 fsname[j]=0;
317                 romfs_copyfrom(i, fsname, offset+ROMFH_SIZE, j);
318
319                 ino = offset;
320                 nextfh = be32_to_cpu(ri.next);
321                 if ((nextfh & ROMFH_TYPE) == ROMFH_HRD)
322                         ino = be32_to_cpu(ri.spec);
323                 if (filldir(dirent, fsname, j, offset, ino,
324                             romfs_dtype_table[nextfh & ROMFH_TYPE]) < 0) {
325                         goto out;
326                 }
327                 stored++;
328                 offset = nextfh & ROMFH_MASK;
329         }
330 out:
331         unlock_kernel();
332         return stored;
333 }
334
335 static struct dentry *
336 romfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
337 {
338         unsigned long offset, maxoff;
339         int fslen, res;
340         struct inode *inode;
341         char fsname[ROMFS_MAXFN];       /* XXX dynamic? */
342         struct romfs_inode ri;
343         const char *name;               /* got from dentry */
344         int len;
345
346         res = -EACCES;                  /* placeholder for "no data here" */
347         offset = dir->i_ino & ROMFH_MASK;
348         lock_kernel();
349         if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
350                 goto out;
351
352         maxoff = romfs_maxsize(dir->i_sb);
353         offset = be32_to_cpu(ri.spec) & ROMFH_MASK;
354
355         /* OK, now find the file whose name is in "dentry" in the
356          * directory specified by "dir".  */
357
358         name = dentry->d_name.name;
359         len = dentry->d_name.len;
360
361         for(;;) {
362                 if (!offset || offset >= maxoff)
363                         goto out0;
364                 if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
365                         goto out;
366
367                 /* try to match the first 16 bytes of name */
368                 fslen = romfs_strnlen(dir, offset+ROMFH_SIZE, ROMFH_SIZE);
369                 if (len < ROMFH_SIZE) {
370                         if (len == fslen) {
371                                 /* both are shorter, and same size */
372                                 romfs_copyfrom(dir, fsname, offset+ROMFH_SIZE, len+1);
373                                 if (strncmp (name, fsname, len) == 0)
374                                         break;
375                         }
376                 } else if (fslen >= ROMFH_SIZE) {
377                         /* both are longer; XXX optimize max size */
378                         fslen = romfs_strnlen(dir, offset+ROMFH_SIZE, sizeof(fsname)-1);
379                         if (len == fslen) {
380                                 romfs_copyfrom(dir, fsname, offset+ROMFH_SIZE, len+1);
381                                 if (strncmp(name, fsname, len) == 0)
382                                         break;
383                         }
384                 }
385                 /* next entry */
386                 offset = be32_to_cpu(ri.next) & ROMFH_MASK;
387         }
388
389         /* Hard link handling */
390         if ((be32_to_cpu(ri.next) & ROMFH_TYPE) == ROMFH_HRD)
391                 offset = be32_to_cpu(ri.spec) & ROMFH_MASK;
392
393         if ((inode = iget(dir->i_sb, offset)))
394                 goto outi;
395
396         /*
397          * it's a bit funky, _lookup needs to return an error code
398          * (negative) or a NULL, both as a dentry.  ENOENT should not
399          * be returned, instead we need to create a negative dentry by
400          * d_add(dentry, NULL); and return 0 as no error.
401          * (Although as I see, it only matters on writable file
402          * systems).
403          */
404
405 out0:   inode = NULL;
406 outi:   res = 0;
407         d_add (dentry, inode);
408
409 out:    unlock_kernel();
410         return ERR_PTR(res);
411 }
412
413 /*
414  * Ok, we do readpage, to be able to execute programs.  Unfortunately,
415  * we can't use bmap, since we may have looser alignments.
416  */
417
418 static int
419 romfs_readpage(struct file *file, struct page * page)
420 {
421         struct inode *inode = page->mapping->host;
422         unsigned long offset, avail, readlen;
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->index << PAGE_CACHE_SHIFT;
434         if (offset < inode->i_size) {
435                 avail = inode->i_size-offset;
436                 readlen = min_t(unsigned long, avail, PAGE_SIZE);
437                 if (romfs_copyfrom(inode, buf, ROMFS_I(inode)->i_dataoffset+offset, readlen) == readlen) {
438                         if (readlen < PAGE_SIZE) {
439                                 memset(buf + readlen,0,PAGE_SIZE-readlen);
440                         }
441                         SetPageUptodate(page);
442                         result = 0;
443                 }
444         }
445         if (result) {
446                 memset(buf, 0, PAGE_SIZE);
447                 SetPageError(page);
448         }
449         flush_dcache_page(page);
450
451         unlock_page(page);
452
453         kunmap(page);
454 err_out:
455         page_cache_release(page);
456         unlock_kernel();
457
458         return result;
459 }
460
461 /* Mapping from our types to the kernel */
462
463 static struct address_space_operations romfs_aops = {
464         .readpage = romfs_readpage
465 };
466
467 static struct file_operations romfs_dir_operations = {
468         .read           = generic_read_dir,
469         .readdir        = romfs_readdir,
470 };
471
472 static struct inode_operations romfs_dir_inode_operations = {
473         .lookup         = romfs_lookup,
474 };
475
476 static mode_t romfs_modemap[] =
477 {
478         0, S_IFDIR+0644, S_IFREG+0644, S_IFLNK+0777,
479         S_IFBLK+0600, S_IFCHR+0600, S_IFSOCK+0644, S_IFIFO+0644
480 };
481
482 static void
483 romfs_read_inode(struct inode *i)
484 {
485         int nextfh, ino;
486         struct romfs_inode ri;
487
488         ino = i->i_ino & ROMFH_MASK;
489         i->i_mode = 0;
490
491         /* Loop for finding the real hard link */
492         for(;;) {
493                 if (romfs_copyfrom(i, &ri, ino, ROMFH_SIZE) <= 0) {
494                         printk("romfs: read error for inode 0x%x\n", ino);
495                         return;
496                 }
497                 /* XXX: do romfs_checksum here too (with name) */
498
499                 nextfh = be32_to_cpu(ri.next);
500                 if ((nextfh & ROMFH_TYPE) != ROMFH_HRD)
501                         break;
502
503                 ino = be32_to_cpu(ri.spec) & ROMFH_MASK;
504         }
505
506         i->i_nlink = 1;         /* Hard to decide.. */
507         i->i_size = be32_to_cpu(ri.size);
508         i->i_mtime.tv_sec = i->i_atime.tv_sec = i->i_ctime.tv_sec = 0;
509         i->i_mtime.tv_nsec = i->i_atime.tv_nsec = i->i_ctime.tv_nsec = 0;
510         i->i_uid = i->i_gid = 0;
511
512         /* Precalculate the data offset */
513         ino = romfs_strnlen(i, ino+ROMFH_SIZE, ROMFS_MAXFN);
514         if (ino >= 0)
515                 ino = ((ROMFH_SIZE+ino+1+ROMFH_PAD)&ROMFH_MASK);
516         else
517                 ino = 0;
518
519         ROMFS_I(i)->i_metasize = ino;
520         ROMFS_I(i)->i_dataoffset = ino+(i->i_ino&ROMFH_MASK);
521
522         /* Compute permissions */
523         ino = romfs_modemap[nextfh & ROMFH_TYPE];
524         /* only "normal" files have ops */
525         switch (nextfh & ROMFH_TYPE) {
526                 case 1:
527                         i->i_size = ROMFS_I(i)->i_metasize;
528                         i->i_op = &romfs_dir_inode_operations;
529                         i->i_fop = &romfs_dir_operations;
530                         if (nextfh & ROMFH_EXEC)
531                                 ino |= S_IXUGO;
532                         i->i_mode = ino;
533                         break;
534                 case 2:
535                         i->i_fop = &generic_ro_fops;
536                         i->i_data.a_ops = &romfs_aops;
537                         if (nextfh & ROMFH_EXEC)
538                                 ino |= S_IXUGO;
539                         i->i_mode = ino;
540                         break;
541                 case 3:
542                         i->i_op = &page_symlink_inode_operations;
543                         i->i_data.a_ops = &romfs_aops;
544                         i->i_mode = ino | S_IRWXUGO;
545                         break;
546                 default:
547                         /* depending on MBZ for sock/fifos */
548                         nextfh = be32_to_cpu(ri.spec);
549                         init_special_inode(i, ino,
550                                         MKDEV(nextfh>>16,nextfh&0xffff));
551         }
552 }
553
554 static kmem_cache_t * romfs_inode_cachep;
555
556 static struct inode *romfs_alloc_inode(struct super_block *sb)
557 {
558         struct romfs_inode_info *ei;
559         ei = (struct romfs_inode_info *)kmem_cache_alloc(romfs_inode_cachep, SLAB_KERNEL);
560         if (!ei)
561                 return NULL;
562         return &ei->vfs_inode;
563 }
564
565 static void romfs_destroy_inode(struct inode *inode)
566 {
567         kmem_cache_free(romfs_inode_cachep, ROMFS_I(inode));
568 }
569
570 static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
571 {
572         struct romfs_inode_info *ei = (struct romfs_inode_info *) foo;
573
574         if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
575             SLAB_CTOR_CONSTRUCTOR)
576                 inode_init_once(&ei->vfs_inode);
577 }
578  
579 static int init_inodecache(void)
580 {
581         romfs_inode_cachep = kmem_cache_create("romfs_inode_cache",
582                                              sizeof(struct romfs_inode_info),
583                                              0, SLAB_RECLAIM_ACCOUNT,
584                                              init_once, NULL);
585         if (romfs_inode_cachep == NULL)
586                 return -ENOMEM;
587         return 0;
588 }
589
590 static void destroy_inodecache(void)
591 {
592         if (kmem_cache_destroy(romfs_inode_cachep))
593                 printk(KERN_INFO "romfs_inode_cache: not all structures were freed\n");
594 }
595
596 static int romfs_remount(struct super_block *sb, int *flags, char *data)
597 {
598         *flags |= MS_RDONLY;
599         return 0;
600 }
601
602 static struct super_operations romfs_ops = {
603         .alloc_inode    = romfs_alloc_inode,
604         .destroy_inode  = romfs_destroy_inode,
605         .read_inode     = romfs_read_inode,
606         .statfs         = romfs_statfs,
607         .remount_fs     = romfs_remount,
608 };
609
610 static struct super_block *romfs_get_sb(struct file_system_type *fs_type,
611         int flags, const char *dev_name, void *data)
612 {
613         return get_sb_bdev(fs_type, flags, dev_name, data, romfs_fill_super);
614 }
615
616 static struct file_system_type romfs_fs_type = {
617         .owner          = THIS_MODULE,
618         .name           = "romfs",
619         .get_sb         = romfs_get_sb,
620         .kill_sb        = kill_block_super,
621         .fs_flags       = FS_REQUIRES_DEV,
622 };
623
624 static int __init init_romfs_fs(void)
625 {
626         int err = init_inodecache();
627         if (err)
628                 goto out1;
629         err = register_filesystem(&romfs_fs_type);
630         if (err)
631                 goto out;
632         return 0;
633 out:
634         destroy_inodecache();
635 out1:
636         return err;
637 }
638
639 static void __exit exit_romfs_fs(void)
640 {
641         unregister_filesystem(&romfs_fs_type);
642         destroy_inodecache();
643 }
644
645 /* Yes, works even as a module... :) */
646
647 module_init(init_romfs_fs)
648 module_exit(exit_romfs_fs)
649 MODULE_LICENSE("GPL");