patch-2.4.7 linux/fs/cramfs/inode.c

Next file: linux/fs/dcache.c
Previous file: linux/fs/cramfs/cramfs.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.6/linux/fs/cramfs/inode.c linux/fs/cramfs/inode.c
@@ -17,10 +17,16 @@
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/locks.h>
+#include <linux/blkdev.h>
+#include <linux/cramfs_fs.h>
 
 #include <asm/uaccess.h>
 
-#include "cramfs.h"
+#define CRAMFS_SB_MAGIC u.cramfs_sb.magic
+#define CRAMFS_SB_SIZE u.cramfs_sb.size
+#define CRAMFS_SB_BLOCKS u.cramfs_sb.blocks
+#define CRAMFS_SB_FILES u.cramfs_sb.files
+#define CRAMFS_SB_FLAGS u.cramfs_sb.flags
 
 static struct super_operations cramfs_ops;
 static struct inode_operations cramfs_dir_inode_operations;
@@ -40,6 +46,8 @@
 		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_blksize = PAGE_CACHE_SIZE;
 		inode->i_gid = cramfs_inode->gid;
 		inode->i_ino = CRAMINO(cramfs_inode);
 		/* inode->i_nlink is left 1 - arguably wrong for directories,
@@ -100,7 +108,11 @@
 static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned int len)
 {
 	struct buffer_head * bh_array[BLKS_PER_BUF];
-	unsigned i, blocknr, buffer;
+	struct buffer_head * read_array[BLKS_PER_BUF];
+	unsigned i, blocknr, buffer, unread;
+	unsigned long devsize;
+	int major, minor;
+	
 	char *data;
 
 	if (!len)
@@ -123,9 +135,34 @@
 		return read_buffers[i] + blk_offset;
 	}
 
+	devsize = ~0UL;
+	major = MAJOR(sb->s_dev);
+	minor = MINOR(sb->s_dev);
+
+	if (blk_size[major])
+		devsize = blk_size[major][minor] >> 2;
+
 	/* Ok, read in BLKS_PER_BUF pages completely first. */
-	for (i = 0; i < BLKS_PER_BUF; i++)
-		bh_array[i] = bread(sb->s_dev, blocknr + i, PAGE_CACHE_SIZE);
+	unread = 0;
+	for (i = 0; i < BLKS_PER_BUF; i++) {
+		struct buffer_head *bh;
+
+		bh = NULL;
+		if (blocknr + i < devsize) {
+			bh = getblk(sb->s_dev, blocknr + i, PAGE_CACHE_SIZE);
+			if (!buffer_uptodate(bh))
+				read_array[unread++] = bh;
+		}
+		bh_array[i] = bh;
+	}
+
+	if (unread) {
+		ll_rw_block(READ, unread, read_array);
+		do {
+			unread--;
+			wait_on_buffer(read_array[unread]);
+		} while (unread);
+	}
 
 	/* Ok, copy them to the staging area without sleeping. */
 	buffer = next_buffer;
@@ -167,34 +204,50 @@
 
 	/* Do sanity checks on the superblock */
 	if (super.magic != CRAMFS_MAGIC) {
-		printk("wrong magic\n");
-		goto out;
-	}
-	if (memcmp(super.signature, CRAMFS_SIGNATURE, sizeof(super.signature))) {
-		printk("wrong signature\n");
-		goto out;
+		/* check at 512 byte offset */
+		memcpy(&super, cramfs_read(sb, 512, sizeof(super)), sizeof(super));
+		if (super.magic != CRAMFS_MAGIC) {
+			printk(KERN_ERR "cramfs: wrong magic\n");
+			goto out;
+		}
 	}
+
+	/* get feature flags first */
 	if (super.flags & ~CRAMFS_SUPPORTED_FLAGS) {
-		printk("unsupported filesystem features\n");
+		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)) {
-		printk("root is not a directory\n");
+		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) {
+		sb->CRAMFS_SB_SIZE=super.size;
+		sb->CRAMFS_SB_BLOCKS=super.fsid.blocks;
+		sb->CRAMFS_SB_FILES=super.fsid.files;
+	} else {
+		sb->CRAMFS_SB_SIZE=1<<28;
+		sb->CRAMFS_SB_BLOCKS=0;
+		sb->CRAMFS_SB_FILES=0;
+	}
+	sb->CRAMFS_SB_MAGIC=super.magic;
+	sb->CRAMFS_SB_FLAGS=super.flags;
 	if (root_offset == 0)
-		printk(KERN_INFO "cramfs: note: empty filesystem");
-	else if (root_offset != sizeof(struct cramfs_super)) {
-		printk("bad root offset %lu\n", root_offset);
+		printk(KERN_INFO "cramfs: empty filesystem");
+	else if (!(super.flags & CRAMFS_FLAG_SHIFTED_ROOT_OFFSET) &&
+		 ((root_offset != sizeof(struct cramfs_super)) &&
+		  (root_offset != 512 + sizeof(struct cramfs_super))))
+	{
+		printk(KERN_ERR "cramfs: bad root offset %lu\n", root_offset);
 		goto out;
 	}
 
 	/* Set it all up.. */
-	sb->s_op	= &cramfs_ops;
-	sb->s_root 	= d_alloc_root(get_cramfs_inode(sb, &super.root));
+	sb->s_op = &cramfs_ops;
+	sb->s_root = d_alloc_root(get_cramfs_inode(sb, &super.root));
 	retval = sb;
 out:
 	return retval;
@@ -204,8 +257,10 @@
 {
 	buf->f_type = CRAMFS_MAGIC;
 	buf->f_bsize = PAGE_CACHE_SIZE;
+	buf->f_blocks = sb->CRAMFS_SB_BLOCKS;
 	buf->f_bfree = 0;
 	buf->f_bavail = 0;
+	buf->f_files = sb->CRAMFS_SB_FILES;
 	buf->f_ffree = 0;
 	buf->f_namelen = 255;
 	return 0;
@@ -270,14 +325,20 @@
 static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry)
 {
 	unsigned int offset = 0;
+	int sorted = dir->i_sb->CRAMFS_SB_FLAGS & CRAMFS_FLAG_SORTED_DIRS;
 
 	while (offset < dir->i_size) {
 		struct cramfs_inode *de;
 		char *name;
-		int namelen;
+		int namelen, retval;
 
 		de = cramfs_read(dir->i_sb, OFFSET(dir) + offset, sizeof(*de)+256);
 		name = (char *)(de+1);
+
+		/* Try to take advantage of sorted directories */
+		if (sorted && (dentry->d_name.name[0] < name[0]))
+			break;
+
 		namelen = de->namelen << 2;
 		offset += sizeof(*de) + namelen;
 
@@ -294,10 +355,16 @@
 		}
 		if (namelen != dentry->d_name.len)
 			continue;
-		if (memcmp(dentry->d_name.name, name, namelen))
+		retval = memcmp(dentry->d_name.name, name, namelen);
+		if (retval > 0)
 			continue;
-		d_add(dentry, get_cramfs_inode(dir->i_sb, de));
-		return NULL;
+		if (!retval) {
+			d_add(dentry, get_cramfs_inode(dir->i_sb, de));
+			return NULL;
+		}
+		/* else (retval < 0) */
+		if (sorted)
+			break;
 	}
 	d_add(dentry, NULL);
 	return NULL;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)