fs:ext4:write:fix: Reinitialize global variables after updating a file accepted/tizen/common/20140513.150712 submit/tizen_common/20140513.150414
authorLukasz Majewski <l.majewski@samsung.com>
Wed, 30 Apr 2014 07:08:49 +0000 (09:08 +0200)
committerLukasz Majewski <l.majewski@samsung.com>
Wed, 30 Apr 2014 10:44:01 +0000 (12:44 +0200)
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.

Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
fs/ext4/ext4_common.c
fs/ext4/ext4_write.c
include/ext4fs.h

index 62e2e80..d0de285 100644 (file)
@@ -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)
index 46c573b..4a5f652 100644 (file)
@@ -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");
index aacb147..fbbb002 100644 (file)
@@ -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);