Make cramfs little endian only
Subsystems (2)
cover Make cramfs little endian only
The following patchset makes cramfs little endian only and updates the documentation.
I already sent this updated version three weeks ago as a reply in a discussion (http://marc.info/?l=linux-fsdevel&m=119698067927762&w=2).
As I didn't get any further responses for the updated version (please let me know if I did something terribly wrong that prevented people from commenting it) I resend it.
The changes were tested on the following types of machines:
An i386 compatible box (little endian)
UltraSparc IIi (big endian)
Diffed against Linus' git tree.
PATCH RESEND 1/2 Make cramfs little endian only
The following patch makes cramfs little endian only.
When trying to mount a big endian image, an error message is produced.
The changes were tested on the following types of machines:
An i386 compatible box (little endian)
UltraSparc IIi (big endian)
--- fs/cramfs/inode.c | 119 ++++++++++++++++++++++++++++++--------------- include/linux/cramfs_fs.h | 22 ++++---- 2 files changed, 91 insertions(+), 50 deletions(-)
fs/cramfs/inode.c +80 -39
@@ -4,6 +4,10 @@* Copyright (C) 1999 Linus Torvalds. * * This file is released under the GPL. +* +* Changelog: +* 11/07 - Andi Drebes <[email protected]> +* Made cramfs little endian only. */ /*
@@ -34,13 +38,46 @@ static const struct address_space_operations cramfs_aops;static DEFINE_MUTEX (read_mutex); +#define CRAMFS_NAMELEN_MASK ((1ul << CRAMFS_NAMELEN_WIDTH)-1) +#define CRAMFS_MODE_MASK ((1ul << CRAMFS_MODE_WIDTH)-1) +#define CRAMFS_SIZE_MASK ((1ul << CRAMFS_SIZE_WIDTH)-1) + +static inline u32 cramfs_mode (struct cramfs_inode *inode) +{ +return le32_to_cpu (inode->mode_uid) &CRAMFS_MODE_MASK ; +} + +static inline u32 cramfs_uid (struct cramfs_inode *inode) +{ +return le32_to_cpu (inode->mode_uid) >>CRAMFS_MODE_WIDTH ; +} + +static inline u32 cramfs_size (struct cramfs_inode *inode) +{ +return le32_to_cpu (inode->size_gid) &CRAMFS_SIZE_MASK ; +} + +static inline u32 cramfs_gid (struct cramfs_inode *inode) +{ +return le32_to_cpu (inode->size_gid) >>CRAMFS_SIZE_WIDTH ; +} + +static inline u32 cramfs_offset (struct cramfs_inode *inode) +{ +return le32_to_cpu (inode->namelen_offset) >>CRAMFS_NAMELEN_WIDTH ; +} + +static inline u32 cramfs_namelen (struct cramfs_inode *inode) +{ +return le32_to_cpu (inode->namelen_offset) &CRAMFS_NAMELEN_MASK ; +}/* These two macros may change in future, to provide better st_ino semantics. */ -#define CRAMINO (x) (((x)->offset && (x)->size)?(x)->offset<<2:1) +#define CRAMINO (x) ((cramfs_offset(x) && cramfs_size(x)) ? \ + cramfs_offset(x) << 2 : 1)#define OFFSET (x) ((x)->i_ino) -static int cramfs_iget5_test (struct inode *inode,void *opaque) {struct cramfs_inode *cramfs_inode = opaque;
@@ -53,13 +90,13 @@ static int cramfs_iget5_test(struct inode *inode, void *opaque)/* all empty directories, char, block, pipe, and sock, share inode #1 */ -if ((inode->i_mode != cramfs_inode->mode) || - (inode->i_gid != cramfs_inode->gid) || - (inode->i_uid != cramfs_inode->uid)) +if ((inode->i_mode !=cramfs_mode (cramfs_inode)) || + (inode->i_gid !=cramfs_gid (cramfs_inode)) || + (inode->i_uid !=cramfs_uid (cramfs_inode)))return 0 ;/* does not match */ if ((S_ISCHR (inode->i_mode) ||S_ISBLK (inode->i_mode)) && - (inode->i_rdev !=old_decode_dev (cramfs_inode->size))) + (inode->i_rdev !=old_decode_dev (cramfs_size (cramfs_inode))))return 0 ;/* does not match */ return 1 ;/* matches */
@@ -69,11 +106,11 @@ static int cramfs_iget5_set(struct inode *inode, void *opaque) {static struct timespec zerotime;struct cramfs_inode *cramfs_inode = opaque; - inode->i_mode = cramfs_inode->mode; - inode->i_uid = cramfs_inode->uid; - inode->i_size = cramfs_inode->size; - inode->i_blocks = (cramfs_inode->size -1 ) /512 +1 ; - inode->i_gid = cramfs_inode->gid; + inode->i_mode =cramfs_mode (cramfs_inode); + inode->i_uid =cramfs_uid (cramfs_inode); + inode->i_size =cramfs_size (cramfs_inode); + inode->i_blocks = (cramfs_size (cramfs_inode) -1 ) /512 +1 ; + inode->i_gid =cramfs_gid (cramfs_inode);/* Struct copy intentional */ inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime; inode->i_ino =CRAMINO (cramfs_inode);
@@ -94,7 +131,7 @@ static int cramfs_iget5_set(struct inode *inode, void *opaque) inode->i_size =0 ; inode->i_blocks =0 ;init_special_inode (inode, inode->i_mode, -old_decode_dev (cramfs_inode->size)); +old_decode_dev (cramfs_size (cramfs_inode))); }return 0 ; }
@@ -256,53 +293,57 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent)mutex_unlock (&read_mutex);/* Do sanity checks on the superblock */ -if (super.magic !=CRAMFS_MAGIC ) { -/* check for wrong endianess */ -if (super.magic ==CRAMFS_MAGIC_WEND ) { -if (!silent) -printk (KERN_ERR "cramfs: wrong endianess\n" ); - goto out; - } - +if (le32_to_cpu (super.magic) !=CRAMFS_MAGIC && +le32_to_cpu (super.magic) !=CRAMFS_MAGIC_WEND ) {/* check at 512 byte offset */ mutex_lock (&read_mutex);memcpy (&super,cramfs_read (sb,512 ,sizeof (super)),sizeof (super));mutex_unlock (&read_mutex); -if (super.magic !=CRAMFS_MAGIC ) { -if (super.magic ==CRAMFS_MAGIC_WEND && !silent) -printk (KERN_ERR "cramfs: wrong endianess\n" ); -else if (!silent) + +if (le32_to_cpu (super.magic) ==CRAMFS_MAGIC_WEND ) + goto other_endian; +else if (le32_to_cpu (super.magic) !=CRAMFS_MAGIC ) { +if (!silent)printk (KERN_ERR "cramfs: wrong magic\n" ); + goto out; } } +/* check for wrong endianess */ +else if (le32_to_cpu (super.magic) ==CRAMFS_MAGIC_WEND ) { +other_endian: +if (!silent) +printk (KERN_ERR "cramfs: filesystems in big endian format are not supported any longer.\n" ); + + goto out; + }/* get feature flags first */ -if (super.flags & ~CRAMFS_SUPPORTED_FLAGS ) { +if (le32_to_cpu (super.flags) & ~CRAMFS_SUPPORTED_FLAGS ) {printk (KERN_ERR "cramfs: unsupported filesystem features\n" ); goto out; }/* Check that the root inode is in a sane state */ -if (!S_ISDIR (super.root.mode)) { +if (!S_ISDIR (cramfs_mode (&super.root))) {printk (KERN_ERR "cramfs: root is not a directory\n" ); goto out; } - root_offset = super.root.offset <<2 ; -if (super.flags &CRAMFS_FLAG_FSID_VERSION_2 ) { - sbi->size=super.size; - sbi->blocks=super.fsid.blocks; - sbi->files=super.fsid.files; + root_offset =cramfs_offset (&super.root) <<2 ; +if (__le32_to_cpu (super.flags) &CRAMFS_FLAG_FSID_VERSION_2 ) { + sbi->size =le32_to_cpu (super.size); + sbi->blocks =le32_to_cpu (super.fsid.blocks); + sbi->files =le32_to_cpu (super.fsid.files); }else { sbi->size=1 <<28 ; sbi->blocks=0 ; sbi->files=0 ; } - sbi->magic=super.magic; - sbi->flags=super.flags; + sbi->magic =le32_to_cpu (super.magic); + sbi->flags =le32_to_cpu (super.flags);if (root_offset ==0 )printk (KERN_INFO "cramfs: empty filesystem" ); -else if (!(super.flags &CRAMFS_FLAG_SHIFTED_ROOT_OFFSET ) && +else if (!(le32_to_cpu (super.flags) &CRAMFS_FLAG_SHIFTED_ROOT_OFFSET ) && ((root_offset !=sizeof (struct cramfs_super )) && (root_offset !=512 +sizeof (struct cramfs_super )))) {
@@ -383,10 +424,10 @@ static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir)* and the name padded out to 4-byte boundaries * with zeroes. */ - namelen = de->namelen <<2 ; + namelen =cramfs_namelen (de) <<2 ;memcpy (buf, name, namelen); ino =CRAMINO (de); - mode = de->mode; + mode =cramfs_mode (de);mutex_unlock (&read_mutex); nextoffset = offset +sizeof (*de) + namelen;for (;;) {
@@ -432,7 +473,7 @@ static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, sif (sorted && (dentry->d_name.name[0 ] < name[0 ]))break ; - namelen = de->namelen <<2 ; + namelen =cramfs_namelen (de) <<2 ; offset +=sizeof (*de) + namelen;/* Quick check that the name is roughly the right length */
@@ -484,8 +525,8 @@ static int cramfs_readpage(struct file *file, struct page * page) start_offset =OFFSET (inode) + maxblock*4 ;mutex_lock (&read_mutex);if (page->index) - start_offset = *(u32 *)cramfs_read (sb, blkptr_offset-4 ,4 ); - compr_len = (*(u32 *)cramfs_read (sb, blkptr_offset,4 ) - start_offset); + start_offset =le32_to_cpu (*(__le32 *)cramfs_read (sb, blkptr_offset-4 ,4 )); + compr_len =le32_to_cpu (*(__le32 *)cramfs_read (sb, blkptr_offset,4 )) - start_offset;mutex_unlock (&read_mutex); pgdata =kmap (page);if (compr_len ==0 )
include/linux/cramfs_fs.h +11 -11
@@ -28,9 +28,9 @@* Reasonably terse representation of the inode data. */ struct cramfs_inode { -__u32 mode:CRAMFS_MODE_WIDTH , uid:CRAMFS_UID_WIDTH ; +__le32 mode_uid;/* SIZE for device files is i_rdev */ -__u32 size:CRAMFS_SIZE_WIDTH , gid:CRAMFS_GID_WIDTH ; +__le32 size_gid;/* NAMELEN is the length of the file name, divided by 4 and rounded up. (cramfs doesn't support hard links.) */ /* OFFSET: For symlinks and non-empty regular files, this
@@ -39,24 +39,24 @@ struct cramfs_inode {see README). For non-empty directories it is the offset (divided by 4) of the inode of the first file in that directory. For anything else, offset is zero. */ - __u32 namelen:CRAMFS_NAMELEN_WIDTH, offset:CRAMFS_OFFSET_WIDTH; +__le32 namelen_offset; };struct cramfs_info { -__u32 crc; -__u32 edition; -__u32 blocks; -__u32 files; +__le32 crc; +__le32 edition; +__le32 blocks; +__le32 files; };/* * Superblock information at the beginning of the FS. */ struct cramfs_super { -__u32 magic;/* 0x28cd3d45 - random number */ -__u32 size;/* length in bytes */ -__u32 flags;/* feature flags */ -__u32 future;/* reserved for future use */ +__le32 magic;/* 0x28cd3d45 - random number */ +__le32 size;/* length in bytes */ +__le32 flags;/* feature flags */ +__le32 future;/* reserved for future use */ __u8 signature[16 ];/* "Compressed ROMFS" */ struct cramfs_info fsid;/* unique filesystem info */ __u8 name[16 ];/* user-defined name */
Signature · 1 line
1.5.1.53.g77e6f
PATCH RESEND 2/2 Make cramfs little endian only: Update documentation
In reply to Andi DrebesThe following patch updates the cramfs documentation according to the changes that make cramfs little endian only.
--- fs/cramfs/README | 19 +++++-------------- 1 files changed, 5 insertions(+), 14 deletions(-)
fs/cramfs/README +5 -14
@@ -6,8 +6,11 @@ a bit looser, e.g. it doesn't care if the <file_data> items are swapped around (though it does care that directory entries (inodes) in a given directory are contiguous, as this is used by readdir). -All data is currently in host-endian format; neither mkcramfs nor the -kernel ever do swabbing. (See section `Block Size' below.) +All data is now in little endian format. Before, it was in host endian +format. In order to make filesystem images more shareable between machines +with a different byte order, cramfs' specification ("this README file") +was updated. There will be no support for big endian filesystems in the +future. <filesystem>: <superblock>
@@ -108,18 +111,6 @@ kernels, not even necessarily kernels of the same architecture if PAGE_CACHE_SIZE is subject to change between kernel versions (currently possible with arm and ia64). -The remaining options try to make cramfs more sharable. - -One part of that is addressing endianness. The two options here are -`always use little-endian' (like ext2fs) or `writer chooses -endianness; kernel adapts at runtime'. Little-endian wins because of -code simplicity and little CPU overhead even on big-endian machines. - -The cost of swabbing is changing the code to use the le32_to_cpu -etc. macros as used by ext2fs. We don't need to swab the compressed -data, only the superblock, inodes and block pointers. - - The other part of making cramfs more sharable is choosing a block size. The options are:
Signature · 1 line
1.5.1.53.g77e6f