fs/ext4: Support device block sizes != 512 bytes

The 512 byte block size was hard coded in the ext4 file systems.
Large harddisks today support bigger block sizes typically 4096
bytes.
This patch removes this limitation.

Signed-off-by: Egbert Eich <eich@suse.com>
diff --git a/fs/ext4/dev.c b/fs/ext4/dev.c
index 464a67d..3e993cc 100644
--- a/fs/ext4/dev.c
+++ b/fs/ext4/dev.c
@@ -40,6 +40,7 @@
 #include <config.h>
 #include <ext4fs.h>
 #include <ext_common.h>
+#include "ext4_common.h"
 
 unsigned long part_offset;
 
@@ -48,37 +49,41 @@
 
 void ext4fs_set_blk_dev(block_dev_desc_t *rbdd, disk_partition_t *info)
 {
+	assert(rbdd->blksz == (1 << rbdd->log2blksz));
 	ext4fs_block_dev_desc = rbdd;
 	part_info = info;
 	part_offset = info->start;
-	get_fs()->total_sect = (info->size * info->blksz) / SECTOR_SIZE;
+	get_fs()->total_sect = (info->size * info->blksz) >>
+		get_fs()->dev_desc->log2blksz;
 	get_fs()->dev_desc = rbdd;
 }
 
 int ext4fs_devread(int sector, int byte_offset, int byte_len, char *buf)
 {
-	ALLOC_CACHE_ALIGN_BUFFER(char, sec_buf, SECTOR_SIZE);
 	unsigned block_len;
+	int log2blksz = ext4fs_block_dev_desc->log2blksz;
+	ALLOC_CACHE_ALIGN_BUFFER(char, sec_buf, (ext4fs_block_dev_desc ?
+						 ext4fs_block_dev_desc->blksz :
+						 0));
+	if (ext4fs_block_dev_desc == NULL) {
+		printf("** Invalid Block Device Descriptor (NULL)\n");
+		return 0;
+	}
 
 	/* Check partition boundaries */
-	if ((sector < 0)
-	    || ((sector + ((byte_offset + byte_len - 1) >> SECTOR_BITS)) >=
-		part_info->size)) {
+	if ((sector < 0) ||
+	    ((sector + ((byte_offset + byte_len - 1) >> log2blksz))
+	     >= part_info->size)) {
 		printf("%s read outside partition %d\n", __func__, sector);
 		return 0;
 	}
 
 	/* Get the read to the beginning of a partition */
-	sector += byte_offset >> SECTOR_BITS;
-	byte_offset &= SECTOR_SIZE - 1;
+	sector += byte_offset >> log2blksz;
+	byte_offset &= ext4fs_block_dev_desc->blksz - 1;
 
 	debug(" <%d, %d, %d>\n", sector, byte_offset, byte_len);
 
-	if (ext4fs_block_dev_desc == NULL) {
-		printf("** Invalid Block Device Descriptor (NULL)\n");
-		return 0;
-	}
-
 	if (byte_offset != 0) {
 		/* read first part which isn't aligned with start of sector */
 		if (ext4fs_block_dev_desc->
@@ -89,9 +94,12 @@
 			return 0;
 		}
 		memcpy(buf, sec_buf + byte_offset,
-			min(SECTOR_SIZE - byte_offset, byte_len));
-		buf += min(SECTOR_SIZE - byte_offset, byte_len);
-		byte_len -= min(SECTOR_SIZE - byte_offset, byte_len);
+			min(ext4fs_block_dev_desc->blksz
+			    - byte_offset, byte_len));
+		buf += min(ext4fs_block_dev_desc->blksz
+			   - byte_offset, byte_len);
+		byte_len -= min(ext4fs_block_dev_desc->blksz
+				- byte_offset, byte_len);
 		sector++;
 	}
 
@@ -99,12 +107,12 @@
 		return 1;
 
 	/* read sector aligned part */
-	block_len = byte_len & ~(SECTOR_SIZE - 1);
+	block_len = byte_len & ~(ext4fs_block_dev_desc->blksz - 1);
 
 	if (block_len == 0) {
-		ALLOC_CACHE_ALIGN_BUFFER(u8, p, SECTOR_SIZE);
+		ALLOC_CACHE_ALIGN_BUFFER(u8, p, ext4fs_block_dev_desc->blksz);
 
-		block_len = SECTOR_SIZE;
+		block_len = ext4fs_block_dev_desc->blksz;
 		ext4fs_block_dev_desc->block_read(ext4fs_block_dev_desc->dev,
 						  part_info->start + sector,
 						  1, (unsigned long *)p);
@@ -114,16 +122,16 @@
 
 	if (ext4fs_block_dev_desc->block_read(ext4fs_block_dev_desc->dev,
 					       part_info->start + sector,
-					       block_len / SECTOR_SIZE,
+					       block_len >> log2blksz,
 					       (unsigned long *) buf) !=
-					       block_len / SECTOR_SIZE) {
+					       block_len >> log2blksz) {
 		printf(" ** %s read error - block\n", __func__);
 		return 0;
 	}
-	block_len = byte_len & ~(SECTOR_SIZE - 1);
+	block_len = byte_len & ~(ext4fs_block_dev_desc->blksz - 1);
 	buf += block_len;
 	byte_len -= block_len;
-	sector += block_len / SECTOR_SIZE;
+	sector += block_len / ext4fs_block_dev_desc->blksz;
 
 	if (byte_len != 0) {
 		/* read rest of data which are not in whole sector */
@@ -138,3 +146,13 @@
 	}
 	return 1;
 }
+
+int ext4_read_superblock(char *buffer)
+{
+	struct ext_filesystem *fs = get_fs();
+	int sect = SUPERBLOCK_START >> fs->dev_desc->log2blksz;
+	int off = SUPERBLOCK_START % fs->dev_desc->blksz;
+
+	return ext4fs_devread(sect, off, SUPERBLOCK_SIZE,
+				buffer);
+}
diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c
index f12b805..58880b4 100644
--- a/fs/ext4/ext4_common.c
+++ b/fs/ext4/ext4_common.c
@@ -71,18 +71,18 @@
 	uint64_t startblock;
 	uint64_t remainder;
 	unsigned char *temp_ptr = NULL;
-	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, sec_buf, SECTOR_SIZE);
 	struct ext_filesystem *fs = get_fs();
+	int log2blksz = fs->dev_desc->log2blksz;
+	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, sec_buf, fs->dev_desc->blksz);
 
-	startblock = off / (uint64_t)SECTOR_SIZE;
+	startblock = off >> log2blksz;
 	startblock += part_offset;
-	remainder = off % (uint64_t)SECTOR_SIZE;
-	remainder &= SECTOR_SIZE - 1;
+	remainder = off & (uint64_t)(fs->dev_desc->blksz - 1);
 
 	if (fs->dev_desc == NULL)
 		return;
 
-	if ((startblock + (size / SECTOR_SIZE)) >
+	if ((startblock + (size >> log2blksz)) >
 	    (part_offset + fs->total_sect)) {
 		printf("part_offset is %lu\n", part_offset);
 		printf("total_sector is %llu\n", fs->total_sect);
@@ -101,10 +101,10 @@
 						  startblock, 1, sec_buf);
 		}
 	} else {
-		if (size / SECTOR_SIZE != 0) {
+		if (size >> log2blksz != 0) {
 			fs->dev_desc->block_write(fs->dev_desc->dev,
 						  startblock,
-						  size / SECTOR_SIZE,
+						  size >> log2blksz,
 						  (unsigned long *)buf);
 		} else {
 			fs->dev_desc->block_read(fs->dev_desc->dev,
@@ -1459,6 +1459,7 @@
 {
 	long int blkno;
 	unsigned int blkoff, desc_per_blk;
+	int log2blksz = get_fs()->dev_desc->log2blksz;
 
 	desc_per_blk = EXT2_BLOCK_SIZE(data) / sizeof(struct ext2_block_group);
 
@@ -1469,7 +1470,7 @@
 	debug("ext4fs read %d group descriptor (blkno %ld blkoff %u)\n",
 	      group, blkno, blkoff);
 
-	return ext4fs_devread(blkno << LOG2_EXT2_BLOCK_SIZE(data),
+	return ext4fs_devread(blkno << (LOG2_BLOCK_SIZE(data) - log2blksz),
 			      blkoff, sizeof(struct ext2_block_group),
 			      (char *)blkgrp);
 }
@@ -1479,6 +1480,7 @@
 	struct ext2_block_group blkgrp;
 	struct ext2_sblock *sblock = &data->sblock;
 	struct ext_filesystem *fs = get_fs();
+	int log2blksz = get_fs()->dev_desc->log2blksz;
 	int inodes_per_block, status;
 	long int blkno;
 	unsigned int blkoff;
@@ -1495,7 +1497,8 @@
 	    (ino % __le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block;
 	blkoff = (ino % inodes_per_block) * fs->inodesz;
 	/* Read the inode. */
-	status = ext4fs_devread(blkno << LOG2_EXT2_BLOCK_SIZE(data), blkoff,
+	status = ext4fs_devread(blkno << (LOG2_BLOCK_SIZE(data) - log2blksz),
+				blkoff,
 				sizeof(struct ext2_inode), (char *)inode);
 	if (status == 0)
 		return 0;
@@ -1515,7 +1518,9 @@
 	unsigned long long start;
 	/* get the blocksize of the filesystem */
 	blksz = EXT2_BLOCK_SIZE(ext4fs_root);
-	log2_blksz = LOG2_EXT2_BLOCK_SIZE(ext4fs_root);
+	log2_blksz = LOG2_BLOCK_SIZE(ext4fs_root)
+		- get_fs()->dev_desc->log2blksz;
+
 	if (le32_to_cpu(inode->flags) & EXT4_EXTENTS_FL) {
 		char *buf = zalloc(blksz);
 		if (!buf)
@@ -1523,11 +1528,11 @@
 		struct ext4_extent_header *ext_block;
 		struct ext4_extent *extent;
 		int i = -1;
-		ext_block = ext4fs_get_extent_block(ext4fs_root, buf,
-						    (struct ext4_extent_header
-						     *)inode->b.
-						    blocks.dir_blocks,
-						    fileblock, log2_blksz);
+		ext_block =
+			ext4fs_get_extent_block(ext4fs_root, buf,
+						(struct ext4_extent_header *)
+						inode->b.blocks.dir_blocks,
+						fileblock, log2_blksz);
 		if (!ext_block) {
 			printf("invalid extent block\n");
 			free(buf);
@@ -1839,7 +1844,7 @@
 		blknr = __le32_to_cpu(ext4fs_indir3_block
 				      [rblock % perblock_child]);
 	}
-	debug("ext4fs_read_block %ld\n", blknr);
+	debug("read_allocated_block %ld\n", blknr);
 
 	return blknr;
 }
@@ -2193,13 +2198,12 @@
 	struct ext2_data *data;
 	int status;
 	struct ext_filesystem *fs = get_fs();
-	data = zalloc(sizeof(struct ext2_data));
+	data = zalloc(SUPERBLOCK_SIZE);
 	if (!data)
 		return 0;
 
 	/* Read the superblock. */
-	status = ext4fs_devread(1 * 2, 0, sizeof(struct ext2_sblock),
-				(char *)&data->sblock);
+	status = ext4_read_superblock((char *)&data->sblock);
 
 	if (status == 0)
 		goto fail;
diff --git a/fs/ext4/ext4_common.h b/fs/ext4/ext4_common.h
index 72cd020..6571df6 100644
--- a/fs/ext4/ext4_common.h
+++ b/fs/ext4/ext4_common.h
@@ -49,7 +49,7 @@
 
 #define S_IFLNK		0120000		/* symbolic link */
 #define BLOCK_NO_ONE		1
-#define SUPERBLOCK_SECTOR	2
+#define SUPERBLOCK_START	(2 * 512)
 #define SUPERBLOCK_SIZE	1024
 #define F_FILE			1
 
diff --git a/fs/ext4/ext4_journal.c b/fs/ext4/ext4_journal.c
index ba4a7bb..81aa5fc 100644
--- a/fs/ext4/ext4_journal.c
+++ b/fs/ext4/ext4_journal.c
@@ -534,16 +534,14 @@
 		jsb->s_start = cpu_to_be32(1);
 		jsb->s_sequence = cpu_to_be32(be32_to_cpu(jsb->s_sequence) + 1);
 		/* get the superblock */
-		ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE,
-			       (char *)fs->sb);
+		ext4_read_superblock((char *)fs->sb);
 		fs->sb->feature_incompat |= EXT3_FEATURE_INCOMPAT_RECOVER;
 
 		/* Update the super block */
 		put_ext4((uint64_t) (SUPERBLOCK_SIZE),
 			 (struct ext2_sblock *)fs->sb,
 			 (uint32_t) SUPERBLOCK_SIZE);
-		ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE,
-			       (char *)fs->sb);
+		ext4_read_superblock((char *)fs->sb);
 
 		blknr = read_allocated_block(&inode_journal,
 					 EXT2_JOURNAL_SUPERBLOCK);
diff --git a/fs/ext4/ext4_write.c b/fs/ext4/ext4_write.c
index c4e399c..0c1f62b 100644
--- a/fs/ext4/ext4_write.c
+++ b/fs/ext4/ext4_write.c
@@ -614,14 +614,13 @@
 	/* populate fs */
 	fs->blksz = EXT2_BLOCK_SIZE(ext4fs_root);
 	fs->inodesz = INODE_SIZE_FILESYSTEM(ext4fs_root);
-	fs->sect_perblk = fs->blksz / SECTOR_SIZE;
+	fs->sect_perblk = fs->blksz >> fs->dev_desc->log2blksz;
 
 	/* get the superblock */
 	fs->sb = zalloc(SUPERBLOCK_SIZE);
 	if (!fs->sb)
 		return -ENOMEM;
-	if (!ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE,
-			(char *)fs->sb))
+	if (!ext4_read_superblock((char *)fs->sb))
 		goto fail;
 
 	/* init journal */
@@ -722,7 +721,7 @@
 	ext4fs_free_journal();
 
 	/* get the superblock */
-	ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE, (char *)fs->sb);
+	ext4_read_superblock((char *)fs->sb);
 	fs->sb->feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
 	put_ext4((uint64_t)(SUPERBLOCK_SIZE),
 		 (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
@@ -766,9 +765,10 @@
 {
 	int i;
 	int blockcnt;
-	int log2blocksize = LOG2_EXT2_BLOCK_SIZE(ext4fs_root);
 	unsigned int filesize = __le32_to_cpu(file_inode->size);
 	struct ext_filesystem *fs = get_fs();
+	int log2blksz = fs->dev_desc->log2blksz;
+	int log2_fs_blocksize = LOG2_BLOCK_SIZE(ext4fs_root) - log2blksz;
 	int previous_block_number = -1;
 	int delayed_start = 0;
 	int delayed_extent = 0;
@@ -789,16 +789,16 @@
 		if (blknr < 0)
 			return -1;
 
-		blknr = blknr << log2blocksize;
+		blknr = blknr << log2_fs_blocksize;
 
 		if (blknr) {
 			if (previous_block_number != -1) {
 				if (delayed_next == blknr) {
 					delayed_extent += blockend;
-					delayed_next += blockend >> SECTOR_BITS;
+					delayed_next += blockend >> log2blksz;
 				} else {	/* spill */
-					put_ext4((uint64_t) (delayed_start *
-							     SECTOR_SIZE),
+					put_ext4((uint64_t)
+						 (delayed_start << log2blksz),
 						 delayed_buf,
 						 (uint32_t) delayed_extent);
 					previous_block_number = blknr;
@@ -806,7 +806,7 @@
 					delayed_extent = blockend;
 					delayed_buf = buf;
 					delayed_next = blknr +
-					    (blockend >> SECTOR_BITS);
+					    (blockend >> log2blksz);
 				}
 			} else {
 				previous_block_number = blknr;
@@ -814,13 +814,14 @@
 				delayed_extent = blockend;
 				delayed_buf = buf;
 				delayed_next = blknr +
-				    (blockend >> SECTOR_BITS);
+				    (blockend >> log2blksz);
 			}
 		} else {
 			if (previous_block_number != -1) {
 				/* spill */
-				put_ext4((uint64_t) (delayed_start *
-						     SECTOR_SIZE), delayed_buf,
+				put_ext4((uint64_t) (delayed_start <<
+						     log2blksz),
+					 delayed_buf,
 					 (uint32_t) delayed_extent);
 				previous_block_number = -1;
 			}
@@ -830,7 +831,7 @@
 	}
 	if (previous_block_number != -1) {
 		/* spill */
-		put_ext4((uint64_t) (delayed_start * SECTOR_SIZE),
+		put_ext4((uint64_t) (delayed_start << log2blksz),
 			 delayed_buf, (uint32_t) delayed_extent);
 		previous_block_number = -1;
 	}
@@ -921,7 +922,8 @@
 	/* Allocate data blocks */
 	ext4fs_allocate_blocks(file_inode, blocks_remaining,
 			       &blks_reqd_for_file);
-	file_inode->blockcnt = (blks_reqd_for_file * fs->blksz) / SECTOR_SIZE;
+	file_inode->blockcnt = (blks_reqd_for_file * fs->blksz) >>
+		fs->dev_desc->log2blksz;
 
 	temp_ptr = zalloc(fs->blksz);
 	if (!temp_ptr)
diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c
index 4dddde2..1954afb 100644
--- a/fs/ext4/ext4fs.c
+++ b/fs/ext4/ext4fs.c
@@ -60,10 +60,12 @@
 int ext4fs_read_file(struct ext2fs_node *node, int pos,
 		unsigned int len, char *buf)
 {
+	struct ext_filesystem *fs = get_fs();
 	int i;
 	int blockcnt;
-	int log2blocksize = LOG2_EXT2_BLOCK_SIZE(node->data);
-	int blocksize = 1 << (log2blocksize + DISK_SECTOR_BITS);
+	int log2blksz = fs->dev_desc->log2blksz;
+	int log2_fs_blocksize = LOG2_BLOCK_SIZE(node->data) - log2blksz;
+	int blocksize = (1 << (log2_fs_blocksize + log2blksz));
 	unsigned int filesize = __le32_to_cpu(node->inode.size);
 	int previous_block_number = -1;
 	int delayed_start = 0;
@@ -88,7 +90,7 @@
 		if (blknr < 0)
 			return -1;
 
-		blknr = blknr << log2blocksize;
+		blknr = blknr << log2_fs_blocksize;
 
 		/* Last block.  */
 		if (i == blockcnt - 1) {
@@ -110,7 +112,7 @@
 			if (previous_block_number != -1) {
 				if (delayed_next == blknr) {
 					delayed_extent += blockend;
-					delayed_next += blockend >> SECTOR_BITS;
+					delayed_next += blockend >> log2blksz;
 				} else {	/* spill */
 					status = ext4fs_devread(delayed_start,
 							delayed_skipfirst,
@@ -124,7 +126,7 @@
 					delayed_skipfirst = skipfirst;
 					delayed_buf = buf;
 					delayed_next = blknr +
-						(blockend >> SECTOR_BITS);
+						(blockend >> log2blksz);
 				}
 			} else {
 				previous_block_number = blknr;
@@ -133,7 +135,7 @@
 				delayed_skipfirst = skipfirst;
 				delayed_buf = buf;
 				delayed_next = blknr +
-					(blockend >> SECTOR_BITS);
+					(blockend >> log2blksz);
 			}
 		} else {
 			if (previous_block_number != -1) {