Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at c9a28fa7b9ac19b676deefa0a171ce7df8755c08 647 lines 16 kB view raw
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 81struct 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 */ 88static inline unsigned long romfs_maxsize(struct super_block *sb) 89{ 90 return (unsigned long)sb->s_fs_info; 91} 92 93static inline struct romfs_inode_info *ROMFS_I(struct inode *inode) 94{ 95 return container_of(inode, struct romfs_inode_info, vfs_inode); 96} 97 98static __u32 99romfs_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 113static const struct super_operations romfs_ops; 114 115static 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 171outiput: 172 iput(root); 173out: 174 brelse(bh); 175outnobh: 176 return -EINVAL; 177} 178 179/* That's simple too. */ 180 181static int 182romfs_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 194static int 195romfs_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 236static int 237romfs_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 272static unsigned char romfs_dtype_table[] = { 273 DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_SOCK, DT_FIFO 274}; 275 276static int 277romfs_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 } 329out: 330 unlock_kernel(); 331 return stored; 332} 333 334static struct dentry * 335romfs_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 404out0: inode = NULL; 405outi: res = 0; 406 d_add (dentry, inode); 407 408out: 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 417static int 418romfs_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); 453err_out: 454 page_cache_release(page); 455 unlock_kernel(); 456 457 return result; 458} 459 460/* Mapping from our types to the kernel */ 461 462static const struct address_space_operations romfs_aops = { 463 .readpage = romfs_readpage 464}; 465 466static const struct file_operations romfs_dir_operations = { 467 .read = generic_read_dir, 468 .readdir = romfs_readdir, 469}; 470 471static const struct inode_operations romfs_dir_inode_operations = { 472 .lookup = romfs_lookup, 473}; 474 475static 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 481static void 482romfs_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 553static struct kmem_cache * romfs_inode_cachep; 554 555static struct inode *romfs_alloc_inode(struct super_block *sb) 556{ 557 struct romfs_inode_info *ei; 558 ei = kmem_cache_alloc(romfs_inode_cachep, GFP_KERNEL); 559 if (!ei) 560 return NULL; 561 return &ei->vfs_inode; 562} 563 564static void romfs_destroy_inode(struct inode *inode) 565{ 566 kmem_cache_free(romfs_inode_cachep, ROMFS_I(inode)); 567} 568 569static void init_once(struct kmem_cache *cachep, void *foo) 570{ 571 struct romfs_inode_info *ei = foo; 572 573 inode_init_once(&ei->vfs_inode); 574} 575 576static 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); 583 if (romfs_inode_cachep == NULL) 584 return -ENOMEM; 585 return 0; 586} 587 588static void destroy_inodecache(void) 589{ 590 kmem_cache_destroy(romfs_inode_cachep); 591} 592 593static int romfs_remount(struct super_block *sb, int *flags, char *data) 594{ 595 *flags |= MS_RDONLY; 596 return 0; 597} 598 599static 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 607static 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 614static 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 622static 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; 631out: 632 destroy_inodecache(); 633out1: 634 return err; 635} 636 637static 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 645module_init(init_romfs_fs) 646module_exit(exit_romfs_fs) 647MODULE_LICENSE("GPL");