Skip to contentSkip to conversation

fs:ext4: Fixes and code cleanup

PATCH Superseded Lukasz Majewski 4 participants 15 messages Apr 30, 2014 – May 13, 2014 ext4 file system

lore
Share & tools
lore
#0 lore raw

cover fs:ext4: Fixes and code cleanup

This code fixes problem with storing file with the same name multiple times on the same ext4 fs (with different sizes).

Code reorganization and cleanup is also included.

Lukasz Majewski (2):
fs:ext4:cleanup: Remove superfluous code fs:ext4:write:fix: Reinitialize global variables after updating a
file

 fs/ext4/ext4_common.c |   29 +++++++++++++++-------------
 fs/ext4/ext4_write.c  |   51 +++++++++++++++++--------------------------------
 include/ext4fs.h      |    1 +
 3 files changed, 34 insertions(+), 47 deletions(-)
Signature · 1 line
1.7.10.4
#1 lore raw

PATCH 1/2 fs:ext4:cleanup: Remove superfluous code

Code responsible for handling situation when ext4 has block size of 1024B can be ordered to take less space.

This patch does that for ext4 common and write files.

---
 fs/ext4/ext4_common.c |    6 ++----
 fs/ext4/ext4_write.c  |   50 ++++++++++++++++---------------------------------
 2 files changed, 18 insertions(+), 38 deletions(-)
fs/ext4/ext4_common.c +2 -4
index 02da75c..62e2e80 100644
@@ -904,10 +904,8 @@ long int ext4fs_get_new_blk_no(void)
 restart:
 		fs->curr_blkno++;
 		/* get the blockbitmap index respective to blockno */
-		if (fs->blksz != 1024) {
-			bg_idx = fs->curr_blkno / blk_per_grp;
-		} else {
-			bg_idx = fs->curr_blkno / blk_per_grp;
+		bg_idx = fs->curr_blkno / blk_per_grp;
+		if (fs->blksz == 1024) {
 			remainder = fs->curr_blkno % blk_per_grp;
 			if (!remainder)
 				bg_idx--;
fs/ext4/ext4_write.c +16 -34

98 lines not on this page · raw message

Signature · 1 line
1.7.10.4
#2 lore raw

PATCH 1/2 fs:ext4:cleanup: Remove superfluous code

Quoted 6 lines · Lukasz Majewski

Code responsible for handling situation when ext4 has block size of 1024B can be ordered to take less space.

This patch does that for ext4 common and write files.

Quoted 9 lines
---
 fs/ext4/ext4_common.c |    6 ++----
 fs/ext4/ext4_write.c  |   50 ++++++++++++++++---------------------------------
 2 files changed, 18 insertions(+), 38 deletions(-)
fs/ext4/ext4_common.c +0 -0
index 02da75c..62e2e80 100644

[snip]

fs/ext4/ext4_common.c static void delete_double_indirect_block(struct ext2_inode *inode) · line 182

Quoted 9 lines
fs/ext4/ext4_common.c +1 -4
@@ -181,10 +179,8 @@ static void delete_double_indirect_block(struct ext2_inode *inode)
                                break;
 
                        debug("DICB releasing %u\n", *di_buffer);
-                       if (fs->blksz != 1024) {
-                               bg_idx = (*di_buffer) / blk_per_grp;
-                       } else {
-                               bg_idx = (*di_buffer) / blk_per_grp;
+                       bg_idx = (*di_buffer) / blk_per_grp;

You don't need the brackets here (or below).

Quoted 87 lines
fs/ext4/ext4_common.c +13 -27
+                       if (fs->blksz == 1024) {
                                remainder = (*di_buffer) % blk_per_grp;
                                if (!remainder)
                                        bg_idx--;
@@ -213,10 +209,8 @@ static void delete_double_indirect_block(struct ext2_inode *inode)
 
                /* removing the parent double indirect block */
                blknr = inode->b.blocks.double_indir_block;
-               if (fs->blksz != 1024) {
-                       bg_idx = blknr / blk_per_grp;
-               } else {
-                       bg_idx = blknr / blk_per_grp;
+               bg_idx = blknr / blk_per_grp;
+               if (fs->blksz == 1024) {
                        remainder = blknr % blk_per_grp;
                        if (!remainder)
                                bg_idx--;
@@ -293,11 +287,8 @@ static void delete_triple_indirect_block(struct ext2_inode *inode)
                        for (j = 0; j < fs->blksz / sizeof(int); j++) {
                                if (*tip_buffer == 0)
                                        break;
-                               if (fs->blksz != 1024) {
-                                       bg_idx = (*tip_buffer) / blk_per_grp;
-                               } else {
-                                       bg_idx = (*tip_buffer) / blk_per_grp;
-
+                               bg_idx = (*tip_buffer) / blk_per_grp;
+                               if (fs->blksz == 1024) {
                                        remainder = (*tip_buffer) % blk_per_grp;
                                        if (!remainder)
                                                bg_idx--;
@@ -336,11 +327,8 @@ static void delete_triple_indirect_block(struct ext2_inode *inode)
                         * removing the grand parent blocks
                         * which is connected to inode
                         */
-                       if (fs->blksz != 1024) {
-                               bg_idx = (*tigp_buffer) / blk_per_grp;
-                       } else {
-                               bg_idx = (*tigp_buffer) / blk_per_grp;
-
+                       bg_idx = (*tigp_buffer) / blk_per_grp;
+                       if (fs->blksz == 1024) {
                                remainder = (*tigp_buffer) % blk_per_grp;
                                if (!remainder)
                                        bg_idx--;
@@ -371,10 +359,8 @@ static void delete_triple_indirect_block(struct ext2_inode *inode)
 
                /* removing the grand parent triple indirect block */
                blknr = inode->b.blocks.triple_indir_block;
-               if (fs->blksz != 1024) {
-                       bg_idx = blknr / blk_per_grp;
-               } else {
-                       bg_idx = blknr / blk_per_grp;
+               bg_idx = blknr / blk_per_grp;
+               if (fs->blksz == 1024) {
                        remainder = blknr % blk_per_grp;
                        if (!remainder)
                                bg_idx--;
@@ -452,10 +438,8 @@ static int ext4fs_delete_file(int inodeno)
 
                for (i = 0; i < no_blocks; i++) {
                        blknr = read_allocated_block(&(node_inode->inode), i);
-                       if (fs->blksz != 1024) {
-                               bg_idx = blknr / blk_per_grp;
-                       } else {
-                               bg_idx = blknr / blk_per_grp;
+                       bg_idx = blknr / blk_per_grp;
+                       if (fs->blksz == 1024) {
                                remainder = blknr % blk_per_grp;
                                if (!remainder)
                                        bg_idx--;
@@ -499,10 +483,8 @@ static int ext4fs_delete_file(int inodeno)
                        no_blocks++;
                for (i = 0; i < no_blocks; i++) {
                        blknr = read_allocated_block(&inode, i);
-                       if (fs->blksz != 1024) {
-                               bg_idx = blknr / blk_per_grp;
-                       } else {
-                               bg_idx = blknr / blk_per_grp;
+                       bg_idx = blknr / blk_per_grp;
+                       if (fs->blksz == 1024) {
                                remainder = blknr % blk_per_grp;
                                if (!remainder)
                                        bg_idx--;
--

1.7.10.4

#3 lore raw

PATCH 1/2 fs:ext4:cleanup: Remove superfluous code

Hi Simon,

Quoted 26 lines
Quoted 6 lines · Lukasz Majewski

Code responsible for handling situation when ext4 has block size of 1024B can be ordered to take less space.

This patch does that for ext4 common and write files.

Quoted 10 lines
---
 fs/ext4/ext4_common.c |    6 ++----
 fs/ext4/ext4_write.c  |   50

++++++++++++++++--------------------------------- 2 files changed, 18 insertions(+), 38 deletions(-)

fs/ext4/ext4_common.c +0 -0
index 02da75c..62e2e80 100644

[snip]

Quoted 3 lines
fs/ext4/ext4_common.c +0 -0
@@ -181,10 +179,8 @@ static void
 delete_double_indirect_block(struct ext2_inode *inode) break;
 
Quoted 8 lines

fs/ext4/ext4_common.c static void · line 182

Quoted 6 lines
fs/ext4/ext4_common.c +1 -4
                        debug("DICB releasing %u\n", *di_buffer);
-                       if (fs->blksz != 1024) {
-                               bg_idx = (*di_buffer) / blk_per_grp;
-                       } else {
-                               bg_idx = (*di_buffer) / blk_per_grp;
+                       bg_idx = (*di_buffer) / blk_per_grp;

You don't need the brackets here (or below).

Maybe the GIT formatting is a bit misleading, but I've double checked and it seems that those parenthesis are necessary here.

Quoted 95 lines
Quoted 95 lines
fs/ext4/ext4_common.c +3 -4
+                       if (fs->blksz == 1024) {
                                remainder = (*di_buffer) %
 blk_per_grp; if (!remainder)
                                        bg_idx--;
@@ -213,10 +209,8 @@ static void
 delete_double_indirect_block(struct ext2_inode *inode)
 
                /* removing the parent double indirect block */
                blknr = inode->b.blocks.double_indir_block;
-               if (fs->blksz != 1024) {
-                       bg_idx = blknr / blk_per_grp;
-               } else {
-                       bg_idx = blknr / blk_per_grp;
+               bg_idx = blknr / blk_per_grp;
+               if (fs->blksz == 1024) {
                        remainder = blknr % blk_per_grp;
                        if (!remainder)
                                bg_idx--;
fs/ext4/ext4_common.c +0 -4
@@ -293,11 +287,8 @@ static void
 delete_triple_indirect_block(struct ext2_inode *inode) for (j = 0;
 j < fs->blksz / sizeof(int); j++) { if (*tip_buffer == 0)
                                        break;
-                               if (fs->blksz != 1024) {
-                                       bg_idx = (*tip_buffer) /
 blk_per_grp;
-                               } else {
-                                       bg_idx = (*tip_buffer) /

blk_per_grp; -
+ bg_idx = (*tip_buffer) /
blk_per_grp;
+ if (fs->blksz == 1024) {
remainder = (*tip_buffer) %
blk_per_grp; if (!remainder)

                                                bg_idx--;
fs/ext4/ext4_common.c +0 -4
@@ -336,11 +327,8 @@ static void
 delete_triple_indirect_block(struct ext2_inode *inode)
                         * removing the grand parent blocks
                         * which is connected to inode
                         */
-                       if (fs->blksz != 1024) {
-                               bg_idx = (*tigp_buffer) /
 blk_per_grp;
-                       } else {
-                               bg_idx = (*tigp_buffer) /

blk_per_grp; -

fs/ext4/ext4_common.c +2 -0
+                       bg_idx = (*tigp_buffer) / blk_per_grp;
+                       if (fs->blksz == 1024) {
                                remainder = (*tigp_buffer) %

blk_per_grp; if (!remainder)

                                        bg_idx--;
fs/ext4/ext4_common.c +2 -4
@@ -371,10 +359,8 @@ static void
 delete_triple_indirect_block(struct ext2_inode *inode)
 
                /* removing the grand parent triple indirect block
 */ blknr = inode->b.blocks.triple_indir_block;
-               if (fs->blksz != 1024) {
-                       bg_idx = blknr / blk_per_grp;
-               } else {
-                       bg_idx = blknr / blk_per_grp;
+               bg_idx = blknr / blk_per_grp;
+               if (fs->blksz == 1024) {
                        remainder = blknr % blk_per_grp;
                        if (!remainder)
                                bg_idx--;
fs/ext4/ext4_common.c +2 -4
@@ -452,10 +438,8 @@ static int ext4fs_delete_file(int inodeno)
 
                for (i = 0; i < no_blocks; i++) {
                        blknr =
 read_allocated_block(&(node_inode->inode), i);
-                       if (fs->blksz != 1024) {
-                               bg_idx = blknr / blk_per_grp;
-                       } else {
-                               bg_idx = blknr / blk_per_grp;
+                       bg_idx = blknr / blk_per_grp;
+                       if (fs->blksz == 1024) {
                                remainder = blknr % blk_per_grp;
                                if (!remainder)
                                        bg_idx--;
fs/ext4/ext4_common.c +2 -5
@@ -499,10 +483,8 @@ static int ext4fs_delete_file(int inodeno)
                        no_blocks++;
                for (i = 0; i < no_blocks; i++) {
                        blknr = read_allocated_block(&inode, i);
-                       if (fs->blksz != 1024) {
-                               bg_idx = blknr / blk_per_grp;
-                       } else {
-                               bg_idx = blknr / blk_per_grp;
+                       bg_idx = blknr / blk_per_grp;
+                       if (fs->blksz == 1024) {
                                remainder = blknr % blk_per_grp;
                                if (!remainder)
                                        bg_idx--;
--

1.7.10.4

Signature · 5 lines
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
#4 lore raw

PATCH 1/2 fs:ext4:cleanup: Remove superfluous code

Hi Lukasz,

Quoted 37 lines · Lukasz Majewski

Hi Simon,

Quoted 26 lines
Quoted 6 lines · Lukasz Majewski

Code responsible for handling situation when ext4 has block size of 1024B can be ordered to take less space.

This patch does that for ext4 common and write files.

Quoted 10 lines
---
 fs/ext4/ext4_common.c |    6 ++----
 fs/ext4/ext4_write.c  |   50

++++++++++++++++--------------------------------- 2 files changed, 18 insertions(+), 38 deletions(-)

fs/ext4/ext4_common.c +0 -0
index 02da75c..62e2e80 100644

[snip]

Quoted 3 lines
fs/ext4/ext4_common.c +0 -0
@@ -181,10 +179,8 @@ static void
 delete_double_indirect_block(struct ext2_inode *inode) break;
 
Quoted 8 lines

fs/ext4/ext4_common.c static void · line 182

Quoted 6 lines
fs/ext4/ext4_common.c +1 -4
                        debug("DICB releasing %u\n", *di_buffer);
-                       if (fs->blksz != 1024) {
-                               bg_idx = (*di_buffer) / blk_per_grp;
-                       } else {
-                               bg_idx = (*di_buffer) / blk_per_grp;
+                       bg_idx = (*di_buffer) / blk_per_grp;

You don't need the brackets here (or below).

Quoted 2 lines

Maybe the GIT formatting is a bit misleading, but I've double checked and it seems that those parenthesis are necessary here.

OK. What is di_buffer such that (*di_buffer) works but *di_buffer doesn't?

Regards,
Simon

#5 lore raw

PATCH 1/2 fs:ext4:cleanup: Remove superfluous code

Quoted 43 lines · On Mon, 5 May 2014 08:24:22 -0600 Simon Glass <[email protected]> wrote:

Hi Lukasz,

Quoted 39 lines · Lukasz Majewski

Hi Simon,

Quoted 36 lines
Quoted 6 lines · Lukasz Majewski

Code responsible for handling situation when ext4 has block size of 1024B can be ordered to take less space.

This patch does that for ext4 common and write files.

Quoted 10 lines
---
 fs/ext4/ext4_common.c |    6 ++----
 fs/ext4/ext4_write.c  |   50

++++++++++++++++--------------------------------- 2 files changed, 18 insertions(+), 38 deletions(-)

fs/ext4/ext4_common.c +0 -0
index 02da75c..62e2e80 100644

[snip]

fs/ext4/ext4_common.c static void · line 184

Quoted 11 lines
fs/ext4/ext4_common.c +1 -4
@@ -181,10 +179,8 @@ static void
 delete_double_indirect_block(struct ext2_inode *inode) break;
 
                        debug("DICB releasing %u\n", *di_buffer);
-                       if (fs->blksz != 1024) {
-                               bg_idx = (*di_buffer) /
 blk_per_grp;
-                       } else {
-                               bg_idx = (*di_buffer) /
 blk_per_grp;
+                       bg_idx = (*di_buffer) / blk_per_grp;

You don't need the brackets here (or below).

Quoted 5 lines
Quoted 2 lines

Maybe the GIT formatting is a bit misleading, but I've double checked and it seems that those parenthesis are necessary here.

OK. What is di_buffer such that (*di_buffer) works but *di_buffer doesn't?

It is hard to admit :-), but I've misunderstood you. I thought that you are talking about the {} parentheses.

I will check the code tomorrow and prepare proper patch.

Quoted 3 lines

Regards,
Simon

Best regards,
Lukasz Majewski
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20140505/417aecc9/attachment.pgp>

#6 lore raw

PATCH 1/2 fs:ext4:cleanup: Remove superfluous code

Hi Lukasz,

Quoted 49 lines · Lukasz Majewski
Quoted 46 lines · On Mon, 5 May 2014 08:24:22 -0600 Simon Glass <[email protected]> wrote:

Hi Lukasz,

Quoted 41 lines · Lukasz Majewski

Hi Simon,

Quoted 26 lines
Quoted 6 lines · Lukasz Majewski

Code responsible for handling situation when ext4 has block size of 1024B can be ordered to take less space.

This patch does that for ext4 common and write files.

Quoted 10 lines
---
 fs/ext4/ext4_common.c |    6 ++----
 fs/ext4/ext4_write.c  |   50

++++++++++++++++--------------------------------- 2 files changed, 18 insertions(+), 38 deletions(-)

fs/ext4/ext4_common.c +0 -0
index 02da75c..62e2e80 100644

[snip]

Quoted 3 lines
fs/ext4/ext4_common.c +0 -0
@@ -181,10 +179,8 @@ static void
 delete_double_indirect_block(struct ext2_inode *inode) break;
 
Quoted 10 lines

fs/ext4/ext4_common.c static void · line 184

Quoted 8 lines
fs/ext4/ext4_common.c +1 -4
                        debug("DICB releasing %u\n", *di_buffer);
-                       if (fs->blksz != 1024) {
-                               bg_idx = (*di_buffer) /
 blk_per_grp;
-                       } else {
-                               bg_idx = (*di_buffer) /
 blk_per_grp;
+                       bg_idx = (*di_buffer) / blk_per_grp;

You don't need the brackets here (or below).

Maybe the GIT formatting is a bit misleading, but I've double checked and it seems that those parenthesis are necessary here.

Quoted 7 lines
Quoted 2 lines

OK. What is di_buffer such that (*di_buffer) works but *di_buffer doesn't?

It is hard to admit :-), but I've misunderstood you. I thought that you are talking about the {} parentheses.

I will check the code tomorrow and prepare proper patch.

Ah, sorry I wasn't at all clear on that.

Regards,
Simon

#7 lore raw

PATCH 2/2 fs:ext4:write:fix: Reinitialize global variables after updating a file

In reply to Lukasz Majewski

This bug shows up when file stored on the ext4 file system is updated.

The ext4fs_delete_file() is responsible for deleting file's (e.g. uImage) data.
However some global data (especially ext4fs_indir2_block), which is used during file deletion are left unchanged.

The ext4fs_indir2_block pointer stores reference to old ext4 double indirect allocated blocks. When it is unchanged, after file deletion, ext4fs_write_file() uses the same pointer (since it is already initialized
- i.e. not NULL) to return number of blocks to write. This trunks larger file when previous one was smaller.

Lets consider following scenario:

1. Flash target with ext4 formatted boot.img (which has uImage [*] on itself)
2. Developer wants to upload their custom uImage [**]
- When new uImage [**] is smaller than the [*] - everything works correctly - we are able to store the whole smaller file with corrupted ext4fs_indir2_block pointer
- When new uImage [**] is larger than the [*] - theCRC is corrupted, since truncation on data stored at eMMC was done.
3. When uImage CRC error appears, then reboot and THOR/DFU reflashing causes proper setting of ext4fs_indir2_block() and after that uImage[**] is successfully stored (correct uImage [*] metadata is stored at an eMMC on the first flashing).

Due to above the bug was very difficult to reproduce.
This patch sets default values for all ext4fs_indir* pointers/variables.

---
 fs/ext4/ext4_common.c |   23 ++++++++++++++---------
 fs/ext4/ext4_write.c  |    1 +
 include/ext4fs.h      |    1 +
 3 files changed, 16 insertions(+), 9 deletions(-)
fs/ext4/ext4_common.c +14 -9
index 62e2e80..d0de285 100644
@@ -1841,16 +1841,8 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock)
 	return blknr;
 }
 
-void ext4fs_close(void)
+void ext4fs_reinit_global(void)
 {
-	if ((ext4fs_file != NULL) && (ext4fs_root != NULL)) {
-		ext4fs_free_node(ext4fs_file, &ext4fs_root->diropen);
-		ext4fs_file = NULL;
-	}
-	if (ext4fs_root != NULL) {
-		free(ext4fs_root);
-		ext4fs_root = NULL;
-	}
 	if (ext4fs_indir1_block != NULL) {
 		free(ext4fs_indir1_block);
 		ext4fs_indir1_block = NULL;
@@ -1870,6 +1862,19 @@ void ext4fs_close(void)
 		ext4fs_indir3_blkno = -1;
 	}
 }
+void ext4fs_close(void)
+{
+	if ((ext4fs_file != NULL) && (ext4fs_root != NULL)) {
+		ext4fs_free_node(ext4fs_file, &ext4fs_root->diropen);
+		ext4fs_file = NULL;
+	}
+	if (ext4fs_root != NULL) {
+		free(ext4fs_root);
+		ext4fs_root = NULL;
+	}
+
+	ext4fs_reinit_global();
+}
 
 int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name,
 				struct ext2fs_node **fnode, int *ftype)
fs/ext4/ext4_write.c +1 -0
index 46c573b..4a5f652 100644
@@ -562,6 +562,7 @@ static int ext4fs_delete_file(int inodeno)
 
 	ext4fs_update();
 	ext4fs_deinit();
+	ext4fs_reinit_global();
 
 	if (ext4fs_init() != 0) {
 		printf("error in File System init\n");
include/ext4fs.h +1 -0
index aacb147..fbbb002 100644
@@ -133,6 +133,7 @@ int ext4fs_open(const char *filename);
 int ext4fs_read(char *buf, unsigned len);
 int ext4fs_mount(unsigned part_length);
 void ext4fs_close(void);
+void ext4fs_reinit_global(void);
 int ext4fs_ls(const char *dirname);
 int ext4fs_exists(const char *filename);
 void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot);
Signature · 1 line
1.7.10.4
#8 lore raw

PATCH 2/2 fs:ext4:write:fix: Reinitialize global variables after updating a file

Hi Lukasz,

Quoted 27 lines · Lukasz Majewski

This bug shows up when file stored on the ext4 file system is updated.

The ext4fs_delete_file() is responsible for deleting file's (e.g. uImage) data.
However some global data (especially ext4fs_indir2_block), which is used during file deletion are left unchanged.

The ext4fs_indir2_block pointer stores reference to old ext4 double indirect allocated blocks. When it is unchanged, after file deletion, ext4fs_write_file() uses the same pointer (since it is already initialized
- i.e. not NULL) to return number of blocks to write. This trunks larger file when previous one was smaller.

Lets consider following scenario:

1. Flash target with ext4 formatted boot.img (which has uImage [*] on itself)
2. Developer wants to upload their custom uImage [**]
- When new uImage [**] is smaller than the [*] - everything works correctly - we are able to store the whole smaller file with corrupted ext4fs_indir2_block pointer
- When new uImage [**] is larger than the [*] - theCRC is corrupted, since truncation on data stored at eMMC was done.
3. When uImage CRC error appears, then reboot and THOR/DFU reflashing causes proper setting of ext4fs_indir2_block() and after that uImage[**] is successfully stored (correct uImage [*] metadata is stored at an eMMC on the first flashing).

Quoted 1 line

Due to above the bug was very difficult to reproduce.

I wonder if a sandbox test would be a good idea? You could fairly easy mkfs in a loopback file and write a U-Boot script to operate on it. See test/ for some examples.

Quoted 68 lines

This patch sets default values for all ext4fs_indir* pointers/variables.

---
 fs/ext4/ext4_common.c |   23 ++++++++++++++---------
 fs/ext4/ext4_write.c  |    1 +
 include/ext4fs.h      |    1 +
 3 files changed, 16 insertions(+), 9 deletions(-)
fs/ext4/ext4_common.c +14 -9
index 62e2e80..d0de285 100644
@@ -1841,16 +1841,8 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock)
        return blknr;
 }
 
-void ext4fs_close(void)
+void ext4fs_reinit_global(void)
 {
-       if ((ext4fs_file != NULL) && (ext4fs_root != NULL)) {
-               ext4fs_free_node(ext4fs_file, &ext4fs_root->diropen);
-               ext4fs_file = NULL;
-       }
-       if (ext4fs_root != NULL) {
-               free(ext4fs_root);
-               ext4fs_root = NULL;
-       }
        if (ext4fs_indir1_block != NULL) {
                free(ext4fs_indir1_block);
                ext4fs_indir1_block = NULL;
@@ -1870,6 +1862,19 @@ void ext4fs_close(void)
                ext4fs_indir3_blkno = -1;
        }
 }
+void ext4fs_close(void)
+{
+       if ((ext4fs_file != NULL) && (ext4fs_root != NULL)) {
+               ext4fs_free_node(ext4fs_file, &ext4fs_root->diropen);
+               ext4fs_file = NULL;
+       }
+       if (ext4fs_root != NULL) {
+               free(ext4fs_root);
+               ext4fs_root = NULL;
+       }
+
+       ext4fs_reinit_global();
+}
 
 int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name,
                                struct ext2fs_node **fnode, int *ftype)
fs/ext4/ext4_write.c +1 -0
index 46c573b..4a5f652 100644
@@ -562,6 +562,7 @@ static int ext4fs_delete_file(int inodeno)
 
        ext4fs_update();
        ext4fs_deinit();
+       ext4fs_reinit_global();
 
        if (ext4fs_init() != 0) {
                printf("error in File System init\n");
include/ext4fs.h +0 -0
index aacb147..fbbb002 100644

include/ext4fs.h int ext4fs_open(const char *filename); · line 136

Quoted 4 lines
include/ext4fs.h +1 -0
@@ -133,6 +133,7 @@ int ext4fs_open(const char *filename);
 int ext4fs_read(char *buf, unsigned len);
 int ext4fs_mount(unsigned part_length);
 void ext4fs_close(void);
+void ext4fs_reinit_global(void);

Can we have a comment as to what this function does?

Quoted 6 lines
include/ext4fs.h +0 -1
 int ext4fs_ls(const char *dirname);
 int ext4fs_exists(const char *filename);
 void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot);
--

1.7.10.4

Regards,
Simon

#9 lore raw

PATCH 2/2 fs:ext4:write:fix: Reinitialize global variables after updating a file

Hi Simon,

Quoted 33 lines

Hi Lukasz,

Quoted 29 lines · Lukasz Majewski

This bug shows up when file stored on the ext4 file system is updated.

The ext4fs_delete_file() is responsible for deleting file's (e.g. uImage) data.
However some global data (especially ext4fs_indir2_block), which is used during file deletion are left unchanged.

The ext4fs_indir2_block pointer stores reference to old ext4 double indirect allocated blocks. When it is unchanged, after file deletion, ext4fs_write_file() uses the same pointer (since it is already initialized
- i.e. not NULL) to return number of blocks to write. This trunks larger file when previous one was smaller.

Lets consider following scenario:

1. Flash target with ext4 formatted boot.img (which has uImage [*] on itself) 2. Developer wants to upload their custom uImage [**]
- When new uImage [**] is smaller than the [*] - everything
works correctly - we are able to store the whole smaller file with corrupted ext4fs_indir2_block pointer
- When new uImage [**] is larger than the [*] - theCRC is
corrupted, since truncation on data stored at eMMC was done.
3. When uImage CRC error appears, then reboot and THOR/DFU reflashing causes proper setting of ext4fs_indir2_block() and after that uImage[**] is successfully stored (correct uImage [*] metadata is stored at an eMMC on the first flashing).

Quoted 5 lines
Quoted 1 line

Due to above the bug was very difficult to reproduce.

I wonder if a sandbox test would be a good idea? You could fairly easy mkfs in a loopback file and write a U-Boot script to operate on it. See test/ for some examples.

If my time budget allows, I will try to add test to sandbox.

Quoted 65 lines
Quoted 65 lines

This patch sets default values for all ext4fs_indir* pointers/variables.

---
 fs/ext4/ext4_common.c |   23 ++++++++++++++---------
 fs/ext4/ext4_write.c  |    1 +
 include/ext4fs.h      |    1 +
 3 files changed, 16 insertions(+), 9 deletions(-)
fs/ext4/ext4_common.c +1 -9
index 62e2e80..d0de285 100644
@@ -1841,16 +1841,8 @@ long int read_allocated_block(struct
 ext2_inode *inode, int fileblock) return blknr;
 }
 
-void ext4fs_close(void)
+void ext4fs_reinit_global(void)
 {
-       if ((ext4fs_file != NULL) && (ext4fs_root != NULL)) {
-               ext4fs_free_node(ext4fs_file,
 &ext4fs_root->diropen);
-               ext4fs_file = NULL;
-       }
-       if (ext4fs_root != NULL) {
-               free(ext4fs_root);
-               ext4fs_root = NULL;
-       }
        if (ext4fs_indir1_block != NULL) {
                free(ext4fs_indir1_block);
                ext4fs_indir1_block = NULL;
fs/ext4/ext4_common.c +13 -0
@@ -1870,6 +1862,19 @@ void ext4fs_close(void)
                ext4fs_indir3_blkno = -1;
        }
 }
+void ext4fs_close(void)
+{
+       if ((ext4fs_file != NULL) && (ext4fs_root != NULL)) {
+               ext4fs_free_node(ext4fs_file,
 &ext4fs_root->diropen);
+               ext4fs_file = NULL;
+       }
+       if (ext4fs_root != NULL) {
+               free(ext4fs_root);
+               ext4fs_root = NULL;
+       }
+
+       ext4fs_reinit_global();
+}
 
 int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name,

struct ext2fs_node **fnode, int
*ftype) diff --git a/fs/ext4/ext4_write.c b/fs/ext4/ext4_write.c index 46c573b..4a5f652 100644

fs/ext4/ext4_write.c +1 -0
@@ -562,6 +562,7 @@ static int ext4fs_delete_file(int inodeno)
 
        ext4fs_update();
        ext4fs_deinit();
+       ext4fs_reinit_global();
 
Quoted 13 lines

include/ext4fs.h int ext4fs_open(const char *filename); · line 136

Quoted 11 lines
fs/ext4/ext4_write.c +0 -0
        if (ext4fs_init() != 0) {
                printf("error in File System init\n");
include/ext4fs.h +1 -0
index aacb147..fbbb002 100644
@@ -133,6 +133,7 @@ int ext4fs_open(const char *filename);
 int ext4fs_read(char *buf, unsigned len);
 int ext4fs_mount(unsigned part_length);
 void ext4fs_close(void);
+void ext4fs_reinit_global(void);

Can we have a comment as to what this function does?

I can add comment to the source code. No problem.

Quoted 10 lines
Quoted 7 lines
include/ext4fs.h +0 -0
 int ext4fs_ls(const char *dirname);
 int ext4fs_exists(const char *filename);
 void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node

*currroot); --
1.7.10.4

Regards,
Simon

Signature · 5 lines
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
#10 lore raw

v2 cover fs:ext4: Fixes and code cleanup

In reply to Lukasz Majewski

This code fixes problem with storing file with the same name multiple times on the same ext4 fs (with different sizes).

Code reorganization and cleanup is also included.

Lukasz Majewski (2):
fs:ext4:cleanup: Remove superfluous code fs:ext4:write:fix: Reinitialize global variables after updating a
file

 fs/ext4/ext4_common.c |   41 ++++++++++++++++++++++++-----------
 fs/ext4/ext4_write.c  |   57 +++++++++++++++++--------------------------------
 include/ext4fs.h      |    1 +
 3 files changed, 49 insertions(+), 50 deletions(-)
Signature · 1 line
1.7.10.4
#11 lore raw

PATCH v2 1/2 fs:ext4:cleanup: Remove superfluous code

Code responsible for handling situation when ext4 has block size of 1024B can be ordered to take less space.

This patch does that for ext4 common and write files.

---
Changes for v2:
- Remove () parenthesis around pointers

---
 fs/ext4/ext4_common.c |    6 ++----
 fs/ext4/ext4_write.c  |   56 +++++++++++++++++--------------------------------
 2 files changed, 21 insertions(+), 41 deletions(-)
fs/ext4/ext4_common.c +2 -4
index 02da75c..62e2e80 100644
@@ -904,10 +904,8 @@ long int ext4fs_get_new_blk_no(void)
 restart:
 		fs->curr_blkno++;
 		/* get the blockbitmap index respective to blockno */
-		if (fs->blksz != 1024) {
-			bg_idx = fs->curr_blkno / blk_per_grp;
-		} else {
-			bg_idx = fs->curr_blkno / blk_per_grp;
+		bg_idx = fs->curr_blkno / blk_per_grp;
+		if (fs->blksz == 1024) {
 			remainder = fs->curr_blkno % blk_per_grp;
 			if (!remainder)
 				bg_idx--;
fs/ext4/ext4_write.c +19 -37

104 lines not on this page · raw message

Signature · 1 line
1.7.10.4
#12 lore raw

PATCH v2 1/2 fs:ext4:cleanup: Remove superfluous code

Quoted 6 lines · ?ukasz Majewski

Code responsible for handling situation when ext4 has block size of 1024B can be ordered to take less space.

This patch does that for ext4 common and write files.

Applied to u-boot/master, thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20140512/43945f1a/attachment.pgp>
#13 lore raw

PATCH v2 2/2 fs:ext4:write:fix: Reinitialize global variables after updating a file

In reply to Lukasz Majewski

This bug shows up when file stored on the ext4 file system is updated.

The ext4fs_delete_file() is responsible for deleting file's (e.g. uImage) data.
However some global data (especially ext4fs_indir2_block), which is used during file deletion are left unchanged.

The ext4fs_indir2_block pointer stores reference to old ext4 double indirect allocated blocks. When it is unchanged, after file deletion, ext4fs_write_file() uses the same pointer (since it is already initialized
- i.e. not NULL) to return number of blocks to write. This trunks larger file when previous one was smaller.

Lets consider following scenario:

1. Flash target with ext4 formatted boot.img (which has uImage [*] on itself)
2. Developer wants to upload their custom uImage [**]
- When new uImage [**] is smaller than the [*] - everything works correctly - we are able to store the whole smaller file with corrupted ext4fs_indir2_block pointer
- When new uImage [**] is larger than the [*] - theCRC is corrupted, since truncation on data stored at eMMC was done.
3. When uImage CRC error appears, then reboot and LTHOR/DFU reflashing causes proper setting of ext4fs_indir2_block() and after that uImage[**] is successfully stored (correct uImage [*] metadata is stored at an eMMC on the first flashing).

Due to above the bug was very difficult to reproduce.
This patch sets default values for all ext4fs_indir* pointers/variables.

---
Changes for v2:
- Add comment describing the purpose of ext4fs_reinit_global() function

---
 fs/ext4/ext4_common.c |   35 ++++++++++++++++++++++++++---------
 fs/ext4/ext4_write.c  |    1 +
 include/ext4fs.h      |    1 +
 3 files changed, 28 insertions(+), 9 deletions(-)
fs/ext4/ext4_common.c +26 -9
index 62e2e80..1c11721 100644
@@ -1841,16 +1841,20 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock)
 	return blknr;
 }
 
-void ext4fs_close(void)
+/**
+ * ext4fs_reinit_global() - Reinitialize values of ext4 write implementation's
+ *			    global pointers
+ *
+ * This function assures that for a file with the same name but different size
+ * the sequential store on the ext4 filesystem will be correct.
+ *
+ * In this function the global data, responsible for internal representation
+ * of the ext4 data are initialized to the reset state. Without this, during
+ * replacement of the smaller file with the bigger truncation of new file was
+ * performed.
+ */
+void ext4fs_reinit_global(void)
 {
-	if ((ext4fs_file != NULL) && (ext4fs_root != NULL)) {
-		ext4fs_free_node(ext4fs_file, &ext4fs_root->diropen);
-		ext4fs_file = NULL;
-	}
-	if (ext4fs_root != NULL) {
-		free(ext4fs_root);
-		ext4fs_root = NULL;
-	}
 	if (ext4fs_indir1_block != NULL) {
 		free(ext4fs_indir1_block);
 		ext4fs_indir1_block = NULL;
@@ -1870,6 +1874,19 @@ void ext4fs_close(void)
 		ext4fs_indir3_blkno = -1;
 	}
 }
+void ext4fs_close(void)
+{
+	if ((ext4fs_file != NULL) && (ext4fs_root != NULL)) {
+		ext4fs_free_node(ext4fs_file, &ext4fs_root->diropen);
+		ext4fs_file = NULL;
+	}
+	if (ext4fs_root != NULL) {
+		free(ext4fs_root);
+		ext4fs_root = NULL;
+	}
+
+	ext4fs_reinit_global();
+}
 
 int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name,
 				struct ext2fs_node **fnode, int *ftype)
fs/ext4/ext4_write.c +1 -0
index 3db22f8..c42add9 100644
@@ -562,6 +562,7 @@ static int ext4fs_delete_file(int inodeno)
 
 	ext4fs_update();
 	ext4fs_deinit();
+	ext4fs_reinit_global();
 
 	if (ext4fs_init() != 0) {
 		printf("error in File System init\n");
include/ext4fs.h +1 -0
index aacb147..fbbb002 100644
@@ -133,6 +133,7 @@ int ext4fs_open(const char *filename);
 int ext4fs_read(char *buf, unsigned len);
 int ext4fs_mount(unsigned part_length);
 void ext4fs_close(void);
+void ext4fs_reinit_global(void);
 int ext4fs_ls(const char *dirname);
 int ext4fs_exists(const char *filename);
 void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot);
Signature · 1 line
1.7.10.4
#14 lore raw

PATCH v2 2/2 fs:ext4:write:fix: Reinitialize global variables after updating a file

Quoted 27 lines · ?ukasz Majewski

This bug shows up when file stored on the ext4 file system is updated.

The ext4fs_delete_file() is responsible for deleting file's (e.g. uImage) data.
However some global data (especially ext4fs_indir2_block), which is used during file deletion are left unchanged.

The ext4fs_indir2_block pointer stores reference to old ext4 double indirect allocated blocks. When it is unchanged, after file deletion, ext4fs_write_file() uses the same pointer (since it is already initialized
- i.e. not NULL) to return number of blocks to write. This trunks larger file when previous one was smaller.

Lets consider following scenario:

1. Flash target with ext4 formatted boot.img (which has uImage [*] on itself)
2. Developer wants to upload their custom uImage [**]
- When new uImage [**] is smaller than the [*] - everything works correctly - we are able to store the whole smaller file with corrupted ext4fs_indir2_block pointer
- When new uImage [**] is larger than the [*] - theCRC is corrupted, since truncation on data stored at eMMC was done.
3. When uImage CRC error appears, then reboot and LTHOR/DFU reflashing causes proper setting of ext4fs_indir2_block() and after that uImage[**] is successfully stored (correct uImage [*] metadata is stored at an eMMC on the first flashing).

Quoted 4 lines

Due to above the bug was very difficult to reproduce.
This patch sets default values for all ext4fs_indir* pointers/variables.

Applied to u-boot/master, thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20140512/83b32b6e/attachment.pgp>