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

NOMMU: Make it possible for RomFS to use MTD devices directly

Change RomFS so that it can use MTD devices directly - without the intercession
of the block layer - as well as using block devices.

This permits RomFS:

(1) to use the MTD direct mapping facility available under NOMMU conditions if
the underlying device is directly accessible by the CPU (including XIP);

(2) and thus to be used when the block layer is disabled.

RomFS can be configured with support just for MTD devices, just for Block
devices or for both. If RomFS is configured for both, then it will treat
mtdblock device files as MTD backing stores, not block layer backing stores.

I tested this using a CONFIG_MMU=n CONFIG_BLOCK=n kernel running on my FRV
board with a RomFS image installed on the mtdram test device. I see my test
program being run XIP:

# cat /proc/maps
...
c0c000b0-c0c01f8c r-xs 00000000 1f:00 144 /mnt/doshm
...

GDB on the kernel can be used to show that these addresses are within the
set-aside RAM space.

Signed-off-by: David Howells <dhowells@redhat.com>
Tested-by: Bernd Schmidt <bernd.schmidt@analog.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>

authored by

David Howells and committed by
David Woodhouse
da4458bd 6e232cfc

+1062 -667
+24
fs/romfs/Kconfig
··· 14 14 15 15 If you don't know whether you need it, then you don't need it: 16 16 answer N. 17 + 18 + config ROMFS_ON_BLOCK 19 + bool "Block device-backed ROM file system support" if (ROMFS_ON_MTD && EMBEDDED) 20 + depends on ROMFS_FS && BLOCK 21 + help 22 + This permits ROMFS to use block devices buffered through the page 23 + cache as the medium from which to retrieve data. It does not allow 24 + direct mapping of the medium. 25 + 26 + If unsure, answer Y. 27 + 28 + config ROMFS_ON_MTD 29 + bool "MTD-backed ROM file system support" 30 + depends on ROMFS_FS 31 + depends on MTD=y || (ROMFS_FS=m && MTD) 32 + help 33 + This permits ROMFS to use MTD based devices directly, without the 34 + intercession of the block layer (which may have been disabled). It 35 + also allows direct mapping of MTD devices through romfs files under 36 + NOMMU conditions if the underlying device is directly addressable by 37 + the CPU. 38 + 39 + If unsure, answer Y. 40 +
+7 -2
fs/romfs/Makefile
··· 1 1 # 2 - # Makefile for the linux romfs filesystem routines. 2 + # Makefile for the linux RomFS filesystem routines. 3 3 # 4 4 5 5 obj-$(CONFIG_ROMFS_FS) += romfs.o 6 6 7 - romfs-objs := inode.o 7 + romfs-y := storage.o super.o 8 + 9 + ifneq ($(CONFIG_MMU),y) 10 + romfs-$(CONFIG_ROMFS_ON_MTD) += mmap-nommu.o 11 + endif 12 +
-665
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, ret; 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 - 528 - /* Precalculate the data offset */ 529 - ret = romfs_strnlen(i, ino + ROMFH_SIZE, ROMFS_MAXFN); 530 - if (ret >= 0) 531 - ino = (ROMFH_SIZE + ret + 1 + ROMFH_PAD) & ROMFH_MASK; 532 - else 533 - ino = 0; 534 - 535 - ROMFS_I(i)->i_metasize = ino; 536 - ROMFS_I(i)->i_dataoffset = ino+(i->i_ino&ROMFH_MASK); 537 - 538 - /* Compute permissions */ 539 - ino = romfs_modemap[nextfh & ROMFH_TYPE]; 540 - /* only "normal" files have ops */ 541 - switch (nextfh & ROMFH_TYPE) { 542 - case 1: 543 - i->i_size = ROMFS_I(i)->i_metasize; 544 - i->i_op = &romfs_dir_inode_operations; 545 - i->i_fop = &romfs_dir_operations; 546 - if (nextfh & ROMFH_EXEC) 547 - ino |= S_IXUGO; 548 - i->i_mode = ino; 549 - break; 550 - case 2: 551 - i->i_fop = &generic_ro_fops; 552 - i->i_data.a_ops = &romfs_aops; 553 - if (nextfh & ROMFH_EXEC) 554 - ino |= S_IXUGO; 555 - i->i_mode = ino; 556 - break; 557 - case 3: 558 - i->i_op = &page_symlink_inode_operations; 559 - i->i_data.a_ops = &romfs_aops; 560 - i->i_mode = ino | S_IRWXUGO; 561 - break; 562 - default: 563 - /* depending on MBZ for sock/fifos */ 564 - nextfh = be32_to_cpu(ri.spec); 565 - init_special_inode(i, ino, 566 - MKDEV(nextfh>>16,nextfh&0xffff)); 567 - } 568 - unlock_new_inode(i); 569 - return i; 570 - } 571 - 572 - static struct kmem_cache * romfs_inode_cachep; 573 - 574 - static struct inode *romfs_alloc_inode(struct super_block *sb) 575 - { 576 - struct romfs_inode_info *ei; 577 - ei = kmem_cache_alloc(romfs_inode_cachep, GFP_KERNEL); 578 - if (!ei) 579 - return NULL; 580 - return &ei->vfs_inode; 581 - } 582 - 583 - static void romfs_destroy_inode(struct inode *inode) 584 - { 585 - kmem_cache_free(romfs_inode_cachep, ROMFS_I(inode)); 586 - } 587 - 588 - static void init_once(void *foo) 589 - { 590 - struct romfs_inode_info *ei = foo; 591 - 592 - inode_init_once(&ei->vfs_inode); 593 - } 594 - 595 - static int init_inodecache(void) 596 - { 597 - romfs_inode_cachep = kmem_cache_create("romfs_inode_cache", 598 - sizeof(struct romfs_inode_info), 599 - 0, (SLAB_RECLAIM_ACCOUNT| 600 - SLAB_MEM_SPREAD), 601 - init_once); 602 - if (romfs_inode_cachep == NULL) 603 - return -ENOMEM; 604 - return 0; 605 - } 606 - 607 - static void destroy_inodecache(void) 608 - { 609 - kmem_cache_destroy(romfs_inode_cachep); 610 - } 611 - 612 - static int romfs_remount(struct super_block *sb, int *flags, char *data) 613 - { 614 - *flags |= MS_RDONLY; 615 - return 0; 616 - } 617 - 618 - static const struct super_operations romfs_ops = { 619 - .alloc_inode = romfs_alloc_inode, 620 - .destroy_inode = romfs_destroy_inode, 621 - .statfs = romfs_statfs, 622 - .remount_fs = romfs_remount, 623 - }; 624 - 625 - static int romfs_get_sb(struct file_system_type *fs_type, 626 - int flags, const char *dev_name, void *data, struct vfsmount *mnt) 627 - { 628 - return get_sb_bdev(fs_type, flags, dev_name, data, romfs_fill_super, 629 - mnt); 630 - } 631 - 632 - static struct file_system_type romfs_fs_type = { 633 - .owner = THIS_MODULE, 634 - .name = "romfs", 635 - .get_sb = romfs_get_sb, 636 - .kill_sb = kill_block_super, 637 - .fs_flags = FS_REQUIRES_DEV, 638 - }; 639 - 640 - static int __init init_romfs_fs(void) 641 - { 642 - int err = init_inodecache(); 643 - if (err) 644 - goto out1; 645 - err = register_filesystem(&romfs_fs_type); 646 - if (err) 647 - goto out; 648 - return 0; 649 - out: 650 - destroy_inodecache(); 651 - out1: 652 - return err; 653 - } 654 - 655 - static void __exit exit_romfs_fs(void) 656 - { 657 - unregister_filesystem(&romfs_fs_type); 658 - destroy_inodecache(); 659 - } 660 - 661 - /* Yes, works even as a module... :) */ 662 - 663 - module_init(init_romfs_fs) 664 - module_exit(exit_romfs_fs) 665 - MODULE_LICENSE("GPL");
+47
fs/romfs/internal.h
··· 1 + /* RomFS internal definitions 2 + * 3 + * Copyright © 2007 Red Hat, Inc. All Rights Reserved. 4 + * Written by David Howells (dhowells@redhat.com) 5 + * 6 + * This program is free software; you can redistribute it and/or 7 + * modify it under the terms of the GNU General Public License 8 + * as published by the Free Software Foundation; either version 9 + * 2 of the License, or (at your option) any later version. 10 + */ 11 + 12 + #include <linux/romfs_fs.h> 13 + 14 + struct romfs_inode_info { 15 + struct inode vfs_inode; 16 + unsigned long i_metasize; /* size of non-data area */ 17 + unsigned long i_dataoffset; /* from the start of fs */ 18 + }; 19 + 20 + static inline size_t romfs_maxsize(struct super_block *sb) 21 + { 22 + return (size_t) (unsigned long) sb->s_fs_info; 23 + } 24 + 25 + static inline struct romfs_inode_info *ROMFS_I(struct inode *inode) 26 + { 27 + return container_of(inode, struct romfs_inode_info, vfs_inode); 28 + } 29 + 30 + /* 31 + * mmap-nommu.c 32 + */ 33 + #if !defined(CONFIG_MMU) && defined(CONFIG_ROMFS_ON_MTD) 34 + extern const struct file_operations romfs_ro_fops; 35 + #else 36 + #define romfs_ro_fops generic_ro_fops 37 + #endif 38 + 39 + /* 40 + * storage.c 41 + */ 42 + extern int romfs_dev_read(struct super_block *sb, unsigned long pos, 43 + void *buf, size_t buflen); 44 + extern ssize_t romfs_dev_strnlen(struct super_block *sb, 45 + unsigned long pos, size_t maxlen); 46 + extern int romfs_dev_strncmp(struct super_block *sb, unsigned long pos, 47 + const char *str, size_t size);
+75
fs/romfs/mmap-nommu.c
··· 1 + /* NOMMU mmap support for RomFS on MTD devices 2 + * 3 + * Copyright © 2007 Red Hat, Inc. All Rights Reserved. 4 + * Written by David Howells (dhowells@redhat.com) 5 + * 6 + * This program is free software; you can redistribute it and/or 7 + * modify it under the terms of the GNU General Public License 8 + * as published by the Free Software Foundation; either version 9 + * 2 of the License, or (at your option) any later version. 10 + */ 11 + 12 + #include <linux/mm.h> 13 + #include <linux/mtd/super.h> 14 + #include "internal.h" 15 + 16 + /* 17 + * try to determine where a shared mapping can be made 18 + * - only supported for NOMMU at the moment (MMU can't doesn't copy private 19 + * mappings) 20 + * - attempts to map through to the underlying MTD device 21 + */ 22 + static unsigned long romfs_get_unmapped_area(struct file *file, 23 + unsigned long addr, 24 + unsigned long len, 25 + unsigned long pgoff, 26 + unsigned long flags) 27 + { 28 + struct inode *inode = file->f_mapping->host; 29 + struct mtd_info *mtd = inode->i_sb->s_mtd; 30 + unsigned long isize, offset; 31 + 32 + if (!mtd) 33 + goto cant_map_directly; 34 + 35 + isize = i_size_read(inode); 36 + offset = pgoff << PAGE_SHIFT; 37 + if (offset > isize || len > isize || offset > isize - len) 38 + return (unsigned long) -EINVAL; 39 + 40 + /* we need to call down to the MTD layer to do the actual mapping */ 41 + if (mtd->get_unmapped_area) { 42 + if (addr != 0) 43 + return (unsigned long) -EINVAL; 44 + 45 + if (len > mtd->size || pgoff >= (mtd->size >> PAGE_SHIFT)) 46 + return (unsigned long) -EINVAL; 47 + 48 + offset += ROMFS_I(inode)->i_dataoffset; 49 + if (offset > mtd->size - len) 50 + return (unsigned long) -EINVAL; 51 + 52 + return mtd->get_unmapped_area(mtd, len, offset, flags); 53 + } 54 + 55 + cant_map_directly: 56 + return (unsigned long) -ENOSYS; 57 + } 58 + 59 + /* 60 + * permit a R/O mapping to be made directly through onto an MTD device if 61 + * possible 62 + */ 63 + static int romfs_mmap(struct file *file, struct vm_area_struct *vma) 64 + { 65 + return vma->vm_flags & (VM_SHARED | VM_MAYSHARE) ? 0 : -ENOSYS; 66 + } 67 + 68 + const struct file_operations romfs_ro_fops = { 69 + .llseek = generic_file_llseek, 70 + .read = do_sync_read, 71 + .aio_read = generic_file_aio_read, 72 + .splice_read = generic_file_splice_read, 73 + .mmap = romfs_mmap, 74 + .get_unmapped_area = romfs_get_unmapped_area, 75 + };
+261
fs/romfs/storage.c
··· 1 + /* RomFS storage access routines 2 + * 3 + * Copyright © 2007 Red Hat, Inc. All Rights Reserved. 4 + * Written by David Howells (dhowells@redhat.com) 5 + * 6 + * This program is free software; you can redistribute it and/or 7 + * modify it under the terms of the GNU General Public License 8 + * as published by the Free Software Foundation; either version 9 + * 2 of the License, or (at your option) any later version. 10 + */ 11 + 12 + #include <linux/fs.h> 13 + #include <linux/mtd/super.h> 14 + #include <linux/buffer_head.h> 15 + #include "internal.h" 16 + 17 + #if !defined(CONFIG_ROMFS_ON_MTD) && !defined(CONFIG_ROMFS_ON_BLOCK) 18 + #error no ROMFS backing store interface configured 19 + #endif 20 + 21 + #ifdef CONFIG_ROMFS_ON_MTD 22 + #define ROMFS_MTD_READ(sb, ...) ((sb)->s_mtd->read((sb)->s_mtd, ##__VA_ARGS__)) 23 + 24 + /* 25 + * read data from an romfs image on an MTD device 26 + */ 27 + static int romfs_mtd_read(struct super_block *sb, unsigned long pos, 28 + void *buf, size_t buflen) 29 + { 30 + size_t rlen; 31 + int ret; 32 + 33 + ret = ROMFS_MTD_READ(sb, pos, buflen, &rlen, buf); 34 + return (ret < 0 || rlen != buflen) ? -EIO : 0; 35 + } 36 + 37 + /* 38 + * determine the length of a string in a romfs image on an MTD device 39 + */ 40 + static ssize_t romfs_mtd_strnlen(struct super_block *sb, 41 + unsigned long pos, size_t maxlen) 42 + { 43 + ssize_t n = 0; 44 + size_t segment; 45 + u_char buf[16], *p; 46 + size_t len; 47 + int ret; 48 + 49 + /* scan the string up to 16 bytes at a time */ 50 + while (maxlen > 0) { 51 + segment = min_t(size_t, maxlen, 16); 52 + ret = ROMFS_MTD_READ(sb, pos, segment, &len, buf); 53 + if (ret < 0) 54 + return ret; 55 + p = memchr(buf, 0, len); 56 + if (p) 57 + return n + (p - buf); 58 + maxlen -= len; 59 + pos += len; 60 + n += len; 61 + } 62 + 63 + return n; 64 + } 65 + 66 + /* 67 + * compare a string to one in a romfs image on MTD 68 + * - return 1 if matched, 0 if differ, -ve if error 69 + */ 70 + static int romfs_mtd_strncmp(struct super_block *sb, unsigned long pos, 71 + const char *str, size_t size) 72 + { 73 + u_char buf[16]; 74 + size_t len, segment; 75 + int ret; 76 + 77 + /* scan the string up to 16 bytes at a time */ 78 + while (size > 0) { 79 + segment = min_t(size_t, size, 16); 80 + ret = ROMFS_MTD_READ(sb, pos, segment, &len, buf); 81 + if (ret < 0) 82 + return ret; 83 + if (memcmp(buf, str, len) != 0) 84 + return 0; 85 + size -= len; 86 + pos += len; 87 + str += len; 88 + } 89 + 90 + return 1; 91 + } 92 + #endif /* CONFIG_ROMFS_ON_MTD */ 93 + 94 + #ifdef CONFIG_ROMFS_ON_BLOCK 95 + /* 96 + * read data from an romfs image on a block device 97 + */ 98 + static int romfs_blk_read(struct super_block *sb, unsigned long pos, 99 + void *buf, size_t buflen) 100 + { 101 + struct buffer_head *bh; 102 + unsigned long offset; 103 + size_t segment; 104 + 105 + /* copy the string up to blocksize bytes at a time */ 106 + while (buflen > 0) { 107 + offset = pos & (ROMBSIZE - 1); 108 + segment = min_t(size_t, buflen, ROMBSIZE - offset); 109 + bh = sb_bread(sb, pos >> ROMBSBITS); 110 + if (!bh) 111 + return -EIO; 112 + memcpy(buf, bh->b_data + offset, segment); 113 + brelse(bh); 114 + buflen -= segment; 115 + pos += segment; 116 + } 117 + 118 + return 0; 119 + } 120 + 121 + /* 122 + * determine the length of a string in romfs on a block device 123 + */ 124 + static ssize_t romfs_blk_strnlen(struct super_block *sb, 125 + unsigned long pos, size_t limit) 126 + { 127 + struct buffer_head *bh; 128 + unsigned long offset; 129 + ssize_t n = 0; 130 + size_t segment; 131 + u_char *buf, *p; 132 + 133 + /* scan the string up to blocksize bytes at a time */ 134 + while (limit > 0) { 135 + offset = pos & (ROMBSIZE - 1); 136 + segment = min_t(size_t, limit, ROMBSIZE - offset); 137 + bh = sb_bread(sb, pos >> ROMBSBITS); 138 + if (!bh) 139 + return -EIO; 140 + buf = bh->b_data + offset; 141 + p = memchr(buf, 0, segment); 142 + brelse(bh); 143 + if (p) 144 + return n + (p - buf); 145 + limit -= segment; 146 + pos += segment; 147 + n += segment; 148 + } 149 + 150 + return n; 151 + } 152 + 153 + /* 154 + * compare a string to one in a romfs image on a block device 155 + * - return 1 if matched, 0 if differ, -ve if error 156 + */ 157 + static int romfs_blk_strncmp(struct super_block *sb, unsigned long pos, 158 + const char *str, size_t size) 159 + { 160 + struct buffer_head *bh; 161 + unsigned long offset; 162 + size_t segment; 163 + bool x; 164 + 165 + /* scan the string up to 16 bytes at a time */ 166 + while (size > 0) { 167 + offset = pos & (ROMBSIZE - 1); 168 + segment = min_t(size_t, size, ROMBSIZE - offset); 169 + bh = sb_bread(sb, pos >> ROMBSBITS); 170 + if (!bh) 171 + return -EIO; 172 + x = (memcmp(bh->b_data + offset, str, segment) != 0); 173 + brelse(bh); 174 + if (x) 175 + return 0; 176 + size -= segment; 177 + pos += segment; 178 + str += segment; 179 + } 180 + 181 + return 1; 182 + } 183 + #endif /* CONFIG_ROMFS_ON_BLOCK */ 184 + 185 + /* 186 + * read data from the romfs image 187 + */ 188 + int romfs_dev_read(struct super_block *sb, unsigned long pos, 189 + void *buf, size_t buflen) 190 + { 191 + size_t limit; 192 + 193 + limit = romfs_maxsize(sb); 194 + if (pos >= limit) 195 + return -EIO; 196 + if (buflen > limit - pos) 197 + buflen = limit - pos; 198 + 199 + #ifdef CONFIG_ROMFS_ON_MTD 200 + if (sb->s_mtd) 201 + return romfs_mtd_read(sb, pos, buf, buflen); 202 + #endif 203 + #ifdef CONFIG_ROMFS_ON_BLOCK 204 + if (sb->s_bdev) 205 + return romfs_blk_read(sb, pos, buf, buflen); 206 + #endif 207 + return -EIO; 208 + } 209 + 210 + /* 211 + * determine the length of a string in romfs 212 + */ 213 + ssize_t romfs_dev_strnlen(struct super_block *sb, 214 + unsigned long pos, size_t maxlen) 215 + { 216 + size_t limit; 217 + 218 + limit = romfs_maxsize(sb); 219 + if (pos >= limit) 220 + return -EIO; 221 + if (maxlen > limit - pos) 222 + maxlen = limit - pos; 223 + 224 + #ifdef CONFIG_ROMFS_ON_MTD 225 + if (sb->s_mtd) 226 + return romfs_mtd_strnlen(sb, pos, limit); 227 + #endif 228 + #ifdef CONFIG_ROMFS_ON_BLOCK 229 + if (sb->s_bdev) 230 + return romfs_blk_strnlen(sb, pos, limit); 231 + #endif 232 + return -EIO; 233 + } 234 + 235 + /* 236 + * compare a string to one in romfs 237 + * - return 1 if matched, 0 if differ, -ve if error 238 + */ 239 + int romfs_dev_strncmp(struct super_block *sb, unsigned long pos, 240 + const char *str, size_t size) 241 + { 242 + size_t limit; 243 + 244 + limit = romfs_maxsize(sb); 245 + if (pos >= limit) 246 + return -EIO; 247 + if (size > ROMFS_MAXFN) 248 + return -ENAMETOOLONG; 249 + if (size > limit - pos) 250 + return -EIO; 251 + 252 + #ifdef CONFIG_ROMFS_ON_MTD 253 + if (sb->s_mtd) 254 + return romfs_mtd_strncmp(sb, pos, str, size); 255 + #endif 256 + #ifdef CONFIG_ROMFS_ON_BLOCK 257 + if (sb->s_bdev) 258 + return romfs_blk_strncmp(sb, pos, str, size); 259 + #endif 260 + return -EIO; 261 + }
+648
fs/romfs/super.c
··· 1 + /* Block- or MTD-based romfs 2 + * 3 + * Copyright © 2007 Red Hat, Inc. All Rights Reserved. 4 + * Written by David Howells (dhowells@redhat.com) 5 + * 6 + * Derived from: ROMFS file system, Linux implementation 7 + * 8 + * Copyright © 1997-1999 Janos Farkas <chexum@shadow.banki.hu> 9 + * 10 + * Using parts of the minix filesystem 11 + * Copyright © 1991, 1992 Linus Torvalds 12 + * 13 + * and parts of the affs filesystem additionally 14 + * Copyright © 1993 Ray Burr 15 + * Copyright © 1996 Hans-Joachim Widmaier 16 + * 17 + * Changes 18 + * Changed for 2.1.19 modules 19 + * Jan 1997 Initial release 20 + * Jun 1997 2.1.43+ changes 21 + * Proper page locking in readpage 22 + * Changed to work with 2.1.45+ fs 23 + * Jul 1997 Fixed follow_link 24 + * 2.1.47 25 + * lookup shouldn't return -ENOENT 26 + * from Horst von Brand: 27 + * fail on wrong checksum 28 + * double unlock_super was possible 29 + * correct namelen for statfs 30 + * spotted by Bill Hawes: 31 + * readlink shouldn't iput() 32 + * Jun 1998 2.1.106 from Avery Pennarun: glibc scandir() 33 + * exposed a problem in readdir 34 + * 2.1.107 code-freeze spellchecker run 35 + * Aug 1998 2.1.118+ VFS changes 36 + * Sep 1998 2.1.122 another VFS change (follow_link) 37 + * Apr 1999 2.2.7 no more EBADF checking in 38 + * lookup/readdir, use ERR_PTR 39 + * Jun 1999 2.3.6 d_alloc_root use changed 40 + * 2.3.9 clean up usage of ENOENT/negative 41 + * dentries in lookup 42 + * clean up page flags setting 43 + * (error, uptodate, locking) in 44 + * in readpage 45 + * use init_special_inode for 46 + * fifos/sockets (and streamline) in 47 + * read_inode, fix _ops table order 48 + * Aug 1999 2.3.16 __initfunc() => __init change 49 + * Oct 1999 2.3.24 page->owner hack obsoleted 50 + * Nov 1999 2.3.27 2.3.25+ page->offset => index change 51 + * 52 + * 53 + * This program is free software; you can redistribute it and/or 54 + * modify it under the terms of the GNU General Public Licence 55 + * as published by the Free Software Foundation; either version 56 + * 2 of the Licence, or (at your option) any later version. 57 + */ 58 + 59 + #include <linux/module.h> 60 + #include <linux/string.h> 61 + #include <linux/fs.h> 62 + #include <linux/time.h> 63 + #include <linux/slab.h> 64 + #include <linux/init.h> 65 + #include <linux/blkdev.h> 66 + #include <linux/parser.h> 67 + #include <linux/mount.h> 68 + #include <linux/namei.h> 69 + #include <linux/statfs.h> 70 + #include <linux/mtd/super.h> 71 + #include <linux/ctype.h> 72 + #include <linux/highmem.h> 73 + #include <linux/pagemap.h> 74 + #include <linux/uaccess.h> 75 + #include "internal.h" 76 + 77 + static struct kmem_cache *romfs_inode_cachep; 78 + 79 + static const umode_t romfs_modemap[8] = { 80 + 0, /* hard link */ 81 + S_IFDIR | 0644, /* directory */ 82 + S_IFREG | 0644, /* regular file */ 83 + S_IFLNK | 0777, /* symlink */ 84 + S_IFBLK | 0600, /* blockdev */ 85 + S_IFCHR | 0600, /* chardev */ 86 + S_IFSOCK | 0644, /* socket */ 87 + S_IFIFO | 0644 /* FIFO */ 88 + }; 89 + 90 + static const unsigned char romfs_dtype_table[] = { 91 + DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_SOCK, DT_FIFO 92 + }; 93 + 94 + static struct inode *romfs_iget(struct super_block *sb, unsigned long pos); 95 + 96 + /* 97 + * read a page worth of data from the image 98 + */ 99 + static int romfs_readpage(struct file *file, struct page *page) 100 + { 101 + struct inode *inode = page->mapping->host; 102 + loff_t offset, size; 103 + unsigned long fillsize, pos; 104 + void *buf; 105 + int ret; 106 + 107 + buf = kmap(page); 108 + if (!buf) 109 + return -ENOMEM; 110 + 111 + /* 32 bit warning -- but not for us :) */ 112 + offset = page_offset(page); 113 + size = i_size_read(inode); 114 + fillsize = 0; 115 + ret = 0; 116 + if (offset < size) { 117 + size -= offset; 118 + fillsize = size > PAGE_SIZE ? PAGE_SIZE : size; 119 + 120 + pos = ROMFS_I(inode)->i_dataoffset + offset; 121 + 122 + ret = romfs_dev_read(inode->i_sb, pos, buf, fillsize); 123 + if (ret < 0) { 124 + SetPageError(page); 125 + fillsize = 0; 126 + ret = -EIO; 127 + } 128 + } 129 + 130 + if (fillsize < PAGE_SIZE) 131 + memset(buf + fillsize, 0, PAGE_SIZE - fillsize); 132 + if (ret == 0) 133 + SetPageUptodate(page); 134 + 135 + flush_dcache_page(page); 136 + kunmap(page); 137 + unlock_page(page); 138 + return ret; 139 + } 140 + 141 + static const struct address_space_operations romfs_aops = { 142 + .readpage = romfs_readpage 143 + }; 144 + 145 + /* 146 + * read the entries from a directory 147 + */ 148 + static int romfs_readdir(struct file *filp, void *dirent, filldir_t filldir) 149 + { 150 + struct inode *i = filp->f_dentry->d_inode; 151 + struct romfs_inode ri; 152 + unsigned long offset, maxoff; 153 + int j, ino, nextfh; 154 + int stored = 0; 155 + char fsname[ROMFS_MAXFN]; /* XXX dynamic? */ 156 + int ret; 157 + 158 + maxoff = romfs_maxsize(i->i_sb); 159 + 160 + offset = filp->f_pos; 161 + if (!offset) { 162 + offset = i->i_ino & ROMFH_MASK; 163 + ret = romfs_dev_read(i->i_sb, offset, &ri, ROMFH_SIZE); 164 + if (ret < 0) 165 + goto out; 166 + offset = be32_to_cpu(ri.spec) & ROMFH_MASK; 167 + } 168 + 169 + /* Not really failsafe, but we are read-only... */ 170 + for (;;) { 171 + if (!offset || offset >= maxoff) { 172 + offset = maxoff; 173 + filp->f_pos = offset; 174 + goto out; 175 + } 176 + filp->f_pos = offset; 177 + 178 + /* Fetch inode info */ 179 + ret = romfs_dev_read(i->i_sb, offset, &ri, ROMFH_SIZE); 180 + if (ret < 0) 181 + goto out; 182 + 183 + j = romfs_dev_strnlen(i->i_sb, offset + ROMFH_SIZE, 184 + sizeof(fsname) - 1); 185 + if (j < 0) 186 + goto out; 187 + 188 + ret = romfs_dev_read(i->i_sb, offset + ROMFH_SIZE, fsname, j); 189 + if (ret < 0) 190 + goto out; 191 + fsname[j] = '\0'; 192 + 193 + ino = offset; 194 + nextfh = be32_to_cpu(ri.next); 195 + if ((nextfh & ROMFH_TYPE) == ROMFH_HRD) 196 + ino = be32_to_cpu(ri.spec); 197 + if (filldir(dirent, fsname, j, offset, ino, 198 + romfs_dtype_table[nextfh & ROMFH_TYPE]) < 0) 199 + goto out; 200 + 201 + stored++; 202 + offset = nextfh & ROMFH_MASK; 203 + } 204 + 205 + out: 206 + return stored; 207 + } 208 + 209 + /* 210 + * look up an entry in a directory 211 + */ 212 + static struct dentry *romfs_lookup(struct inode *dir, struct dentry *dentry, 213 + struct nameidata *nd) 214 + { 215 + unsigned long offset, maxoff; 216 + struct inode *inode; 217 + struct romfs_inode ri; 218 + const char *name; /* got from dentry */ 219 + int len, ret; 220 + 221 + offset = dir->i_ino & ROMFH_MASK; 222 + ret = romfs_dev_read(dir->i_sb, offset, &ri, ROMFH_SIZE); 223 + if (ret < 0) 224 + goto error; 225 + 226 + /* search all the file entries in the list starting from the one 227 + * pointed to by the directory's special data */ 228 + maxoff = romfs_maxsize(dir->i_sb); 229 + offset = be32_to_cpu(ri.spec) & ROMFH_MASK; 230 + 231 + name = dentry->d_name.name; 232 + len = dentry->d_name.len; 233 + 234 + for (;;) { 235 + if (!offset || offset >= maxoff) 236 + goto out0; 237 + 238 + ret = romfs_dev_read(dir->i_sb, offset, &ri, sizeof(ri)); 239 + if (ret < 0) 240 + goto error; 241 + 242 + /* try to match the first 16 bytes of name */ 243 + ret = romfs_dev_strncmp(dir->i_sb, offset + ROMFH_SIZE, name, 244 + len); 245 + if (ret < 0) 246 + goto error; 247 + if (ret == 1) 248 + break; 249 + 250 + /* next entry */ 251 + offset = be32_to_cpu(ri.next) & ROMFH_MASK; 252 + } 253 + 254 + /* Hard link handling */ 255 + if ((be32_to_cpu(ri.next) & ROMFH_TYPE) == ROMFH_HRD) 256 + offset = be32_to_cpu(ri.spec) & ROMFH_MASK; 257 + 258 + inode = romfs_iget(dir->i_sb, offset); 259 + if (IS_ERR(inode)) { 260 + ret = PTR_ERR(inode); 261 + goto error; 262 + } 263 + goto outi; 264 + 265 + /* 266 + * it's a bit funky, _lookup needs to return an error code 267 + * (negative) or a NULL, both as a dentry. ENOENT should not 268 + * be returned, instead we need to create a negative dentry by 269 + * d_add(dentry, NULL); and return 0 as no error. 270 + * (Although as I see, it only matters on writable file 271 + * systems). 272 + */ 273 + out0: 274 + inode = NULL; 275 + outi: 276 + d_add(dentry, inode); 277 + ret = 0; 278 + error: 279 + return ERR_PTR(ret); 280 + } 281 + 282 + static const struct file_operations romfs_dir_operations = { 283 + .read = generic_read_dir, 284 + .readdir = romfs_readdir, 285 + }; 286 + 287 + static struct inode_operations romfs_dir_inode_operations = { 288 + .lookup = romfs_lookup, 289 + }; 290 + 291 + /* 292 + * get a romfs inode based on its position in the image (which doubles as the 293 + * inode number) 294 + */ 295 + static struct inode *romfs_iget(struct super_block *sb, unsigned long pos) 296 + { 297 + struct romfs_inode_info *inode; 298 + struct romfs_inode ri; 299 + struct inode *i; 300 + unsigned long nlen; 301 + unsigned nextfh, ret; 302 + umode_t mode; 303 + 304 + /* we might have to traverse a chain of "hard link" file entries to get 305 + * to the actual file */ 306 + for (;;) { 307 + ret = romfs_dev_read(sb, pos, &ri, sizeof(ri)); 308 + if (ret < 0) 309 + goto error; 310 + 311 + /* XXX: do romfs_checksum here too (with name) */ 312 + 313 + nextfh = be32_to_cpu(ri.next); 314 + if ((nextfh & ROMFH_TYPE) != ROMFH_HRD) 315 + break; 316 + 317 + pos = be32_to_cpu(ri.spec) & ROMFH_MASK; 318 + } 319 + 320 + /* determine the length of the filename */ 321 + nlen = romfs_dev_strnlen(sb, pos + ROMFH_SIZE, ROMFS_MAXFN); 322 + if (IS_ERR_VALUE(nlen)) 323 + goto eio; 324 + 325 + /* get an inode for this image position */ 326 + i = iget_locked(sb, pos); 327 + if (!i) 328 + return ERR_PTR(-ENOMEM); 329 + 330 + if (!(i->i_state & I_NEW)) 331 + return i; 332 + 333 + /* precalculate the data offset */ 334 + inode = ROMFS_I(i); 335 + inode->i_metasize = (ROMFH_SIZE + nlen + 1 + ROMFH_PAD) & ROMFH_MASK; 336 + inode->i_dataoffset = pos + inode->i_metasize; 337 + 338 + i->i_nlink = 1; /* Hard to decide.. */ 339 + i->i_size = be32_to_cpu(ri.size); 340 + i->i_mtime.tv_sec = i->i_atime.tv_sec = i->i_ctime.tv_sec = 0; 341 + i->i_mtime.tv_nsec = i->i_atime.tv_nsec = i->i_ctime.tv_nsec = 0; 342 + 343 + /* set up mode and ops */ 344 + mode = romfs_modemap[nextfh & ROMFH_TYPE]; 345 + 346 + switch (nextfh & ROMFH_TYPE) { 347 + case ROMFH_DIR: 348 + i->i_size = ROMFS_I(i)->i_metasize; 349 + i->i_op = &romfs_dir_inode_operations; 350 + i->i_fop = &romfs_dir_operations; 351 + if (nextfh & ROMFH_EXEC) 352 + mode |= S_IXUGO; 353 + break; 354 + case ROMFH_REG: 355 + i->i_fop = &romfs_ro_fops; 356 + i->i_data.a_ops = &romfs_aops; 357 + if (i->i_sb->s_mtd) 358 + i->i_data.backing_dev_info = 359 + i->i_sb->s_mtd->backing_dev_info; 360 + if (nextfh & ROMFH_EXEC) 361 + mode |= S_IXUGO; 362 + break; 363 + case ROMFH_SYM: 364 + i->i_op = &page_symlink_inode_operations; 365 + i->i_data.a_ops = &romfs_aops; 366 + mode |= S_IRWXUGO; 367 + break; 368 + default: 369 + /* depending on MBZ for sock/fifos */ 370 + nextfh = be32_to_cpu(ri.spec); 371 + init_special_inode(i, mode, MKDEV(nextfh >> 16, 372 + nextfh & 0xffff)); 373 + break; 374 + } 375 + 376 + i->i_mode = mode; 377 + 378 + unlock_new_inode(i); 379 + return i; 380 + 381 + eio: 382 + ret = -EIO; 383 + error: 384 + printk(KERN_ERR "ROMFS: read error for inode 0x%lx\n", pos); 385 + return ERR_PTR(ret); 386 + } 387 + 388 + /* 389 + * allocate a new inode 390 + */ 391 + static struct inode *romfs_alloc_inode(struct super_block *sb) 392 + { 393 + struct romfs_inode_info *inode; 394 + inode = kmem_cache_alloc(romfs_inode_cachep, GFP_KERNEL); 395 + return inode ? &inode->vfs_inode : NULL; 396 + } 397 + 398 + /* 399 + * return a spent inode to the slab cache 400 + */ 401 + static void romfs_destroy_inode(struct inode *inode) 402 + { 403 + kmem_cache_free(romfs_inode_cachep, ROMFS_I(inode)); 404 + } 405 + 406 + /* 407 + * get filesystem statistics 408 + */ 409 + static int romfs_statfs(struct dentry *dentry, struct kstatfs *buf) 410 + { 411 + buf->f_type = ROMFS_MAGIC; 412 + buf->f_namelen = ROMFS_MAXFN; 413 + buf->f_bsize = ROMBSIZE; 414 + buf->f_bfree = buf->f_bavail = buf->f_ffree; 415 + buf->f_blocks = 416 + (romfs_maxsize(dentry->d_sb) + ROMBSIZE - 1) >> ROMBSBITS; 417 + return 0; 418 + } 419 + 420 + /* 421 + * remounting must involve read-only 422 + */ 423 + static int romfs_remount(struct super_block *sb, int *flags, char *data) 424 + { 425 + *flags |= MS_RDONLY; 426 + return 0; 427 + } 428 + 429 + static const struct super_operations romfs_super_ops = { 430 + .alloc_inode = romfs_alloc_inode, 431 + .destroy_inode = romfs_destroy_inode, 432 + .statfs = romfs_statfs, 433 + .remount_fs = romfs_remount, 434 + }; 435 + 436 + /* 437 + * checksum check on part of a romfs filesystem 438 + */ 439 + static __u32 romfs_checksum(const void *data, int size) 440 + { 441 + const __be32 *ptr = data; 442 + __u32 sum; 443 + 444 + sum = 0; 445 + size >>= 2; 446 + while (size > 0) { 447 + sum += be32_to_cpu(*ptr++); 448 + size--; 449 + } 450 + return sum; 451 + } 452 + 453 + /* 454 + * fill in the superblock 455 + */ 456 + static int romfs_fill_super(struct super_block *sb, void *data, int silent) 457 + { 458 + struct romfs_super_block *rsb; 459 + struct inode *root; 460 + unsigned long pos, img_size; 461 + const char *storage; 462 + size_t len; 463 + int ret; 464 + 465 + #ifdef CONFIG_BLOCK 466 + if (!sb->s_mtd) { 467 + sb_set_blocksize(sb, ROMBSIZE); 468 + } else { 469 + sb->s_blocksize = ROMBSIZE; 470 + sb->s_blocksize_bits = blksize_bits(ROMBSIZE); 471 + } 472 + #endif 473 + 474 + sb->s_maxbytes = 0xFFFFFFFF; 475 + sb->s_magic = ROMFS_MAGIC; 476 + sb->s_flags |= MS_RDONLY | MS_NOATIME; 477 + sb->s_op = &romfs_super_ops; 478 + 479 + /* read the image superblock and check it */ 480 + rsb = kmalloc(512, GFP_KERNEL); 481 + if (!rsb) 482 + return -ENOMEM; 483 + 484 + sb->s_fs_info = (void *) 512; 485 + ret = romfs_dev_read(sb, 0, rsb, 512); 486 + if (ret < 0) 487 + goto error_rsb; 488 + 489 + img_size = be32_to_cpu(rsb->size); 490 + 491 + if (sb->s_mtd && img_size > sb->s_mtd->size) 492 + goto error_rsb_inval; 493 + 494 + sb->s_fs_info = (void *) img_size; 495 + 496 + if (rsb->word0 != ROMSB_WORD0 || rsb->word1 != ROMSB_WORD1 || 497 + img_size < ROMFH_SIZE) { 498 + if (!silent) 499 + printk(KERN_WARNING "VFS:" 500 + " Can't find a romfs filesystem on dev %s.\n", 501 + sb->s_id); 502 + goto error_rsb_inval; 503 + } 504 + 505 + if (romfs_checksum(rsb, min_t(size_t, img_size, 512))) { 506 + printk(KERN_ERR "ROMFS: bad initial checksum on dev %s.\n", 507 + sb->s_id); 508 + goto error_rsb_inval; 509 + } 510 + 511 + storage = sb->s_mtd ? "MTD" : "the block layer"; 512 + 513 + len = strnlen(rsb->name, ROMFS_MAXFN); 514 + if (!silent) 515 + printk(KERN_NOTICE "ROMFS: Mounting image '%*.*s' through %s\n", 516 + (unsigned) len, (unsigned) len, rsb->name, storage); 517 + 518 + kfree(rsb); 519 + rsb = NULL; 520 + 521 + /* find the root directory */ 522 + pos = (ROMFH_SIZE + len + 1 + ROMFH_PAD) & ROMFH_MASK; 523 + 524 + root = romfs_iget(sb, pos); 525 + if (!root) 526 + goto error; 527 + 528 + sb->s_root = d_alloc_root(root); 529 + if (!sb->s_root) 530 + goto error_i; 531 + 532 + return 0; 533 + 534 + error_i: 535 + iput(root); 536 + error: 537 + return -EINVAL; 538 + error_rsb_inval: 539 + ret = -EINVAL; 540 + error_rsb: 541 + return ret; 542 + } 543 + 544 + /* 545 + * get a superblock for mounting 546 + */ 547 + static int romfs_get_sb(struct file_system_type *fs_type, 548 + int flags, const char *dev_name, 549 + void *data, struct vfsmount *mnt) 550 + { 551 + int ret = -EINVAL; 552 + 553 + #ifdef CONFIG_ROMFS_ON_MTD 554 + ret = get_sb_mtd(fs_type, flags, dev_name, data, romfs_fill_super, 555 + mnt); 556 + #endif 557 + #ifdef CONFIG_ROMFS_ON_BLOCK 558 + if (ret == -EINVAL) 559 + ret = get_sb_bdev(fs_type, flags, dev_name, data, 560 + romfs_fill_super, mnt); 561 + #endif 562 + return ret; 563 + } 564 + 565 + /* 566 + * destroy a romfs superblock in the appropriate manner 567 + */ 568 + static void romfs_kill_sb(struct super_block *sb) 569 + { 570 + #ifdef CONFIG_ROMFS_ON_MTD 571 + if (sb->s_mtd) { 572 + kill_mtd_super(sb); 573 + return; 574 + } 575 + #endif 576 + #ifdef CONFIG_ROMFS_ON_BLOCK 577 + if (sb->s_bdev) { 578 + kill_block_super(sb); 579 + return; 580 + } 581 + #endif 582 + } 583 + 584 + static struct file_system_type romfs_fs_type = { 585 + .owner = THIS_MODULE, 586 + .name = "romfs", 587 + .get_sb = romfs_get_sb, 588 + .kill_sb = romfs_kill_sb, 589 + .fs_flags = FS_REQUIRES_DEV, 590 + }; 591 + 592 + /* 593 + * inode storage initialiser 594 + */ 595 + static void romfs_i_init_once(void *_inode) 596 + { 597 + struct romfs_inode_info *inode = _inode; 598 + 599 + inode_init_once(&inode->vfs_inode); 600 + } 601 + 602 + /* 603 + * romfs module initialisation 604 + */ 605 + static int __init init_romfs_fs(void) 606 + { 607 + int ret; 608 + 609 + printk(KERN_INFO "ROMFS MTD (C) 2007 Red Hat, Inc.\n"); 610 + 611 + romfs_inode_cachep = 612 + kmem_cache_create("romfs_i", 613 + sizeof(struct romfs_inode_info), 0, 614 + SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, 615 + romfs_i_init_once); 616 + 617 + if (!romfs_inode_cachep) { 618 + printk(KERN_ERR 619 + "ROMFS error: Failed to initialise inode cache\n"); 620 + return -ENOMEM; 621 + } 622 + ret = register_filesystem(&romfs_fs_type); 623 + if (ret) { 624 + printk(KERN_ERR "ROMFS error: Failed to register filesystem\n"); 625 + goto error_register; 626 + } 627 + return 0; 628 + 629 + error_register: 630 + kmem_cache_destroy(romfs_inode_cachep); 631 + return ret; 632 + } 633 + 634 + /* 635 + * romfs module removal 636 + */ 637 + static void __exit exit_romfs_fs(void) 638 + { 639 + unregister_filesystem(&romfs_fs_type); 640 + kmem_cache_destroy(romfs_inode_cachep); 641 + } 642 + 643 + module_init(init_romfs_fs); 644 + module_exit(exit_romfs_fs); 645 + 646 + MODULE_DESCRIPTION("Direct-MTD Capable RomFS"); 647 + MODULE_AUTHOR("Red Hat, Inc."); 648 + MODULE_LICENSE("GPL"); /* Actually dual-licensed, but it doesn't matter for */