[patch] romfs for 2.1.46

Janos Farkas (Janos.Farkas-#uxXEUD1jgb6yqfuHCRKQg.E1dfC@shadow.banki.hu)
Wed, 23 Jul 1997 13:30:25 +0200


On Mon, Jul 21, 1997 at 11:12:19AM -0400, Horst von Brand wrote: [linux-kernel]
> The code to handle files is in the process of a complete overhaul, for now
> just ext2, isofs and (i believe) autofs do work.

And there's a bunch of pitfalls even with the working ones. For example,
it seems either some inodes or some dentries are cached between umount/mounts
too.. But that may be the fault of romfs or maybe autofs.. :) Anyway, here
are two patches to update romfs to a version working with 2.1.46.

And some issues. Comments in fs/namei.c indicate that follow_link
will be obsoleted (again) and has been removed, but now it is required
(again?), which one is correct? Just because until do_follow_links
is not rewritten, it will try to ->follow_link() on directories
too, that broke the "clever" unified directory/symlink table of romfs,
and circumventing this was easiest in do_follow_link().

Is this "feature" (follow_link() on directories that this field) to
stay? I'll need to add some bytes then... :)

Patch contents: first the patch to fs/namei.c to avoid trying follow_link
for strange directories, this may or may not be required in later
pre-patches. Next: the real update to 2.1.46. No new features, only to
bring up the code to the fs interface of 2.1.4[56], and some documentation
fixes/reformats.

Another patch will follow for 2.0 soon, still no new features, just the
possibly essential bugfix, similar doc cleanups, and a "cleaner" patch
for 2.0.latest. And I'm not sure it's to be included in the "real"
2.0 tree, as the code itself is just changed, and it needs some other
tinkering in the initrd parts, and that's not necessarily nice.

-- 
Janos - Don't worry, my address works.  I'm just bored of spam.

---------------------------------------------------------------------------

diff -urpN linux-2.1.46-orig/fs/namei.c linux/fs/namei.c --- linux-2.1.46-orig/fs/namei.c Mon Jul 21 00:54:33 1997 +++ linux/fs/namei.c Tue Jul 22 00:16:11 1997 @@ -345,7 +345,7 @@ static struct dentry * do_follow_link(st { struct inode * inode = dentry->d_inode; - if (inode && inode->i_op && inode->i_op->follow_link) { + if (inode && S_ISLNK(inode->i_mode) && inode->i_op && inode->i_op->follow_link) { struct dentry *result; /* This eats the base */

---------------------------------------------------------------------------

diff -urpN linux-2.1.46-orig/Documentation/filesystems/romfs.txt linux/Documentation/filesystems/romfs.txt --- linux-2.1.46-orig/Documentation/filesystems/romfs.txt Fri Jan 3 12:03:41 1997 +++ linux/Documentation/filesystems/romfs.txt Tue Jul 22 15:30:09 1997 @@ -8,19 +8,18 @@ similar feature, and even the possibilit file system which doesn't take up useful memory from the router functions in the basement of your office. -For comparison, both the older minix and xiafs filesystems (compiled -as module) need more than 20000 bytes, while romfs is less than a -page, about 4000 bytes (assuming ix86 code). Under the same -conditions, the msdos filesystem would need about 30K (and does not -support device nodes or symlinks), while the nfs module with nfsroot -is about 57K. Furthermore, as a bit unfair comparison, an actual -rescue disk used up 3202 blocks with ext2, while with romfs, it needed -3079 blocks. +For comparison, both the older minix and xiafs (the latter is now +defunct) filesystems, compiled as module need more than 20000 bytes, +while romfs is less than a page, about 4000 bytes (assuming i586 +code). Under the same conditions, the msdos filesystem would need +about 30K (and does not support device nodes or symlinks), while the +nfs module with nfsroot is about 57K. Furthermore, as a bit unfair +comparison, an actual rescue disk used up 3202 blocks with ext2, while +with romfs, it needed 3079 blocks. To create such a file system, you'll need a user program named -genromfs. It is (or will be shortly) available via ftp on -sunsite.unc.edu and its mirrors, in the /pub/Linux/system/Filesystems/ -directory. +genromfs. It is available via anonymous ftp on sunsite.unc.edu and +its mirrors, in the /pub/Linux/system/recovery/ directory. As the name suggests, romfs could be also used (space-efficiently) on various read-only medias, like (E)EPROM disks if someone will have the @@ -61,7 +60,7 @@ offset content +---+---+---+---+ 0 | - | r | o | m | \ +---+---+---+---+ The ASCII representation of those bytes - 4 | 1 | f | s | - | / (i.e. "-rom1fs-" + 4 | 1 | f | s | - | / (i.e. "-rom1fs-") +---+---+---+---+ 8 | full size | The number of accessible bytes in this fs. +---+---+---+---+ @@ -77,7 +76,7 @@ Every multi byte value (32 bit words, I' now on) must be in big endian order. The first eight bytes identify the filesystem, even for the casual -reader. After that in the 3rd longword, it contains the number of +inspector. After that, in the 3rd longword, it contains the number of bytes accessible from the start of this filesystem. The 4th longword is the checksum of the first 512 bytes (or the number of bytes accessible, whichever is smallest). The applied algorithm is the same @@ -101,7 +100,7 @@ offset content 12 | checksum | Covering the meta data, including the file +---+---+---+---+ name, and padding 16 | file name | The zero terminated name of the file, - : : padded to 16 byte boundary. + : : padded to 16 byte boundary +---+---+---+---+ xx | file data | : : @@ -112,9 +111,10 @@ bits are used for the mode information. the file; while bit 4 shows if the file is executable or not. The permissions are assumed to be world readable, if this bit is not set, and world executable if it is; except the character and block devices, -they are readable only for the owner. The owner of every file is user -and group 0, this should never be a problem for the intended use. The -mapping of the 8 possible values to file types is the following: +they are never accessible for other than owner. The owner of every +file is user and group 0, this should never be a problem for the +intended use. The mapping of the 8 possible values to file types is +the following: mapping spec.info means 0 hard link link destination [file header] @@ -128,14 +128,14 @@ mapping of the 8 possible values to file Note that hard links are specifically marked in this filesystem, but they will behave as you can expect (i.e. share the inode number). -Note also that your responsibility to not create hard link loops, and -creating all the . and .. links for directories. This is normally -done correctly by the genromfs program. Please refrain from using the -executable bits on the socket and fifo special files, they may have -other uses in the future. Additionally, please remember that only -regular files, and symlinks are supposed to have a nonzero size field; -they contain the number of bytes available directly after the (padded) -file name. +Note also that it is your responsibility to not create hard link +loops, and creating all the . and .. links for directories. This is +normally done correctly by the genromfs program. Please refrain from +using the executable bits for special purposes on the socket and fifo +special files, they may have other uses in the future. Additionally, +please remember that only regular files, and symlinks are supposed to +have a nonzero size field; they contain the number of bytes available +directly after the (padded) file name. Another thing to note is that romfs works on file headers and data aligned to 16 byte boundaries, but most hardware devices and the block @@ -145,8 +145,44 @@ padded to an 1024 byte boundary. If you have any problems or suggestions concerning this file system, please contact me. However, think twice before wanting me to add -features and code, because the primary advantage of this file system -is the small code. +features and code, because the primary and most important advantage of +this file system is the small code. On the other hand, don't be +alarmed, I'm not getting that much romfs related mail. Now I can +understand why Avery wrote poems in the arcnet docs to get some more +feedback. :) + +romfs has also a mailing list, and to date, it hasn't received any +traffic, so you are welcome to join it to discuss your ideas. :) + +It's run by ezmlm, so you can subscribe to it by sending a message +to romfs-subscribe@shadow.banki.hu, the content is irrelevant. + +Pending issues: + +- Permissions and owner information are pretty essential features of a +Un*x like system, but romfs does not provide the full possibilities. +I have never found this limiting, but others might. + +- The file system is read only, so it can be very small, but in case +one would want to write _anything_ to a file system, he still needs +a writable file system, thus negating the size advantages. Possible +solutions: implement write access as a compile-time option, or a new, +similarly small writable filesystem for ram disks. + +- Since the files are only required to have alignment on a 16 byte +boundary, it is currently possibly suboptimal to read or execute files +from the filesystem. It might be resolved by reordering file data to +have most of it (i.e. except the start and the end) laying at "natural" +boundaries, thus it would be possible to directly map a big portion of +the file contents to the mm subsystem. + +- Compression might be an useful feature, but memory is quite a +limiting factor in my eyes. + +- Where it is used? + +- Does it work on other architectures than intel and motorola? + Have fun, Janos Farkas <chexum@shadow.banki.hu> diff -urpN linux-2.1.46-orig/fs/romfs/inode.c linux/fs/romfs/inode.c --- linux-2.1.46-orig/fs/romfs/inode.c Sun Jul 20 13:10:49 1997 +++ linux/fs/romfs/inode.c Tue Jul 22 15:59:16 1997 @@ -18,12 +18,18 @@ * Changes * Changed for 2.1.19 modules * Jan 1997 Initial release + * Jun 1997 2.1.43+ changes + * Jul 1997 proper page locking in readpage + * Changed to work with 2.1.45+ fs */ /* todo: - * use malloced memory for file names? - * considering write access... - * network (tftp) files? + * - see Documentation/filesystems/romfs.txt + * - use malloced memory for file names? + * - considering write access... + * - network (tftp) files? + * - in the ancient times something leaked to made umounts + * impossible, but I've not seen it in the last months */ /* @@ -74,7 +80,7 @@ romfs_read_super(struct super_block *s, MOD_INC_USE_COUNT; - /* I would parse the options, but there are none.. :) */ + /* I would parse the options here, but there are none.. :) */ lock_super(s); set_blocksize(dev, ROMBSIZE); @@ -82,6 +88,7 @@ romfs_read_super(struct super_block *s, s->s_blocksize_bits = ROMBSBITS; bh = bread(dev, 0, ROMBSIZE); if (!bh) { + /* XXX merge with other printk? */ printk ("romfs: unable to read superblock\n"); goto outnobh; } @@ -113,10 +120,11 @@ romfs_read_super(struct super_block *s, brelse(bh); s->s_op = &romfs_ops; + s->s_root = d_alloc_root(iget(s, sz), NULL); unlock_super(s); - if (!(s->s_mounted = iget(s, sz))) + if (!s->s_root) goto outnobh; /* Ehrhm; sorry.. :) And thanks to Hans-Joachim Widmaier :) */ @@ -145,10 +153,9 @@ romfs_put_super(struct super_block *sb) return; } - /* That's simple too. */ -static void +static int romfs_statfs(struct super_block *sb, struct statfs *buf, int bufsize) { struct statfs tmp; @@ -157,9 +164,12 @@ romfs_statfs(struct super_block *sb, str tmp.f_type = ROMFS_MAGIC; tmp.f_bsize = ROMBSIZE; tmp.f_blocks = (sb->u.romfs_sb.s_maxsize+ROMBSIZE-1)>>ROMBSBITS; - copy_to_user(buf, &tmp, bufsize); + /* XXX tmp.f_namelen = relevant? */ + return copy_to_user(buf, &tmp, bufsize) ? -EFAULT : 0; } +/* some helper routines */ + static int romfs_strnlen(struct inode *i, unsigned long offset, unsigned long count) { @@ -238,8 +248,6 @@ romfs_copyfrom(struct inode *i, void *de return res; } -/* Directory operations */ - static int romfs_readdir(struct inode *i, struct file *filp, void *dirent, filldir_t filldir) { @@ -295,14 +303,16 @@ romfs_readdir(struct inode *i, struct fi } static int -romfs_lookup(struct inode *dir, const char *name, int len, struct inode **result) +romfs_lookup(struct inode *dir, struct dentry *dentry) { unsigned long offset, maxoff; int fslen, res; + struct inode *inode; char fsname[ROMFS_MAXFN]; /* XXX dynamic? */ struct romfs_inode ri; + const char *name; /* got from dentry */ + int len; - *result = NULL; if (!dir || !S_ISDIR(dir->i_mode)) { res = -EBADF; goto out; @@ -317,6 +327,12 @@ romfs_lookup(struct inode *dir, const ch maxoff = dir->i_sb->u.romfs_sb.s_maxsize; offset = ntohl(ri.spec) & ROMFH_MASK; + /* ok, now find the file, whose name is in "dentry", in the + * directory specified by "dir". */ + + name = dentry->d_name.name; + len = dentry->d_name.len; + for(;;) { if (!offset || offset >= maxoff || romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0) { @@ -350,20 +366,19 @@ romfs_lookup(struct inode *dir, const ch if ((ntohl(ri.next) & ROMFH_TYPE) == ROMFH_HRD) offset = ntohl(ri.spec) & ROMFH_MASK; - res = 0; - if (!(*result = iget(dir->i_sb, offset))) - res = -EACCES; + res = -EACCES; + if ((inode = iget(dir->i_sb, offset))!=NULL) { + res = 0; + d_add(dentry, inode); + } out: - iput(dir); return res; } /* * Ok, we do readpage, to be able to execute programs. Unfortunately, - * bmap is not applicable, since we have looser alignments. - * - * XXX I'm not quite sure that I need to muck around the PG_xx bits.. + * we can't use bmap, since we have looser alignments. */ static int @@ -373,8 +388,12 @@ romfs_readpage(struct inode * inode, str unsigned long offset, avail, readlen; int result = -EIO; - buf = page_address(page); atomic_inc(&page->count); + set_bit(PG_locked, &page->flags); + + buf = page_address(page); + clear_bit(PG_uptodate, &page->flags); + clear_bit(PG_error, &page->flags); offset = page->offset; if (offset < inode->i_size) { avail = inode->i_size-offset; @@ -383,13 +402,19 @@ romfs_readpage(struct inode * inode, str if (readlen < PAGE_SIZE) { memset((void *)(buf+readlen),0,PAGE_SIZE-readlen); } - result = 0; set_bit(PG_uptodate, &page->flags); - } else { - memset((void *)buf, 0, PAGE_SIZE); + result = 0; } } + if (result) { + set_bit(PG_error, &page->flags); + memset((void *)buf, 0, PAGE_SIZE); + } + + clear_bit(PG_locked, &page->flags); + wake_up(&page->wait); free_page(buf); + return result; } @@ -417,6 +442,44 @@ out: return mylen; } +static struct dentry * romfs_follow_link(struct inode * inode, struct dentry *base) +{ + char *link; + int len; + long err; + + /* note: 2.1.46 calls this for directories... not handled */ + + err = -EBADF; /* correct? */ + if (!S_ISLNK(inode->i_mode)) + goto outnobuf; + + len = inode->i_size; + + err = -EAGAIN; /* correct? */ + if (!(link = kmalloc(len+1, GFP_KERNEL))) + goto out; + + err = romfs_copyfrom(inode, link, inode->u.romfs_i.i_dataoffset, len); + if (err != len) { + err = -EIO; + goto out; + } else + link[len] = 0; + + base = lookup_dentry(link, base, 1); + kfree(link); + + if (0) { +out: + kfree(link); +outnobuf: + dput(base); + base = ERR_PTR(err); + } + return base; +} + /* Mapping from our types to the kernel */ static struct file_operations romfs_file_operations = { @@ -447,6 +510,7 @@ static struct inode_operations romfs_fil NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ + NULL, /* follow_link */ romfs_readpage, /* readpage */ NULL, /* writepage */ NULL, /* bmap -- not really */ @@ -471,7 +535,7 @@ static struct file_operations romfs_dir_ NULL /* revalidate */ }; -/* Merged dir/symlink op table. readdir/lookup/readlink +/* Merged dir/symlink op table. readdir/lookup/readlink/follow_link * will protect from type mismatch. */ @@ -487,6 +551,7 @@ static struct inode_operations romfs_dir NULL, /* mknod */ NULL, /* rename */ romfs_readlink, /* readlink */ + romfs_follow_link, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -519,9 +584,9 @@ romfs_read_inode(struct inode *i) int nextfh, ino; struct romfs_inode ri; - i->i_op = NULL; - ino = i->i_ino & ROMFH_MASK; + i->i_op = NULL; + i->i_mode = 0; /* Loop for finding the real hard link */ for(;;) { @@ -549,6 +614,7 @@ romfs_read_inode(struct inode *i) ino = ((ROMFH_SIZE+ino+1+ROMFH_PAD)&ROMFH_MASK); else ino = 0; + i->u.romfs_i.i_metasize = ino; i->u.romfs_i.i_dataoffset = ino+(i->i_ino&ROMFH_MASK); @@ -573,9 +639,10 @@ romfs_read_inode(struct inode *i) static struct super_operations romfs_ops = { romfs_read_inode, /* read inode */ - NULL, /* notify change */ NULL, /* write inode */ NULL, /* put inode */ + NULL, /* delete inode */ + NULL, /* notify change */ romfs_put_super, /* put super */ NULL, /* write super */ romfs_statfs, /* statfs */