Commit 50ce4c07 authored by Egbert Eich's avatar Egbert Eich Committed by Tom Rini

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: default avatarEgbert Eich <eich@suse.com>
parent b1e6c4c3
......@@ -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);
}
......@@ -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;
......
......@@ -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
......
......@@ -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);
......
......@@ -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)
......
......@@ -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) {
......
......@@ -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
......@@ -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
......@@ -58,18 +57,13 @@
#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))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment