fs/ext4: Support device block sizes != 512 bytes
authorEgbert Eich <eich@suse.com>
Wed, 1 May 2013 01:13:19 +0000 (01:13 +0000)
committerTom Rini <trini@ti.com>
Fri, 10 May 2013 12:16:33 +0000 (08:16 -0400)
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>
fs/ext4/dev.c
fs/ext4/ext4_common.c
fs/ext4/ext4_common.h
fs/ext4/ext4_journal.c
fs/ext4/ext4_write.c
fs/ext4/ext4fs.c
include/ext4fs.h
include/ext_common.h

index 464a67d5319cf771da2aad2036fb5abf46a3e42a..3e993cc220f09d97f85538adeee51eded9bf7076 100644 (file)
@@ -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 @@ static disk_partition_t *part_info;
 
 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 @@ int ext4fs_devread(int sector, int byte_offset, int byte_len, char *buf)
                        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 @@ int ext4fs_devread(int sector, int byte_offset, int byte_len, char *buf)
                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 @@ int ext4fs_devread(int sector, int byte_offset, int byte_len, char *buf)
 
        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 @@ int ext4fs_devread(int sector, int byte_offset, int byte_len, char *buf)
        }
        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);
+}
index f12b8056cc02abb788bf4d9d6b70cf1f3e0ee8f1..58880b467fbf678e029e793d1e26811675adf70e 100644 (file)
@@ -71,18 +71,18 @@ void put_ext4(uint64_t off, void *buf, uint32_t size)
        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 @@ void put_ext4(uint64_t off, void *buf, uint32_t size)
                                                  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 @@ static int ext4fs_blockgroup
 {
        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 @@ static int ext4fs_blockgroup
        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 @@ int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode)
        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 @@ int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode)
            (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 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock)
        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 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock)
                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 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock)
                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 @@ int ext4fs_mount(unsigned part_length)
        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;
index 72cd020711480fd641fc118dcbb28a46f7276b61..6571df62f0c3393c31c1c1acbaa56342eb756110 100644 (file)
@@ -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
 
index ba4a7bb713d2c4e2cfce80b702d37e8f720064f1..81aa5fc0f86edc0a584a31b367a92493a04739af 100644 (file)
@@ -534,16 +534,14 @@ end:
                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);
index c4e399ccfae55843bd786611d79c539470288048..0c1f62b60caf5d1ab82c2a5800700b14481e744f 100644 (file)
@@ -614,14 +614,13 @@ int ext4fs_init(void)
        /* 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 @@ void ext4fs_deinit(void)
        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 @@ static int ext4fs_write_file(struct ext2_inode *file_inode,
 {
        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 @@ static int ext4fs_write_file(struct ext2_inode *file_inode,
                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 @@ static int ext4fs_write_file(struct ext2_inode *file_inode,
                                        delayed_extent = blockend;
                                        delayed_buf = buf;
                                        delayed_next = blknr +
-                                           (blockend >> SECTOR_BITS);
+                                           (blockend >> log2blksz);
                                }
                        } else {
                                previous_block_number = blknr;
@@ -814,13 +814,14 @@ static int ext4fs_write_file(struct ext2_inode *file_inode,
                                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 @@ static int ext4fs_write_file(struct ext2_inode *file_inode,
        }
        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 @@ int ext4fs_write(const char *fname, unsigned char *buffer,
        /* 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)
index 4dddde247649f9e3d0214a74416cb706279a5144..1954afb91d8817109a8022ee1a7e136fd259d580 100644 (file)
@@ -60,10 +60,12 @@ void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot)
 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 @@ int ext4fs_read_file(struct ext2fs_node *node, int pos,
                if (blknr < 0)
                        return -1;
 
-               blknr = blknr << log2blocksize;
+               blknr = blknr << log2_fs_blocksize;
 
                /* Last block.  */
                if (i == blockcnt - 1) {
@@ -110,7 +112,7 @@ int ext4fs_read_file(struct ext2fs_node *node, int pos,
                        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 @@ int ext4fs_read_file(struct ext2fs_node *node, int pos,
                                        delayed_skipfirst = skipfirst;
                                        delayed_buf = buf;
                                        delayed_next = blknr +
-                                               (blockend >> SECTOR_BITS);
+                                               (blockend >> log2blksz);
                                }
                        } else {
                                previous_block_number = blknr;
@@ -133,7 +135,7 @@ int ext4fs_read_file(struct ext2fs_node *node, int pos,
                                delayed_skipfirst = skipfirst;
                                delayed_buf = buf;
                                delayed_next = blknr +
-                                       (blockend >> SECTOR_BITS);
+                                       (blockend >> log2blksz);
                        }
                } else {
                        if (previous_block_number != -1) {
index 025a2e89c2342d2668e22ca389bb516d46fc0244..379f7eb5e9fccd176ad5dfadfc4ad67541379361 100644 (file)
@@ -141,4 +141,5 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock);
 int ext4fs_probe(block_dev_desc_t *fs_dev_desc,
                 disk_partition_t *fs_partition);
 int ext4_read_file(const char *filename, void *buf, int offset, int len);
+int ext4_read_superblock(char *buffer);
 #endif
index 86373a6e501b463748abf6dd4d4d89189c8984a1..78a7808aa96ade0da0ccb2e665eec19afca6f106 100644 (file)
@@ -34,7 +34,6 @@
 #define __EXT_COMMON__
 #include <command.h>
 #define SECTOR_SIZE            0x200
-#define SECTOR_BITS            9
 
 /* Magic value used to identify an ext2 filesystem.  */
 #define        EXT2_MAGIC                      0xEF53
 #define FILETYPE_INO_SYMLINK           0120000
 #define EXT2_ROOT_INO                  2 /* Root inode */
 
-/* Bits used as offset in sector */
-#define DISK_SECTOR_BITS               9
 /* The size of an ext2 block in bytes.  */
 #define EXT2_BLOCK_SIZE(data)     (1 << LOG2_BLOCK_SIZE(data))
 
-/* Log2 size of ext2 block in 512 blocks.  */
-#define LOG2_EXT2_BLOCK_SIZE(data) (__le32_to_cpu \
-                               (data->sblock.log2_block_size) + 1)
-
 /* Log2 size of ext2 block in bytes.  */
-#define LOG2_BLOCK_SIZE(data)     (__le32_to_cpu \
-               (data->sblock.log2_block_size) + 10)
+#define LOG2_BLOCK_SIZE(data)     (__le32_to_cpu                  \
+                                   (data->sblock.log2_block_size) \
+                                   + EXT2_MIN_BLOCK_LOG_SIZE)
 #define INODE_SIZE_FILESYSTEM(data)    (__le32_to_cpu \
                        (data->sblock.inode_size))