lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:	Fri, 13 Jul 2007 16:01:48 +1000
From:	"Lindsay Roberts" <lindsay.roberts.os@...il.com>
To:	LKML <linux-kernel@...r.kernel.org>
Subject: [PATCH] fs: Add romfs version 2

* Increases romfs partition size limit from 2GB to 4GB.
* Adds new derivative of romfs filesystem (rom2fs) with
  block aligned regular file data to bring performance
  parity with ext2/3. This is about 225% of the read
  speed of the existing romfs.

Signed-off-by: Lindsay Roberts <lindsay.roberts.os@...il.com>
---
genromfs patch available at http://rom2fs.googlepages.com .

 Documentation/filesystems/romfs.txt |   34 +++++--
 fs/romfs/inode.c                    |  195 +++++++++++++++++++++++++++++------
 include/linux/romfs_fs.h            |    1 +
 3 files changed, 187 insertions(+), 43 deletions(-)

diff --git a/Documentation/filesystems/romfs.txt
b/Documentation/filesystems/romfs.txt
index 2d2a7b2..170b1cc 100644
--- a/Documentation/filesystems/romfs.txt
+++ b/Documentation/filesystems/romfs.txt
@@ -7,6 +7,10 @@ similar feature, and even the possibility of a small
kernel, with a
 file system which doesn't take up useful memory from the router
 functions in the basement of your office.

+The romfs version 2 filesystem is a slight derivation created to fix
+performance issues with file data unaligned to logical disk blocks.
+It differs only in its placement of regular file data.
+
 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
@@ -18,7 +22,10 @@ with romfs, it needed 3079 blocks.

 To create such a file system, you'll need a user program named
 genromfs.  It is available via anonymous ftp on sunsite.unc.edu and
-its mirrors, in the /pub/Linux/system/recovery/ directory.
+its mirrors, in the /pub/Linux/system/recovery/ directory, as well as
+at the sourceforge project http://romfs.sourceforge.net/ . A genromfs
+patch to support version 2 is available at
+http://rom2fs.googlepages.com/ .

 As the name suggests, romfs could be also used (space-efficiently) on
 various read-only media, like (E)EPROM disks if someone will have the
@@ -43,6 +50,11 @@ from the network, and you will have all the
tools/modules available
 from a nearby server, so you don't want to carry two disks for this
 purpose, just because it won't fit into ext2.

+romfs also has a secondary use in reproducibility. The absence of
+both timestamps and permission information coupled with the read-only
+nature of the file system gives it amazing capability as a byte
+reproducible medium for a given directory structure.
+
 romfs operates on block devices as you can expect, and the underlying
 structure is very simple.  Every accessible structure begins on 16
 byte boundaries for fast access.  The minimum space a file will take
@@ -50,7 +62,8 @@ is 32 bytes (this is an empty file, with a less than
16 character
 name).  The maximum overhead for any non-empty file is the header, and
 the 16 byte padding for the name and the contents, also 16+14+15 = 45
 bytes.  This is quite rare however, since most file names are longer
-than 3 bytes, and shorter than 15 bytes.
+than 3 bytes, and shorter than 15 bytes. romfs version 2 adds
+additional overhead in order to align file data to (1k) disk blocks.

 The layout of the filesystem is the following:

@@ -59,7 +72,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-" or "-rom2fs-")
 	+---+---+---+---+
   8	|   full size	|	The number of accessible bytes in this fs.
 	+---+---+---+---+
@@ -101,8 +114,10 @@ offset	    content
  16	| file name     |	The zero terminated name of the file,
 	:               :	padded to 16 byte boundary
 	+---+---+---+---+
- xx	| file data	|
-	:		:
+ xx	| file data	|       In the case of romfs version 2 - regular
+	:		:       files, this offset is padded to the next
+                                1024 byte block relative to the start of
+                                the filesystem.

 Since the file headers begin always at a 16 byte boundary, the lowest
 4 bits would be always zero in the next filehdr pointer.  These four
@@ -169,11 +184,12 @@ 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"
+boundary, it is currently 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.
+the file contents to the mm subsystem. This is addressed by romfs
+version 2.

 - Compression might be an useful feature, but memory is quite a
 limiting factor in my eyes.
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
index 2284e03..9fa99d2 100644
--- a/fs/romfs/inode.c
+++ b/fs/romfs/inode.c
@@ -49,6 +49,7 @@
  *	Aug 1999	2.3.16		__initfunc() => __init change
  *	Oct 1999	2.3.24		page->owner hack obsoleted
  *	Nov 1999	2.3.27		2.3.25+ page->offset => index change
+ *	Jul 2007			added romfs version 2
  */

 /* todo:
@@ -75,6 +76,7 @@
 #include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 #include <linux/vfs.h>
+#include <linux/mpage.h>

 #include <asm/uaccess.h>

@@ -84,10 +86,25 @@ struct romfs_inode_info {
 	struct inode vfs_inode;
 };

-/* instead of private superblock data */
-static inline unsigned long romfs_maxsize(struct super_block *sb)
+struct romfs_fs_info {
+	u32 version;
+	u32 size;
+};
+
+enum {
+	ROMFS_VERSION_1 = 1,
+	ROMFS_VERSION_2 = 2,
+};
+
+/* access private superblock data */
+static inline struct romfs_fs_info *get_romfs_priv(struct super_block *sb)
 {
-	return (unsigned long)sb->s_fs_info;
+	return (struct romfs_fs_info *) sb->s_fs_info;
+}
+
+static inline u32 romfs_maxsize(struct super_block *sb)
+{
+	return get_romfs_priv(sb)->size;
 }

 static inline struct romfs_inode_info *ROMFS_I(struct inode *inode)
@@ -95,6 +112,13 @@ static inline struct romfs_inode_info
*ROMFS_I(struct inode *inode)
 	return list_entry(inode, struct romfs_inode_info, vfs_inode);
 }

+/* Returns the block number containing the given byte offset */
+static __u32
+romfs_blocknum(struct super_block *sb, __u32 offset)
+{
+	return (offset - 1) >> sb->s_blocksize_bits;
+}
+
 static __u32
 romfs_checksum(void *data, int size)
 {
@@ -117,7 +141,8 @@ static int romfs_fill_super(struct super_block *s,
void *data, int silent)
 	struct buffer_head *bh;
 	struct romfs_super_block *rsb;
 	struct inode *root;
-	int sz;
+	u32 sz;
+	struct romfs_fs_info * rom_info = NULL;

 	/* I would parse the options here, but there are none.. :) */

@@ -127,39 +152,51 @@ static int romfs_fill_super(struct super_block
*s, void *data, int silent)
 	bh = sb_bread(s, 0);
 	if (!bh) {
 		/* XXX merge with other printk? */
-                printk ("romfs: unable to read superblock\n");
+		printk ("romfs: unable to read superblock\n");
 		goto outnobh;
 	}

 	rsb = (struct romfs_super_block *)bh->b_data;
 	sz = be32_to_cpu(rsb->size);
-	if (rsb->word0 != ROMSB_WORD0 || rsb->word1 != ROMSB_WORD1
+	if (rsb->word0 != ROMSB_WORD0
+	   ||   (rsb->word1 != ROMSB_WORD1
+	      && rsb->word1 != ROM2SB_WORD1)
 	   || sz < ROMFH_SIZE) {
 		if (!silent)
 			printk ("VFS: Can't find a romfs filesystem on dev "
 				"%s.\n", s->s_id);
 		goto out;
 	}
-	if (romfs_checksum(rsb, min_t(int, sz, 512))) {
+	if (romfs_checksum(rsb, min_t(u32, sz, 512))) {
 		printk ("romfs: bad initial checksum on dev "
 			"%s.\n", s->s_id);
 		goto out;
 	}

 	s->s_magic = ROMFS_MAGIC;
-	s->s_fs_info = (void *)(long)sz;
+
+	rom_info = kmalloc (sizeof(struct romfs_fs_info), GFP_KERNEL);
+	if (!rom_info) {
+		printk ("romfs: not enough memory\n");
+		goto out;
+	}
+	s->s_fs_info = rom_info;
+	rom_info->size = sz;
+	rom_info->version = ROMFS_VERSION_1; /* Default to original romfs */
+
+	if (rsb->word1 == ROM2SB_WORD1) {
+		rom_info->version = ROMFS_VERSION_2;
+	}
+
+	sz=ROMFH_SIZE+((ROMFH_PAD+strnlen(rsb->name,ROMFS_MAXFN)+1)&ROMFH_MASK);

 	s->s_flags |= MS_RDONLY;

-	/* Find the start of the fs */
-	sz = (ROMFH_SIZE +
-	      strnlen(rsb->name, ROMFS_MAXFN) + 1 + ROMFH_PAD)
-	     & ROMFH_MASK;

 	s->s_op	= &romfs_ops;
 	root = iget(s, sz);
 	if (!root)
-		goto out;
+		goto outkfree;

 	s->s_root = d_alloc_root(root);
 	if (!s->s_root)
@@ -170,12 +207,21 @@ static int romfs_fill_super(struct super_block
*s, void *data, int silent)

 outiput:
 	iput(root);
+outkfree:
+	kfree(rom_info);
 out:
 	brelse(bh);
 outnobh:
 	return -EINVAL;
 }

+static void
+romfs_put_super(struct super_block * sb)
+{
+	kfree(sb->s_fs_info);
+	sb->s_fs_info = NULL;
+}
+
 /* That's simple too. */

 static int
@@ -233,6 +279,36 @@ romfs_strnlen(struct inode *i, unsigned long
offset, unsigned long count)
 	return res;
 }

+/* Fills the private romfs inode struct with version specific data */
+static void
+romfs_fill_private_inode(struct inode *inode, int is_regular)
+{
+	struct romfs_inode_info *romfs_inode = ROMFS_I(inode);
+	int info_len;
+
+	info_len = romfs_strnlen(inode,
+				 (inode->i_ino & ROMFH_MASK) + ROMFH_SIZE,
+				 ROMFS_MAXFN);
+
+	if (likely(info_len >= 0))
+		info_len = ((ROMFH_SIZE+info_len+1+ROMFH_PAD)&ROMFH_MASK);
+	else
+		info_len = 0;
+
+	romfs_inode->i_metasize = info_len;
+
+	if (get_romfs_priv(inode->i_sb)->version > ROMFS_VERSION_1
+	&& is_regular) {
+		/* Data is on logical block directly after end of header */
+		romfs_inode->i_dataoffset =
+			romfs_blocknum(inode->i_sb,
+				       inode->i_ino+romfs_inode->i_metasize)+1;
+	} else {
+		/* Data is on 16 byte boundry after header */
+		romfs_inode->i_dataoffset = info_len+(inode->i_ino&ROMFH_MASK);
+	}
+}
+
 static int
 romfs_copyfrom(struct inode *i, void *dest, unsigned long offset,
unsigned long count)
 {
@@ -240,11 +316,13 @@ romfs_copyfrom(struct inode *i, void *dest,
unsigned long offset, unsigned long
 	unsigned long avail, maxsize, res;

 	maxsize = romfs_maxsize(i->i_sb);
-	if (offset >= maxsize || count > maxsize || offset+count>maxsize)
+	if (unlikely(	offset >= maxsize
+		     || count > maxsize
+		     || offset + count > maxsize))
 		return -1;

 	bh = sb_bread(i->i_sb, offset>>ROMBSBITS);
-	if (!bh)
+	if (unlikely(!bh))
 		return -1;		/* error */

 	avail = ROMBSIZE - (offset & ROMBMASK);
@@ -259,7 +337,7 @@ romfs_copyfrom(struct inode *i, void *dest,
unsigned long offset, unsigned long
 		dest += maxsize;

 		bh = sb_bread(i->i_sb, offset>>ROMBSBITS);
-		if (!bh)
+		if (unlikely(!bh))
 			return -1;
 		maxsize = min_t(unsigned long, count - res, ROMBSIZE);
 		memcpy(dest, bh->b_data, maxsize);
@@ -410,8 +488,8 @@ out:	unlock_kernel();
 }

 /*
- * Ok, we do readpage, to be able to execute programs.  Unfortunately,
- * we can't use bmap, since we may have looser alignments.
+ * romfs version one readpage function. File data is unaligned
+ * to logical block, must manually copy to kmap'd page.
  */

 static int
@@ -457,12 +535,64 @@ err_out:
 	return result;
 }

+/*
+ * Retrieves the disk logical block given a block relative to a file.
+ * Conforms to include/linux/fs.h:get_block_t
+ */
+int rom2fs_get_block(struct inode *inode, sector_t iblock, struct
buffer_head *bh_result, int create)
+{
+	sector_t disk_block = iblock + ROMFS_I(inode)->i_dataoffset;
+	map_bh(bh_result, inode->i_sb, disk_block);
+	return 0;
+}
+
+
+static int
+rom2fs_readpage(struct file *file, struct page * page)
+{
+	return mpage_readpage(page, rom2fs_get_block);
+}
+
+static int
+rom2fs_readpages(struct file *file, struct address_space * addr_space,
+		 struct list_head *pages, unsigned nr_pages)
+{
+	return mpage_readpages(addr_space, pages, nr_pages, rom2fs_get_block);
+}
+
+static sector_t
+rom2fs_bmap(struct address_space *mapping, sector_t block)
+{
+	return generic_block_bmap(mapping, block, rom2fs_get_block);
+}
+
+static ssize_t
+rom2fs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
+			loff_t offset, unsigned long nr_segs)
+{
+	struct file *file = iocb->ki_filp;
+	struct inode *inode = file->f_mapping->host;
+
+	return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
+				  offset, nr_segs, rom2fs_get_block, NULL);
+}
+
 /* Mapping from our types to the kernel */

 static const struct address_space_operations romfs_aops = {
 	.readpage = romfs_readpage
 };

+
+/* Operations for rom2fs - make use of block aligned file data */
+
+static const struct address_space_operations rom2fs_aops = {
+	.readpage 	= rom2fs_readpage,
+	.readpages 	= rom2fs_readpages,
+	.bmap 		= rom2fs_bmap,
+	.direct_IO 	= rom2fs_direct_IO,
+};
+
 static const struct file_operations romfs_dir_operations = {
 	.read		= generic_read_dir,
 	.readdir	= romfs_readdir,
@@ -508,21 +638,14 @@ romfs_read_inode(struct inode *i)
 	i->i_mtime.tv_nsec = i->i_atime.tv_nsec = i->i_ctime.tv_nsec = 0;
 	i->i_uid = i->i_gid = 0;

-        /* Precalculate the data offset */
-        ino = romfs_strnlen(i, ino+ROMFH_SIZE, ROMFS_MAXFN);
-        if (ino >= 0)
-                ino = ((ROMFH_SIZE+ino+1+ROMFH_PAD)&ROMFH_MASK);
-        else
-                ino = 0;
-
-        ROMFS_I(i)->i_metasize = ino;
-        ROMFS_I(i)->i_dataoffset = ino+(i->i_ino&ROMFH_MASK);
+	/* Precalculate the data offset */
+	romfs_fill_private_inode(i, ((nextfh & ROMFH_TYPE) == ROMFH_REG));

-        /* Compute permissions */
-        ino = romfs_modemap[nextfh & ROMFH_TYPE];
+	/* Compute permissions */
+	ino = romfs_modemap[nextfh & ROMFH_TYPE];
 	/* only "normal" files have ops */
 	switch (nextfh & ROMFH_TYPE) {
-		case 1:
+		case ROMFH_DIR:
 			i->i_size = ROMFS_I(i)->i_metasize;
 			i->i_op = &romfs_dir_inode_operations;
 			i->i_fop = &romfs_dir_operations;
@@ -530,14 +653,17 @@ romfs_read_inode(struct inode *i)
 				ino |= S_IXUGO;
 			i->i_mode = ino;
 			break;
-		case 2:
+		case ROMFH_REG:
 			i->i_fop = &generic_ro_fops;
-			i->i_data.a_ops = &romfs_aops;
+			if (get_romfs_priv(i->i_sb)->version == ROMFS_VERSION_1)
+				i->i_data.a_ops = &romfs_aops;
+			else
+				i->i_data.a_ops = &rom2fs_aops;
 			if (nextfh & ROMFH_EXEC)
 				ino |= S_IXUGO;
 			i->i_mode = ino;
 			break;
-		case 3:
+		case ROMFH_SYM:
 			i->i_op = &page_symlink_inode_operations;
 			i->i_data.a_ops = &romfs_aops;
 			i->i_mode = ino | S_IRWXUGO;
@@ -602,6 +728,7 @@ static const struct super_operations romfs_ops = {
 	.read_inode	= romfs_read_inode,
 	.statfs		= romfs_statfs,
 	.remount_fs	= romfs_remount,
+	.put_super	= romfs_put_super,
 };

 static int romfs_get_sb(struct file_system_type *fs_type,
@@ -624,7 +751,7 @@ static int __init init_romfs_fs(void)
 	int err = init_inodecache();
 	if (err)
 		goto out1;
-        err = register_filesystem(&romfs_fs_type);
+	err = register_filesystem(&romfs_fs_type);
 	if (err)
 		goto out;
 	return 0;
diff --git a/include/linux/romfs_fs.h b/include/linux/romfs_fs.h
index e20bbf9..ab7164b 100644
--- a/include/linux/romfs_fs.h
+++ b/include/linux/romfs_fs.h
@@ -15,6 +15,7 @@
 #define __mk4(a,b,c,d) cpu_to_be32(__mkl(__mkw(a,b),__mkw(c,d)))
 #define ROMSB_WORD0 __mk4('-','r','o','m')
 #define ROMSB_WORD1 __mk4('1','f','s','-')
+#define ROM2SB_WORD1 __mk4('2','f','s','-')

 /* On-disk "super block" */
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists