Re: [PATCH 1/2] Make cramfs little endian only

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Jeff Garzik wrote:
> Bitfields also generate lower-quality assembly than masks&shifts 
> (typically more instructions using additional temporaries to accomplish 
> the same thing), based on my own informal gcc testing.
> 
> You would think gcc would be advanced enough to turn bitfield use into 
> masks and shifts under the hood, but for whatever reason that often is 
> not the case in kernel code.
OK. I'll modify the cramfs structures and replace the bitfields so that the
data can be accessed using masks and shifts. This requires updating the userspace
tools aswell. There will be a new patch avaliable soon.

I worked on the copy-and-convert-problem today and created a new patch that
avoids the negative things pointed out by Linus earlier. I hope I got that
in the right way. However, there are still some functions whose implementations
depend on the machine's endianness. I hope that they will be obsolete as soon as
the new patch is available.

The changes were tested on the following types of machines:
An i386 compatible box (little endian)
UltraSparc IIi (big endian)

Signed-off-by: Andi Drebes <andi@xxxxxxxxxxxxxxxxxxx>
---
 fs/cramfs/inode.c |  131 +++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 96 insertions(+), 35 deletions(-)

diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index 350680f..ceb2c6e 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -4,6 +4,10 @@
  * Copyright (C) 1999 Linus Torvalds.
  *
  * This file is released under the GPL.
+ *
+ * Changelog:
+ *	11/07 - Andi Drebes <andi@xxxxxxxxxxxxxxxxxxx>
+ *	Made cramfs little endian only.
  */
 
 /*
@@ -37,9 +41,62 @@ static DEFINE_MUTEX(read_mutex);
 
 /* 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_to_cpu(x) && cramfs_size_to_cpu(x)) ? \
+			 cramfs_offset_to_cpu(x) << 2 : 1)
 #define OFFSET(x)	((x)->i_ino)
 
+#ifdef __BIG_ENDIAN
+
+/* Converts a cramfs_inode's offset field
+   from little endianto cpu endian */
+static u32 cramfs_offset_to_cpu(struct cramfs_inode *inode)
+{
+	u8 *inode_bytes = (u8 *)inode;
+	return ((inode_bytes[8] & 0xc0) >> 6) | (inode_bytes[9] << 2) |
+		(inode_bytes[10] << 10) | (inode_bytes[11] << 18);
+}
+
+/* Converts a cramfs_inode's namelength field
+   from little endian to cpu endian */
+static u32 cramfs_namelen_to_cpu(struct cramfs_inode *inode)
+{
+	u8 *inode_bytes = (u8 *)inode;
+	return inode_bytes[8] & 0x3f;
+}
+
+/* Converts a cramfs_inode's size field
+   from little endian to cpu endian */
+static u32 cramfs_size_to_cpu(struct cramfs_inode *inode)
+{
+	return ((inode->size & 0xff0000) >> 16) | (inode->size & 0x00ff00) |
+		((inode->size & 0x0000ff) << 16);
+}
+
+#elif defined(__LITTLE_ENDIAN)
+
+/* Converts a cramfs_inode's offset field
+   from little endian to cpu endian */
+static u32 cramfs_offset_to_cpu(struct cramfs_inode *inode)
+{
+	return inode->offset;
+}
+
+/* Converts a cramfs_inode's namelength field
+   from little endian to cpu endian */
+static u32 cramfs_namelen_to_cpu(struct cramfs_inode *inode)
+{
+	return inode->namelen;
+}
+
+/* Converts a cramfs_inode's size field
+   from little endian to cpu endian */
+static u32 cramfs_size_to_cpu(struct cramfs_inode *inode)
+{
+	return inode->size;
+}
+#else
+#error "Neither __BIG_ENDIAN nor __LITTLE_ENDIAN defined."
+#endif
 
 static int cramfs_iget5_test(struct inode *inode, void *opaque)
 {
@@ -53,13 +110,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) ||
+	if ((inode->i_mode != le16_to_cpu(cramfs_inode->mode)) ||
 	    (inode->i_gid != cramfs_inode->gid) ||
-	    (inode->i_uid != cramfs_inode->uid))
+	    (inode->i_uid != le16_to_cpu(cramfs_inode->uid)))
 		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_to_cpu(cramfs_inode))))
 		return 0; /* does not match */
 
 	return 1; /* matches */
@@ -69,10 +126,10 @@ 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_mode = le16_to_cpu(cramfs_inode->mode);
+	inode->i_uid = le16_to_cpu(cramfs_inode->uid);
+	inode->i_size = cramfs_size_to_cpu(cramfs_inode);
+	inode->i_blocks = (cramfs_size_to_cpu(cramfs_inode) - 1) / 512 + 1;
 	inode->i_gid = cramfs_inode->gid;
 	/* Struct copy intentional */
 	inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime;
@@ -94,7 +151,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_to_cpu(cramfs_inode)));
 	}
 	return 0;
 }
@@ -256,53 +313,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(le16_to_cpu(super.root.mode))) {
 		printk(KERN_ERR "cramfs: root is not a directory\n");
 		goto out;
 	}
-	root_offset = super.root.offset << 2;
+	root_offset = cramfs_offset_to_cpu(&super.root) << 2;
 	if (super.flags & CRAMFS_FLAG_FSID_VERSION_2) {
-		sbi->size=super.size;
-		sbi->blocks=super.fsid.blocks;
-		sbi->files=super.fsid.files;
+		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 +444,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_to_cpu(de) << 2;
 		memcpy(buf, name, namelen);
 		ino = CRAMINO(de);
-		mode = de->mode;
+		mode = le16_to_cpu(de->mode);
 		mutex_unlock(&read_mutex);
 		nextoffset = offset + sizeof(*de) + namelen;
 		for (;;) {
@@ -432,7 +493,7 @@ static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, s
 		if (sorted && (dentry->d_name.name[0] < name[0]))
 			break;
 
-		namelen = de->namelen << 2;
+		namelen = cramfs_namelen_to_cpu(de) << 2;
 		offset += sizeof(*de) + namelen;
 
 		/* Quick check that the name is roughly the right length */
@@ -484,8 +545,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(*(u32 *) cramfs_read(sb, blkptr_offset-4, 4));
+		compr_len = le32_to_cpu(*(u32 *) cramfs_read(sb, blkptr_offset, 4)) - start_offset;
 		mutex_unlock(&read_mutex);
 		pgdata = kmap(page);
 		if (compr_len == 0)
-
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux