From de9e831675d72c08c2cc3361a8e9b413ff3facec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Tue, 6 Sep 2016 04:36:55 +0200 Subject: [PATCH] ext4: Correct block number handling, empty block vs. error code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit read_allocated block may return block number 0, which is just an indicator a chunk of the file is not backed by a block, i.e. it is sparse. During file deletions, just continue with the next logical block, for other operations treat blocknumber <= 0 as an error. For writes, blocknumber 0 should never happen, as U-Boot always allocates blocks for the whole file. Reading already handles this correctly, i.e. the read buffer is 0-fillled. Not treating block 0 as sparse block leads to FS corruption, e.g. ./sandbox/u-boot -c 'host bind 0 ./sandbox/test/fs/3GB.ext4.img ; ext4write host 0 0 /2.5GB.file 1 ' The 2.5GB.file from the fs test is actually a sparse file. Signed-off-by: Stefan BrĂ¼ns --- fs/ext4/ext4_common.c | 6 +++--- fs/ext4/ext4_write.c | 11 ++++++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index 5e874afc70..5f21dc7948 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -534,7 +534,7 @@ static int search_dir(struct ext2_inode *parent_inode, char *dirname) /* get the block no allocated to a file */ for (blk_idx = 0; blk_idx < directory_blocks; blk_idx++) { blknr = read_allocated_block(parent_inode, blk_idx); - if (blknr == 0) + if (blknr <= 0) goto fail; /* read the directory block */ @@ -828,7 +828,7 @@ int ext4fs_filename_unlink(char *filename) /* read the block no allocated to a file */ for (blk_idx = 0; blk_idx < directory_blocks; blk_idx++) { blknr = read_allocated_block(g_parent_inode, blk_idx); - if (blknr == 0) + if (blknr <= 0) break; inodeno = unlink_filename(filename, blknr); if (inodeno != -1) @@ -1590,7 +1590,7 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock) if (status == 0) { printf("** SI ext2fs read block (indir 1)" "failed. **\n"); - return 0; + return -1; } ext4fs_indir1_blkno = le32_to_cpu(inode->b.blocks. diff --git a/fs/ext4/ext4_write.c b/fs/ext4/ext4_write.c index 913c46e89f..e4f0905876 100644 --- a/fs/ext4/ext4_write.c +++ b/fs/ext4/ext4_write.c @@ -461,6 +461,10 @@ static int ext4fs_delete_file(int inodeno) /* release data blocks */ for (i = 0; i < no_blocks; i++) { blknr = read_allocated_block(&inode, i); + if (blknr == 0) + continue; + if (blknr < 0) + goto fail; bg_idx = blknr / blk_per_grp; if (fs->blksz == 1024) { remainder = blknr % blk_per_grp; @@ -718,6 +722,10 @@ void ext4fs_deinit(void) fs->curr_blkno = 0; } +/* + * Write data to filesystem blocks. Uses same optimization for + * contigous sectors as ext4fs_read_file + */ static int ext4fs_write_file(struct ext2_inode *file_inode, int pos, unsigned int len, char *buf) { @@ -744,7 +752,7 @@ static int ext4fs_write_file(struct ext2_inode *file_inode, int blockend = fs->blksz; int skipfirst = 0; blknr = read_allocated_block(file_inode, i); - if (blknr < 0) + if (blknr <= 0) return -1; blknr = blknr << log2_fs_blocksize; @@ -910,6 +918,7 @@ int ext4fs_write(const char *fname, unsigned char *buffer, /* copy the file content into data blocks */ if (ext4fs_write_file(file_inode, 0, sizebytes, (char *)buffer) == -1) { printf("Error in copying content\n"); + /* FIXME: Deallocate data blocks */ goto fail; } ibmap_idx = parent_inodeno / le32_to_cpu(ext4fs_root->sblock.inodes_per_group);