shithub: lwext4

Download patch

ref: c109281525bd972c75050db10980fe42ffdc80b7
parent: 5aa75f97a60f95b53a11caf31044363434227f07
author: gkostka <kostka.grzegorz@gmail.com>
date: Sun Oct 27 07:48:48 EDT 2013

FEATURES:
1. New io_raw block device. Allows to access windows partitions.
2. Demo app timings. Windows ext2/3/4 volume access.
3. Faster big file read/write operations (multi block mode).


diff: cannot open b/blockdev/io_raw//null: file does not exist: 'b/blockdev/io_raw//null'
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -25,9 +25,13 @@
 else()
 #Generic example target
 include_directories(blockdev/filedev)
+include_directories(blockdev/io_raw)
+
 aux_source_directory(blockdev/filedev FILEDEV_SRC)
+aux_source_directory(blockdev/io_raw IORAW_SRC)
 aux_source_directory(demos/generic GENERIC_SRC)
-add_executable(fileimage_demo ${GENERIC_SRC} ${FILEDEV_SRC})
+
+add_executable(fileimage_demo ${GENERIC_SRC} ${FILEDEV_SRC} ${IORAW_SRC})
 target_link_libraries(fileimage_demo lwext4)
 add_custom_target(size ALL DEPENDS lwext4 COMMAND size -B liblwext4.a)
 endif()
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,10 @@
 
-all: generic bf518 cortex-m3 cortex-m4 generic
-
+generic:
+	rm -R -f build_generic
+	mkdir build_generic
+	cd build_generic && cmake -G"Unix Makefiles" ../
+	cd build_generic && make
+	
 bf518:
 	rm -R -f build_bf518
 	mkdir build_bf518
@@ -18,14 +22,10 @@
 	mkdir build_cortex-m4
 	cd build_cortex-m4 && cmake -G"Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=../toolchain/cortex-m4.cmake ..
 	cd build_cortex-m4 && make
-	
-	
-generic:
-	rm -R -f build_generic
-	mkdir build_generic
-	cd build_generic && cmake -G"Unix Makefiles" ../
-	cd build_generic && make
-	
+
+all: generic bf518 cortex-m3 cortex-m4 generic
+
+
 	
 clean:
 	rm -R -f build_bf518
--- a/blockdev/filedev/ext4_filedev.c
+++ b/blockdev/filedev/ext4_filedev.c
@@ -33,7 +33,7 @@
 #include <string.h>
 
 /**@brief	Default filename.*/
-const char *fname = "ext2";
+static const char *fname = "ext2";
 
 /**@brief	Image block size.*/
 #define EXT4_FILEDEV_BSIZE		512
@@ -71,7 +71,7 @@
 	dev_file = fopen(fname, "r+b");
 
 	if(!dev_file)
-		return ENOENT;
+		return EIO;
 
 	if(fseek(dev_file, 0, SEEK_END))
 		return EFAULT;
--- /dev/null
+++ b/blockdev/io_raw/io_raw.c
@@ -1,0 +1,202 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <ext4_config.h>
+#include <ext4_blockdev.h>
+#include <ext4_errno.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+
+#ifdef WIN32
+#include <windows.h>
+#include <winioctl.h>
+
+
+/**@brief   Default filename.*/
+static const char *fname = "ext2";
+
+/**@brief   IO block size.*/
+#define EXT4_IORAW_BSIZE      512
+
+/**@brief   Image file descriptor.*/
+static HANDLE dev_file;
+
+
+/**********************BLOCKDEV INTERFACE**************************************/
+static int io_raw_open(struct ext4_blockdev *bdev);
+static int io_raw_bread(struct ext4_blockdev *bdev, void *buf, uint64_t blk_id,
+    uint32_t blk_cnt);
+static int io_raw_bwrite(struct ext4_blockdev *bdev, const void *buf,
+    uint64_t blk_id, uint32_t blk_cnt);
+static int io_raw_close(struct  ext4_blockdev *bdev);
+
+
+
+
+/******************************************************************************/
+EXT4_BLOCKDEV_STATIC_INSTANCE(
+    _filedev,
+    EXT4_IORAW_BSIZE,
+    0,
+    io_raw_open,
+    io_raw_bread,
+    io_raw_bwrite,
+    io_raw_close
+);
+
+/******************************************************************************/
+EXT4_BCACHE_STATIC_INSTANCE(__cache, 8, 1024);
+
+/******************************************************************************/
+static int io_raw_open(struct ext4_blockdev *bdev)
+{
+    char path[64];
+    DISK_GEOMETRY   pdg;
+    uint64_t disk_size;
+    BOOL bResult   = FALSE;
+    DWORD junk;
+
+    sprintf(path, "\\\\.\\%s", fname);
+
+    dev_file = CreateFile (path,
+            GENERIC_READ | GENERIC_WRITE,
+            FILE_SHARE_WRITE | FILE_SHARE_READ,
+            NULL,
+            OPEN_EXISTING,
+            0,
+            NULL);
+
+    if (dev_file == INVALID_HANDLE_VALUE){
+        return EIO;
+    }
+
+    bResult = DeviceIoControl(dev_file,
+            IOCTL_DISK_GET_DRIVE_GEOMETRY,
+            NULL, 0,
+            &pdg, sizeof(pdg),
+            &junk,
+            (LPOVERLAPPED) NULL);
+
+    if(bResult == FALSE){
+        CloseHandle(dev_file);
+        return EIO;
+    }
+
+
+    disk_size = pdg.Cylinders.QuadPart * (ULONG)pdg.TracksPerCylinder *
+            (ULONG)pdg.SectorsPerTrack * (ULONG)pdg.BytesPerSector;
+
+    _filedev.ph_bsize = pdg.BytesPerSector;
+    _filedev.ph_bcnt  = disk_size / pdg.BytesPerSector;
+
+
+    return EOK;
+}
+
+/******************************************************************************/
+
+static int io_raw_bread(struct  ext4_blockdev *bdev, void *buf, uint64_t blk_id,
+    uint32_t blk_cnt)
+{
+    long hipart = blk_id >> (32-9);
+    long lopart = blk_id << 9;
+    long err;
+
+    SetLastError (0);
+    lopart = SetFilePointer (dev_file, lopart, &hipart, FILE_BEGIN);
+
+    if (lopart == -1  &&  NO_ERROR != (err = GetLastError ()))
+    {
+        return EIO;
+    }
+
+    DWORD   n;
+
+    if (!ReadFile (dev_file, buf, blk_cnt * 512, &n, NULL))
+    {
+        err = GetLastError ();
+        return EIO;
+    }
+    return EOK;
+}
+
+/******************************************************************************/
+static int io_raw_bwrite(struct ext4_blockdev *bdev, const void *buf,
+    uint64_t blk_id, uint32_t blk_cnt)
+{
+    long hipart = blk_id >> (32-9);
+    long lopart = blk_id << 9;
+    long err;
+
+    SetLastError (0);
+    lopart = SetFilePointer (dev_file, lopart, &hipart, FILE_BEGIN);
+
+    if (lopart == -1  &&  NO_ERROR != (err = GetLastError ()))
+    {
+        return EIO;
+    }
+
+    DWORD   n;
+
+    if (!WriteFile (dev_file, buf, blk_cnt * 512, &n, NULL))
+    {
+        err = GetLastError ();
+        return EIO;
+    }
+    return EOK;
+}
+
+/******************************************************************************/
+static int io_raw_close(struct  ext4_blockdev *bdev)
+{
+    CloseHandle(dev_file);
+    return EOK;
+}
+
+
+/******************************************************************************/
+
+struct  ext4_bcache* ext4_io_raw_cache_get(void)
+{
+    return &__cache;
+}
+/******************************************************************************/
+struct  ext4_blockdev* ext4_io_raw_dev_get(void)
+{
+    return &_filedev;
+}
+/******************************************************************************/
+void ext4_io_raw_filename(const char *n)
+{
+    fname = n;
+}
+
+/******************************************************************************/
+#endif
+
--- /dev/null
+++ b/blockdev/io_raw/io_raw.h
@@ -1,0 +1,46 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef IO_RAW_H_
+#define IO_RAW_H_
+
+#include <ext4_config.h>
+#include <ext4_blockdev.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+
+
+/**@brief   IO raw get.*/
+struct  ext4_bcache*   ext4_io_raw_cache_get(void);
+
+/**@brief   IO raw blockdev get.*/
+struct  ext4_blockdev* ext4_io_raw_dev_get(void);
+
+void    ext4_io_raw_filename(const char *n);
+
+#endif /* IO_RAW_H_ */
--- a/demos/generic/main.c
+++ b/demos/generic/main.c
@@ -32,23 +32,26 @@
 #include <unistd.h>
 #include <getopt.h>
 #include <stdbool.h>
+#include <time.h>
 
 #include <ext4_filedev.h>
+#include <io_raw.h>
 #include <ext4.h>
 
+/**@brief   Input stream name.*/
 char input_name[128] = "ext2";
 
 /**@brief	Read-write size*/
-static int rw_szie  = 1024;
+static int rw_szie  = 1024 * 1024;
 
 /**@brief	Read-write size*/
-static int rw_count = 10000;
+static int rw_count = 10;
 
 /**@brief   Directory test count*/
-static int dir_cnt  = 10;
+static int dir_cnt  = 0;
 
 /**@brief   Static or dynamic cache mode*/
-static bool cache_mode = false;
+static bool cache_mode = true;
 
 /**@brief   Cleanup after test.*/
 static bool cleanup_flag = false;
@@ -59,6 +62,9 @@
 /**@brief   Superblock stats.*/
 static bool sbstat = false;
 
+/**@brief   Indicates that input is windows partition.*/
+static bool winpart = false;
+
 /**@brief	File write buffer*/
 static uint8_t	*wr_buff;
 
@@ -75,14 +81,15 @@
 Welcome in ext4 generic demo.									\n\
 Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)	\n\
 Usage:															\n\
-	-i   - input file             (default = ext2)				\n\
-	-rws - single R/W size        (default = 1024)				\n\
-	-rwc - R/W count              (default = 10000) 			\n\
-	-cache  - 0 static, 1 dynamic  (default = 0)                \n\
-    -dirs   - directory test count (default = 10)               \n\
-    -clean  - clean up after test                               \n\
-    -bstat  - block device stats                                \n\
-    -sbstat - superblock stats                                  \n\
+    --i   - input file             (default = ext2)				\n\
+    --rws - single R/W size        (default = 1024)				\n\
+    --rwc - R/W count              (default = 10000) 			\n\
+    --cache  - 0 static, 1 dynamic  (default = 1)                \n\
+    --dirs   - directory test count (default = 0)                \n\
+    --clean  - clean up after test                               \n\
+    --bstat  - block device stats                                \n\
+    --sbstat - superblock stats                                  \n\
+    --wpart  - windows partition mode                            \n\
 \n";
 
 static char* entry_to_str(uint8_t type)
@@ -190,8 +197,6 @@
         printf("bcache->lba[%d]        = %u\n", i, (uint32_t)bc->lba[i]);
     }
 
-
-
     printf("**********************************************\n");
 }
 
@@ -201,6 +206,10 @@
     int       r;
     int       i;
     char path[64];
+    clock_t diff;
+    clock_t stop;
+    clock_t start;
+    start = clock() / (CLOCKS_PER_SEC / 1000);
 
     printf("Directory create: /mp/dir1\n");
     r = ext4_dir_mk("/mp/dir1");
@@ -220,54 +229,238 @@
         }
     }
 
+    stop = clock() / (CLOCKS_PER_SEC / 1000);
+    diff = stop - start;
     dir_ls("/mp/dir1");
+    printf("dir_test time: %d ms\n", (int)diff);
     return true;
 }
 
+
+static bool file_test(void)
+{
+    int r;
+    uint32_t  size;
+    ext4_file f;
+    int i;
+    clock_t start;
+    clock_t stop;
+    clock_t diff;
+    uint32_t kbps;
+    uint64_t size_bytes;
+    /*Add hello world file.*/
+    r = ext4_fopen(&f, "/mp/hello.txt", "wb");
+    r = ext4_fwrite(&f, "Hello World !\n", strlen("Hello World !\n"), 0);
+    r = ext4_fclose(&f);
+
+
+    printf("ext4_fopen: test1\n");
+
+    start = clock() / (CLOCKS_PER_SEC / 1000);
+    r = ext4_fopen(&f, "/mp/test1", "wb");
+    if(r != EOK){
+        printf("ext4_fopen ERROR = %d\n", r);
+        return false;
+    }
+
+    printf("ext4_write: %d * %d ..." , rw_szie, rw_count);
+    for (i = 0; i < rw_count; ++i) {
+
+        memset(wr_buff, i % 10 + '0', rw_szie);
+
+        r = ext4_fwrite(&f, wr_buff, rw_szie, &size);
+
+        if((r != EOK) || (size != rw_szie))
+            break;
+    }
+
+    if(i != rw_count){
+        printf("ERROR: rw_count = %d\n", i);
+        return false;
+    }
+
+    printf("OK\n");
+    stop = clock() / (CLOCKS_PER_SEC / 1000);
+    diff = stop - start;
+    size_bytes = rw_szie * rw_count;
+    size_bytes = (size_bytes * 1000) / 1024;
+    kbps = (size_bytes) / (diff + 1);
+    printf("file_test write time: %d ms\n", (int)diff);
+    printf("file_test write speed: %d KB/s\n", kbps);
+    r = ext4_fclose(&f);
+    printf("ext4_fopen: test1\n");
+
+
+    start = clock() / (CLOCKS_PER_SEC / 1000);
+    r = ext4_fopen(&f, "/mp/test1", "r+");
+    if(r != EOK){
+        printf("ext4_fopen ERROR = %d\n", r);
+        return false;
+    }
+
+    printf("ext4_read: %d * %d ..." , rw_szie, rw_count);
+
+    for (i = 0; i < rw_count; ++i) {
+        memset(wr_buff, i % 10 + '0', rw_szie);
+        r = ext4_fread(&f, rd_buff, rw_szie, &size);
+
+        if((r != EOK) || (size != rw_szie))
+            break;
+
+        if(memcmp(rd_buff, wr_buff, rw_szie)){
+            break;
+        }
+    }
+    if(i != rw_count){
+        printf("ERROR: rw_count = %d\n", i);
+        return false;
+    }
+    printf("OK\n");
+    stop = clock() / (CLOCKS_PER_SEC / 1000);
+    diff = stop - start;
+    size_bytes = rw_szie * rw_count;
+    size_bytes = (size_bytes * 1000) / 1024;
+    kbps = (size_bytes) / (diff + 1);
+    printf("file_test read time: %d ms\n", (int)diff);
+    printf("file_test read speed: %d KB/s\n", kbps);
+    r = ext4_fclose(&f);
+
+    return true;
+
+}
 static void cleanup(void)
 {
+    clock_t start;
+    clock_t stop;
+    clock_t diff;
+
     ext4_fremove("/mp/hello.txt");
+
+    printf("cleanup: remove /mp/test1\n");
+    start = clock() / (CLOCKS_PER_SEC / 1000);
     ext4_fremove("/mp/test1");
+    stop = clock() / (CLOCKS_PER_SEC / 1000);
+    diff = stop - start;
+    printf("cleanup: time: %d ms\n", (int)diff);
+
+
+    printf("cleanup: remove /mp/test1\n");
+    start = clock() / (CLOCKS_PER_SEC / 1000);
     ext4_dir_rm("/mp/dir1");
+    stop = clock() / (CLOCKS_PER_SEC / 1000);
+    diff = stop - start;
+    printf("cleanup: time: %d ms\n", (int)diff);
 }
 
-int main(int argc, char **argv)
+static bool open_filedev(void)
 {
-	int option_index = 0;
-	int	c;
-	int	r;
-	int	i;
-	uint32_t  size;
-	ext4_file f;
+    ext4_filedev_filename(input_name);
+    bd = ext4_filedev_get();
+    bc = ext4_filecache_get();
+    if(!bd || !bc){
+        printf("Block device ERROR\n");
+        return false;
+    }
+    return true;
+}
 
+static bool open_winpartition(void)
+{
+#ifdef WIN32
+    ext4_io_raw_filename(input_name);
+    bd = ext4_io_raw_dev_get();
+    bc = ext4_io_raw_cache_get();
+    if(!bd || !bc){
+        printf("Block device ERROR\n");
+        return false;
+    }
+    return true;
+#else
+    printf("open_winpartition: this mode shouls be used only under windows !\n");
+    return false;
+#endif
+}
+
+static bool mount(void)
+{
+    int r;
+    if(winpart){
+         if(!open_winpartition())
+             return false;
+    }else{
+        if(!open_filedev())
+            return false;
+
+    }
+    wr_buff = malloc(rw_szie);
+    rd_buff = malloc(rw_szie);
+
+    if(!wr_buff || !rd_buff){
+        printf("Read-Write allocation ERROR\n");
+        return EXIT_FAILURE;
+    }
+
+    ext4_dmask_set(EXT4_DEBUG_ALL);
+
+    r = ext4_device_register(bd, cache_mode ? 0 : bc, "ext4_filesim");
+    if(r != EOK){
+        printf("ext4_device_register ERROR = %d\n", r);
+        return false;
+    }
+
+    r = ext4_mount("ext4_filesim", "/mp/");
+    if(r != EOK){
+        printf("ext4_mount ERROR = %d\n", r);
+        return false;
+    }
+
+    return true;
+}
+
+static bool umount(void)
+{
+    int r = ext4_umount("/mp/");
+    if(r != EOK){
+        printf("ext4_umount: FAIL %d", r);
+        return false;
+    }
+    return true;
+}
+
+static bool parse_opt(int argc, char **argv)
+{
+    int option_index = 0;
+    int c;
+
     static struct option long_options[] =
       {
-        {"in",     	required_argument, 0, 'a'},
+        {"in",      required_argument, 0, 'a'},
         {"rws",     required_argument, 0, 'b'},
-        {"rwc",		required_argument, 0, 'c'},
+        {"rwc",     required_argument, 0, 'c'},
         {"cache",   required_argument, 0, 'd'},
         {"dirs",    required_argument, 0, 'e'},
         {"clean",   no_argument,       0, 'f'},
         {"bstat",   no_argument,       0, 'g'},
         {"sbstat",  no_argument,       0, 'h'},
+        {"wpart",   no_argument,       0, 'i'},
         {0, 0, 0, 0}
       };
 
-    while(-1 != (c = getopt_long (argc, argv, "a:b:c:d:e:fgh", long_options, &option_index))) {
+    while(-1 != (c = getopt_long (argc, argv, "a:b:c:d:e:fghi", long_options, &option_index))) {
 
-    	switch(c){
-    		case 'a':
-    			strcpy(input_name, optarg);
-    			break;
-    		case 'b':
-    			rw_szie = atoi(optarg);
-    			break;
-    		case 'c':
-    			rw_count = atoi(optarg);
-    			break;
-    		case 'd':
-    			cache_mode = atoi(optarg);
-    			break;
+        switch(c){
+            case 'a':
+                strcpy(input_name, optarg);
+                break;
+            case 'b':
+                rw_szie = atoi(optarg);
+                break;
+            case 'c':
+                rw_count = atoi(optarg);
+                break;
+            case 'd':
+                cache_mode = atoi(optarg);
+                break;
             case 'e':
                 dir_cnt = atoi(optarg);
                 break;
@@ -280,13 +473,23 @@
             case 'h':
                 sbstat = true;
                 break;
-    		default:
-    			printf(usage);
-    			return EXIT_FAILURE;
+            case 'i':
+                winpart = true;
+                break;
+            default:
+                printf(usage);
+                return false;
 
-    	}
+        }
     }
+    return true;
+}
 
+int main(int argc, char **argv)
+{
+    if(!parse_opt(argc, argv))
+        return EXIT_FAILURE;
+
     printf("Test conditions:\n");
     printf("Imput name: %s\n", input_name);
     printf("RW size: %d\n",  rw_szie);
@@ -293,117 +496,30 @@
     printf("RW count: %d\n", rw_count);
     printf("Cache mode: %s\n", cache_mode ? "dynamic" : "static");
 
+    if(!mount())
+        return EXIT_FAILURE;
 
 
-    ext4_filedev_filename(input_name);
+    cleanup();
 
-    wr_buff = malloc(rw_szie);
-    rd_buff = malloc(rw_szie);
-
-    if(!wr_buff || !rd_buff){
-    	printf("Read-Write allocation ERROR\n");
-    	return EXIT_FAILURE;
-    }
-
-	bd = ext4_filedev_get();
-	bc = ext4_filecache_get();
-
-    if(!bd || !bc){
-    	printf("Block device ERROR\n");
-    	return EXIT_FAILURE;
-    }
-
-	ext4_dmask_set(EXT4_DEBUG_ALL);
-
-	r = ext4_device_register(bd, cache_mode ? 0 : bc, "ext4_filesim");
-	if(r != EOK){
-		printf("ext4_device_register ERROR = %d\n", r);
-		return EXIT_FAILURE;
-	}
-
-	r = ext4_mount("ext4_filesim", "/mp/");
-	if(r != EOK){
-		printf("ext4_mount ERROR = %d\n", r);
-		return EXIT_FAILURE;
-	}
-
-	cleanup();
-
     if(sbstat)
         mp_stats();
 
-
     dir_ls("/mp/");
-	dir_test(dir_cnt);
+    fflush(stdout);
+    if(!dir_test(dir_cnt))
+	    return EXIT_FAILURE;
 
-    /*Add hello world file.*/
-    r = ext4_fopen(&f, "/mp/hello.txt", "wb");
-    r = ext4_fwrite(&f, "Hello World !\n", strlen("Hello World !\n"), 0);
-    r = ext4_fclose(&f);
+    fflush(stdout);
+	if(!file_test())
+	    return EXIT_FAILURE;
 
-
-	printf("ext4_fopen: test1\n");
-
-	r = ext4_fopen(&f, "/mp/test1", "wb");
-	if(r != EOK){
-		printf("ext4_fopen ERROR = %d\n", r);
-		return EXIT_FAILURE;
-	}
-
-	printf("ext4_write: %d * %d ..." , rw_count, rw_szie);
-
-	for (i = 0; i < rw_count; ++i) {
-
-		memset(wr_buff, i % 10 + '0', rw_szie);
-
-		r = ext4_fwrite(&f, wr_buff, rw_szie, &size);
-
-		if((r != EOK) || (size != rw_szie))
-			break;
-	}
-
-	if(i != rw_count){
-		printf("ERROR: rw_count = %d\n", i);
-		return EXIT_FAILURE;
-	}
-
-	printf("OK\n");
-	r = ext4_fclose(&f);
-	printf("ext4_fopen: test1\n");
-
-	r = ext4_fopen(&f, "/mp/test1", "r+");
-	if(r != EOK){
-		printf("ext4_fopen ERROR = %d\n", r);
-		return EXIT_FAILURE;
-	}
-
-	printf("ext4_read: %d * %d ..." , rw_count, rw_szie);
-
-	for (i = 0; i < rw_count; ++i) {
-		memset(wr_buff, i % 10 + '0', rw_szie);
-		r = ext4_fread(&f, rd_buff, rw_szie, &size);
-
-		if((r != EOK) || (size != rw_szie))
-			break;
-
-		if(memcmp(rd_buff, wr_buff, rw_szie)){
-			break;
-		}
-	}
-	if(i != rw_count){
-		printf("ERROR: rw_count = %d\n", i);
-		return EXIT_FAILURE;
-	}
-
-	printf("OK\n");
-	r = ext4_fclose(&f);
-
+	fflush(stdout);
 	dir_ls("/mp/");
 
 	if(sbstat)
 	    mp_stats();
 
-
 	if(cleanup_flag)
 	    cleanup();
 
@@ -410,8 +526,10 @@
     if(bstat)
         block_stats();
 
-	r = ext4_umount("/mp/");
-	printf("Test finish: OK\n");
+    if(!umount())
+        return EXIT_FAILURE;
+
+    printf("Test finish: OK\n");
     return EXIT_SUCCESS;
 
 }
--- a/lwext4/ext4.c
+++ b/lwext4/ext4.c
@@ -793,10 +793,13 @@
     int		 r = EOK;
     uint32_t u;
     uint32_t fblock;
+    uint32_t fblock_start;
+    uint32_t fblock_cnt;
     struct ext4_block b;
     uint8_t	*u8_buf = buf;
     struct ext4_inode_ref ref;
     uint32_t sblock;
+    uint32_t sblock_end;
     uint32_t block_size;
 
     ext4_assert(f && f->mp);
@@ -824,9 +827,8 @@
 
     block_size = ext4_sb_get_block_size(&f->mp->fs.sb);
     size = size > (f->fsize - f->fpos) ? (f->fsize - f->fpos) : size;
-
     sblock 	= (f->fpos) / block_size;
-
+    sblock_end = (f->fpos + size) / block_size;
     u = (f->fpos) % block_size;
 
 
@@ -858,25 +860,39 @@
         sblock++;
     }
 
+    fblock_start = 0;
+    fblock_cnt = 0;
     while(size >= block_size){
+        while(sblock < sblock_end){
+            r = ext4_fs_get_inode_data_block_index(&ref, sblock, &fblock);
+            if(r != EOK)
+                goto Finish;
 
-        r = ext4_fs_get_inode_data_block_index(&ref, sblock, &fblock);
-        if(r != EOK)
-            goto Finish;
+            sblock++;
 
-        r = ext4_block_get_direct(f->mp->fs.bdev, u8_buf, fblock);
+            if(!fblock_start){
+                fblock_start = fblock;
+            }
+
+            if((fblock_start + fblock_cnt) != fblock)
+                break;
+
+            fblock_cnt++;
+        }
+
+        r = ext4_blocks_get_direct(f->mp->fs.bdev, u8_buf, fblock_start, fblock_cnt);
         if(r != EOK)
             goto Finish;
 
+        size    -= block_size * fblock_cnt;
+        u8_buf  += block_size * fblock_cnt;
+        f->fpos += block_size * fblock_cnt;
 
-        u8_buf  += block_size;
-        size    -= block_size;
-        f->fpos += block_size;
-
         if(rcnt)
-            *rcnt += block_size;
+            *rcnt += block_size * fblock_cnt;
 
-        sblock++;
+        fblock_start = fblock;
+        fblock_cnt = 1;
     }
 
     if(size){
@@ -915,8 +931,11 @@
     uint8_t	*u8_buf = buf;
     struct ext4_inode_ref ref;
     uint32_t sblock;
+    uint32_t sblock_end;
     uint32_t file_blocks;
     uint32_t block_size;
+    uint32_t fblock_start;
+    uint32_t fblock_cnt;
 
     ext4_assert(f && f->mp);
 
@@ -942,6 +961,8 @@
 
     block_size = ext4_sb_get_block_size(&f->mp->fs.sb);
 
+    sblock_end = (f->fpos + size) > f->fsize ? (f->fpos + size) : f->fsize;
+    sblock_end /= block_size;
     file_blocks = (f->fsize / block_size);
 
     if(f->fsize % block_size)
@@ -986,31 +1007,47 @@
     if(r != EOK)
         goto Finish;
 
+    fblock_start = 0;
+    fblock_cnt = 0;
     while(size >= block_size){
 
-        if(sblock < file_blocks){
-            r = ext4_fs_get_inode_data_block_index(&ref, sblock, &fblock);
-            if(r != EOK)
+        while(sblock < sblock_end){
+            if(sblock < file_blocks){
+                r = ext4_fs_get_inode_data_block_index(&ref, sblock, &fblock);
+                if(r != EOK)
+                    break;
+            }
+            else {
+                r = ext4_fs_append_inode_block(&ref, &fblock, &sblock);
+                if(r != EOK)
+                    break;
+            }
+
+            sblock++;
+
+            if(!fblock_start){
+                fblock_start = fblock;
+            }
+
+            if((fblock_start + fblock_cnt) != fblock)
                 break;
+
+            fblock_cnt++;
         }
-        else {
-            r = ext4_fs_append_inode_block(&ref, &fblock, &sblock);
-            if(r != EOK)
-                break;
-        }
 
-        r = ext4_block_set_direct(f->mp->fs.bdev, u8_buf, fblock);
+        r = ext4_blocks_set_direct(f->mp->fs.bdev, u8_buf, fblock_start, fblock_cnt);
         if(r != EOK)
             break;
 
-        u8_buf  += block_size;
-        size    -= block_size;
-        f->fpos += block_size;
+        size    -= block_size * fblock_cnt;
+        u8_buf  += block_size * fblock_cnt;
+        f->fpos += block_size * fblock_cnt;
 
         if(wcnt)
-            *wcnt += block_size;
+            *wcnt += block_size * fblock_cnt;
 
-        sblock++;
+        fblock_start = fblock;
+        fblock_cnt = 1;
     }
 
     /*Stop delay cache flush mode*/
--- a/lwext4/ext4_blockdev.c
+++ b/lwext4/ext4_blockdev.c
@@ -53,7 +53,7 @@
 
     /*Low level block init*/
     rc = bdev->open(bdev);
-    if(EOK != rc)
+    if(rc != EOK)
         return rc;
 
     bdev->flags |= EXT4_BDEV_INITIALIZED;
@@ -120,9 +120,9 @@
                 continue;
 
             /*Buffer free was delayed and have no reference. Flush it.*/
-            r = ext4_block_set_direct(bdev,
+            r = ext4_blocks_set_direct(bdev,
                     bdev->bc->data + bdev->bc->itemsize * i,
-                    bdev->bc->lba[i]);
+                    bdev->bc->lba[i], 1);
             if(r != EOK)
                 return r;
 
@@ -207,8 +207,8 @@
     return EOK;
 }
 
-int ext4_block_get_direct(struct	ext4_blockdev *bdev, void *buf,
-    uint64_t lba)
+int ext4_blocks_get_direct(struct	ext4_blockdev *bdev, void *buf,
+    uint64_t lba, uint32_t cnt)
 {
     uint64_t pba;
     uint32_t pb_cnt;
@@ -220,13 +220,13 @@
 
     bdev->bread_ctr++;
 
-    return bdev->bread(bdev, buf, pba, pb_cnt);
+    return bdev->bread(bdev, buf, pba, pb_cnt * cnt);
 }
 
 
 
-int ext4_block_set_direct(struct	ext4_blockdev *bdev, const void *buf,
-    uint64_t lba)
+int ext4_blocks_set_direct(struct	ext4_blockdev *bdev, const void *buf,
+    uint64_t lba, uint32_t cnt)
 {
     uint64_t pba;
     uint32_t pb_cnt;
@@ -238,7 +238,7 @@
 
     bdev->bwrite_ctr++;
 
-    return bdev->bwrite(bdev, buf, pba, pb_cnt);
+    return bdev->bwrite(bdev, buf, pba, pb_cnt * cnt);
 }
 
 
@@ -424,9 +424,9 @@
                 continue;
 
             /*Buffer free was delayed and have no reference. Flush it.*/
-            r = ext4_block_set_direct(bdev,
+            r = ext4_blocks_set_direct(bdev,
                     bdev->bc->data + bdev->bc->itemsize * i,
-                    bdev->bc->lba[i]);
+                    bdev->bc->lba[i], 1);
             if(r != EOK)
                 return r;
 
--- a/lwext4/ext4_blockdev.h
+++ b/lwext4/ext4_blockdev.h
@@ -164,8 +164,8 @@
  * @param	buf output buffer
  * @param	lba logical block adderss
  * @return 	standard error code*/
-int ext4_block_get_direct(struct	ext4_blockdev *bdev, void *buf,
-    uint64_t lba);
+int ext4_blocks_get_direct(struct   ext4_blockdev *bdev, void *buf,
+    uint64_t lba, uint32_t cnt);
 
 
 /**@brief	Block write procedure (without cache)
@@ -173,8 +173,8 @@
  * @param	buf output buffer
  * @param	lba logical block address
  * @return 	standard error code*/
-int ext4_block_set_direct(struct	ext4_blockdev *bdev, const void *buf,
-    uint64_t lba);
+int ext4_blocks_set_direct(struct	ext4_blockdev *bdev, const void *buf,
+    uint64_t lba, uint32_t cnt);
 
 /**@brief	Write to block device (by direct adress).
  * @param	bdev block device descriptor
--- a/lwext4/ext4_fs.c
+++ b/lwext4/ext4_fs.c
@@ -267,7 +267,7 @@
         return EOK;
     }
     ext4_dprintf(EXT4_DEBUG_FS,
-        "\nSblock rev_level: \n%d\n", ext4_get32(&fs->sb, rev_level) );
+        "\nSblock rev_level: \n%d\n", (int)ext4_get32(&fs->sb, rev_level));
 
     ext4_dprintf(EXT4_DEBUG_FS,
         "\nSblock minor_rev_level: \n%d\n",