knfsd: exportfs: add find_disconnected_root helper
[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 /* 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 const 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(root);
165         if (!s->s_root)
166                 goto outiput;
167
168         brelse(bh);
169         return 0;
170
171 outiput:
172         iput(root);
173 out:
174         brelse(bh);
175 outnobh:
176         return -EINVAL;
177 }
178
179 /* That's simple too. */
180
181 static int
182 romfs_statfs(struct dentry *dentry, struct kstatfs *buf)
183 {
184         buf->f_type = ROMFS_MAGIC;
185         buf->f_bsize = ROMBSIZE;
186         buf->f_bfree = buf->f_bavail = buf->f_ffree;
187         buf->f_blocks = (romfs_maxsize(dentry->d_sb)+ROMBSIZE-1)>>ROMBSBITS;
188         buf->f_namelen = ROMFS_MAXFN;
189         return 0;
190 }
191
192 /* some helper routines */
193
194 static int
195 romfs_strnlen(struct inode *i, unsigned long offset, unsigned long count)
196 {
197         struct buffer_head *bh;
198         unsigned long avail, maxsize, res;
199
200         maxsize = romfs_maxsize(i->i_sb);
201         if (offset >= maxsize)
202                 return -1;
203
204         /* strnlen is almost always valid */
205         if (count > maxsize || offset+count > maxsize)
206                 count = maxsize-offset;
207
208         bh = sb_bread(i->i_sb, offset>>ROMBSBITS);
209         if (!bh)
210                 return -1;              /* error */
211
212         avail = ROMBSIZE - (offset & ROMBMASK);
213         maxsize = min_t(unsigned long, count, avail);
214         res = strnlen(((char *)bh->b_data)+(offset&ROMBMASK), maxsize);
215         brelse(bh);
216
217         if (res < maxsize)
218                 return res;             /* found all of it */
219
220         while (res < count) {
221                 offset += maxsize;
222
223                 bh = sb_bread(i->i_sb, offset>>ROMBSBITS);
224                 if (!bh)
225                         return -1;
226                 maxsize = min_t(unsigned long, count - res, ROMBSIZE);
227                 avail = strnlen(bh->b_data, maxsize);
228                 res += avail;
229                 brelse(bh);
230                 if (avail < maxsize)
231                         return res;
232         }
233         return res;
234 }
235
236 static int
237 romfs_copyfrom(struct inode *i, void *dest, unsigned long offset, unsigned long count)
238 {
239         struct buffer_head *bh;
240         unsigned long avail, maxsize, res;
241
242         maxsize = romfs_maxsize(i->i_sb);
243         if (offset >= maxsize || count > maxsize || offset+count>maxsize)
244                 return -1;
245
246         bh = sb_bread(i->i_sb, offset>>ROMBSBITS);
247         if (!bh)
248                 return -1;              /* error */
249
250         avail = ROMBSIZE - (offset & ROMBMASK);
251         maxsize = min_t(unsigned long, count, avail);
252         memcpy(dest, ((char *)bh->b_data) + (offset & ROMBMASK), maxsize);
253         brelse(bh);
254
255         res = maxsize;                  /* all of it */
256
257         while (res < count) {
258                 offset += maxsize;
259                 dest += maxsize;
260
261                 bh = sb_bread(i->i_sb, offset>>ROMBSBITS);
262                 if (!bh)
263                         return -1;
264                 maxsize = min_t(unsigned long, count - res, ROMBSIZE);
265                 memcpy(dest, bh->b_data, maxsize);
266                 brelse(bh);
267                 res += maxsize;
268         }
269         return res;
270 }
271
272 static unsigned char romfs_dtype_table[] = {
273         DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_SOCK, DT_FIFO
274 };
275
276 static int
277 romfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
278 {
279         struct inode *i = filp->f_path.dentry->d_inode;
280         struct romfs_inode ri;
281         unsigned long offset, maxoff;
282         int j, ino, nextfh;
283         int stored = 0;
284         char fsname[ROMFS_MAXFN];       /* XXX dynamic? */
285
286         lock_kernel();
287
288         maxoff = romfs_maxsize(i->i_sb);
289
290         offset = filp->f_pos;
291         if (!offset) {
292                 offset = i->i_ino & ROMFH_MASK;
293                 if (romfs_copyfrom(i, &ri, offset, ROMFH_SIZE) <= 0)
294                         goto out;
295                 offset = be32_to_cpu(ri.spec) & ROMFH_MASK;
296         }
297
298         /* Not really failsafe, but we are read-only... */
299         for(;;) {
300                 if (!offset || offset >= maxoff) {
301                         offset = maxoff;
302                         filp->f_pos = offset;
303                         goto out;
304                 }
305                 filp->f_pos = offset;
306
307                 /* Fetch inode info */
308                 if (romfs_copyfrom(i, &ri, offset, ROMFH_SIZE) <= 0)
309                         goto out;
310
311                 j = romfs_strnlen(i, offset+ROMFH_SIZE, sizeof(fsname)-1);
312                 if (j < 0)
313                         goto out;
314
315                 fsname[j]=0;
316                 romfs_copyfrom(i, fsname, offset+ROMFH_SIZE, j);
317
318                 ino = offset;
319                 nextfh = be32_to_cpu(ri.next);
320                 if ((nextfh & ROMFH_TYPE) == ROMFH_HRD)
321                         ino = be32_to_cpu(ri.spec);
322                 if (filldir(dirent, fsname, j, offset, ino,
323                             romfs_dtype_table[nextfh & ROMFH_TYPE]) < 0) {
324                         goto out;
325                 }
326                 stored++;
327                 offset = nextfh & ROMFH_MASK;
328         }
329 out:
330         unlock_kernel();
331         return stored;
332 }
333
334 static struct dentry *
335 romfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
336 {
337         unsigned long offset, maxoff;
338         int fslen, res;
339         struct inode *inode;
340         char fsname[ROMFS_MAXFN];       /* XXX dynamic? */
341         struct romfs_inode ri;
342         const char *name;               /* got from dentry */
343         int len;
344
345         res = -EACCES;                  /* placeholder for "no data here" */
346         offset = dir->i_ino & ROMFH_MASK;
347         lock_kernel();
348         if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
349                 goto out;
350
351         maxoff = romfs_maxsize(dir->i_sb);
352         offset = be32_to_cpu(ri.spec) & ROMFH_MASK;
353
354         /* OK, now find the file whose name is in "dentry" in the
355          * directory specified by "dir".  */
356
357         name = dentry->d_name.name;
358         len = dentry->d_name.len;
359
360         for(;;) {
361                 if (!offset || offset >= maxoff)
362                         goto out0;
363                 if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
364                         goto out;
365
366                 /* try to match the first 16 bytes of name */
367                 fslen = romfs_strnlen(dir, offset+ROMFH_SIZE, ROMFH_SIZE);
368                 if (len < ROMFH_SIZE) {
369                         if (len == fslen) {
370                                 /* both are shorter, and same size */
371                                 romfs_copyfrom(dir, fsname, offset+ROMFH_SIZE, len+1);
372                                 if (strncmp (name, fsname, len) == 0)
373                                         break;
374                         }
375                 } else if (fslen >= ROMFH_SIZE) {
376                         /* both are longer; XXX optimize max size */
377                         fslen = romfs_strnlen(dir, offset+ROMFH_SIZE, sizeof(fsname)-1);
378                         if (len == fslen) {
379                                 romfs_copyfrom(dir, fsname, offset+ROMFH_SIZE, len+1);
380                                 if (strncmp(name, fsname, len) == 0)
381                                         break;
382                         }
383                 }
384                 /* next entry */
385                 offset = be32_to_cpu(ri.next) & ROMFH_MASK;
386         }
387
388         /* Hard link handling */
389         if ((be32_to_cpu(ri.next) & ROMFH_TYPE) == ROMFH_HRD)
390                 offset = be32_to_cpu(ri.spec) & ROMFH_MASK;
391
392         if ((inode = iget(dir->i_sb, offset)))
393                 goto outi;
394
395         /*
396          * it's a bit funky, _lookup needs to return an error code
397          * (negative) or a NULL, both as a dentry.  ENOENT should not
398          * be returned, instead we need to create a negative dentry by
399          * d_add(dentry, NULL); and return 0 as no error.
400          * (Although as I see, it only matters on writable file
401          * systems).
402          */
403
404 out0:   inode = NULL;
405 outi:   res = 0;
406         d_add (dentry, inode);
407
408 out:    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 void
482 romfs_read_inode(struct inode *i)
483 {
484         int nextfh, ino;
485         struct romfs_inode ri;
486
487         ino = i->i_ino & ROMFH_MASK;
488         i->i_mode = 0;
489
490         /* Loop for finding the real hard link */
491         for(;;) {
492                 if (romfs_copyfrom(i, &ri, ino, ROMFH_SIZE) <= 0) {
493                         printk("romfs: read error for inode 0x%x\n", ino);
494                         return;
495                 }
496                 /* XXX: do romfs_checksum here too (with name) */
497
498                 nextfh = be32_to_cpu(ri.next);
499                 if ((nextfh & ROMFH_TYPE) != ROMFH_HRD)
500                         break;
501
502                 ino = be32_to_cpu(ri.spec) & ROMFH_MASK;
503         }
504
505         i->i_nlink = 1;         /* Hard to decide.. */
506         i->i_size = be32_to_cpu(ri.size);
507         i->i_mtime.tv_sec = i->i_atime.tv_sec = i->i_ctime.tv_sec = 0;
508         i->i_mtime.tv_nsec = i->i_atime.tv_nsec = i->i_ctime.tv_nsec = 0;
509         i->i_uid = i->i_gid = 0;
510
511         /* Precalculate the data offset */
512         ino = romfs_strnlen(i, ino+ROMFH_SIZE, ROMFS_MAXFN);
513         if (ino >= 0)
514                 ino = ((ROMFH_SIZE+ino+1+ROMFH_PAD)&ROMFH_MASK);
515         else
516                 ino = 0;
517
518         ROMFS_I(i)->i_metasize = ino;
519         ROMFS_I(i)->i_dataoffset = ino+(i->i_ino&ROMFH_MASK);
520
521         /* Compute permissions */
522         ino = romfs_modemap[nextfh & ROMFH_TYPE];
523         /* only "normal" files have ops */
524         switch (nextfh & ROMFH_TYPE) {
525                 case 1:
526                         i->i_size = ROMFS_I(i)->i_metasize;
527                         i->i_op = &romfs_dir_inode_operations;
528                         i->i_fop = &romfs_dir_operations;
529                         if (nextfh & ROMFH_EXEC)
530                                 ino |= S_IXUGO;
531                         i->i_mode = ino;
532                         break;
533                 case 2:
534                         i->i_fop = &generic_ro_fops;
535                         i->i_data.a_ops = &romfs_aops;
536                         if (nextfh & ROMFH_EXEC)
537                                 ino |= S_IXUGO;
538                         i->i_mode = ino;
539                         break;
540                 case 3:
541                         i->i_op = &page_symlink_inode_operations;
542                         i->i_data.a_ops = &romfs_aops;
543                         i->i_mode = ino | S_IRWXUGO;
544                         break;
545                 default:
546                         /* depending on MBZ for sock/fifos */
547                         nextfh = be32_to_cpu(ri.spec);
548                         init_special_inode(i, ino,
549                                         MKDEV(nextfh>>16,nextfh&0xffff));
550         }
551 }
552
553 static struct kmem_cache * romfs_inode_cachep;
554
555 static struct inode *romfs_alloc_inode(struct super_block *sb)
556 {
557         struct romfs_inode_info *ei;
558         ei = (struct romfs_inode_info *)kmem_cache_alloc(romfs_inode_cachep, GFP_KERNEL);
559         if (!ei)
560                 return NULL;
561         return &ei->vfs_inode;
562 }
563
564 static void romfs_destroy_inode(struct inode *inode)
565 {
566         kmem_cache_free(romfs_inode_cachep, ROMFS_I(inode));
567 }
568
569 static void init_once(void *foo, struct kmem_cache *cachep, unsigned long flags)
570 {
571         struct romfs_inode_info *ei = foo;
572
573         inode_init_once(&ei->vfs_inode);
574 }
575  
576 static int init_inodecache(void)
577 {
578         romfs_inode_cachep = kmem_cache_create("romfs_inode_cache",
579                                              sizeof(struct romfs_inode_info),
580                                              0, (SLAB_RECLAIM_ACCOUNT|
581                                                 SLAB_MEM_SPREAD),
582                                              init_once, NULL);
583         if (romfs_inode_cachep == NULL)
584                 return -ENOMEM;
585         return 0;
586 }
587
588 static void destroy_inodecache(void)
589 {
590         kmem_cache_destroy(romfs_inode_cachep);
591 }
592
593 static int romfs_remount(struct super_block *sb, int *flags, char *data)
594 {
595         *flags |= MS_RDONLY;
596         return 0;
597 }
598
599 static const struct super_operations romfs_ops = {
600         .alloc_inode    = romfs_alloc_inode,
601         .destroy_inode  = romfs_destroy_inode,
602         .read_inode     = romfs_read_inode,
603         .statfs         = romfs_statfs,
604         .remount_fs     = romfs_remount,
605 };
606
607 static int romfs_get_sb(struct file_system_type *fs_type,
608         int flags, const char *dev_name, void *data, struct vfsmount *mnt)
609 {
610         return get_sb_bdev(fs_type, flags, dev_name, data, romfs_fill_super,
611                            mnt);
612 }
613
614 static struct file_system_type romfs_fs_type = {
615         .owner          = THIS_MODULE,
616         .name           = "romfs",
617         .get_sb         = romfs_get_sb,
618         .kill_sb        = kill_block_super,
619         .fs_flags       = FS_REQUIRES_DEV,
620 };
621
622 static int __init init_romfs_fs(void)
623 {
624         int err = init_inodecache();
625         if (err)
626                 goto out1;
627         err = register_filesystem(&romfs_fs_type);
628         if (err)
629                 goto out;
630         return 0;
631 out:
632         destroy_inodecache();
633 out1:
634         return err;
635 }
636
637 static void __exit exit_romfs_fs(void)
638 {
639         unregister_filesystem(&romfs_fs_type);
640         destroy_inodecache();
641 }
642
643 /* Yes, works even as a module... :) */
644
645 module_init(init_romfs_fs)
646 module_exit(exit_romfs_fs)
647 MODULE_LICENSE("GPL");