New targets for:
[lwext4.git] / demos / generic / main.c
1 /*\r
2  * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)\r
3  * All rights reserved.\r
4  *\r
5  * Redistribution and use in source and binary forms, with or without\r
6  * modification, are permitted provided that the following conditions\r
7  * are met:\r
8  *\r
9  * - Redistributions of source code must retain the above copyright\r
10  *   notice, this list of conditions and the following disclaimer.\r
11  * - Redistributions in binary form must reproduce the above copyright\r
12  *   notice, this list of conditions and the following disclaimer in the\r
13  *   documentation and/or other materials provided with the distribution.\r
14  * - The name of the author may not be used to endorse or promote products\r
15  *   derived from this software without specific prior written permission.\r
16  *\r
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\r
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\r
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
27  */\r
28 \r
29 #include <stdio.h>\r
30 #include <stdlib.h>\r
31 #include <string.h>\r
32 #include <unistd.h>\r
33 #include <getopt.h>\r
34 #include <stdbool.h>\r
35 #include <time.h>\r
36 #include <unistd.h>\r
37 #include <sys/time.h>\r
38 \r
39 #include <ext4_filedev.h>\r
40 #include <io_raw.h>\r
41 #include <ext4.h>\r
42 \r
43 #ifdef WIN32\r
44 #include <windows.h>\r
45 #endif\r
46 \r
47 /**@brief   Input stream name.*/\r
48 char input_name[128] = "ext2";\r
49 \r
50 /**@brief   Read-write size*/\r
51 static int rw_szie  = 1024 * 1024;\r
52 \r
53 /**@brief   Read-write size*/\r
54 static int rw_count = 10;\r
55 \r
56 /**@brief   Directory test count*/\r
57 static int dir_cnt  = 0;\r
58 \r
59 /**@brief   Static or dynamic cache mode*/\r
60 static bool cache_mode = true;\r
61 \r
62 /**@brief   Cleanup after test.*/\r
63 static bool cleanup_flag = false;\r
64 \r
65 /**@brief   Block device stats.*/\r
66 static bool bstat = false;\r
67 \r
68 /**@brief   Superblock stats.*/\r
69 static bool sbstat = false;\r
70 \r
71 /**@brief   Indicates that input is windows partition.*/\r
72 static bool winpart = false;\r
73 \r
74 /**@brief   File write buffer*/\r
75 static uint8_t *wr_buff;\r
76 \r
77 /**@brief   File read buffer.*/\r
78 static uint8_t *rd_buff;\r
79 \r
80 /**@brief   Block device handle.*/\r
81 static struct ext4_blockdev *bd;\r
82 \r
83 /**@brief   Static cache instance*/\r
84 EXT4_BCACHE_STATIC_INSTANCE(_lwext4_cache, CONFIG_BLOCK_DEV_CACHE_SIZE, 1024);\r
85 \r
86 /**@brief   Block cache handle.*/\r
87 static struct ext4_bcache   *bc = &_lwext4_cache;\r
88 \r
89 static const char *usage = "                                    \n\\r
90 Welcome in ext4 generic demo.                                   \n\\r
91 Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)  \n\\r
92 Usage:                                                          \n\\r
93     --i   - input file              (default = ext2)            \n\\r
94     --rws - single R/W size         (default = 1024 * 1024)     \n\\r
95     --rwc - R/W count               (default = 10)              \n\\r
96     --cache  - 0 static, 1 dynamic  (default = 1)               \n\\r
97     --dirs   - directory test count (default = 0)               \n\\r
98     --clean  - clean up after test                              \n\\r
99     --bstat  - block device stats                               \n\\r
100     --sbstat - superblock stats                                 \n\\r
101     --wpart  - windows partition mode                           \n\\r
102 \n";\r
103 \r
104 \r
105 \r
106 \r
107 \r
108 static char* entry_to_str(uint8_t type)\r
109 {\r
110     switch(type){\r
111     case EXT4_DIRENTRY_UNKNOWN:\r
112         return "[UNK] ";\r
113     case EXT4_DIRENTRY_REG_FILE:\r
114         return "[FIL] ";\r
115     case EXT4_DIRENTRY_DIR:\r
116         return "[DIR] ";\r
117     case EXT4_DIRENTRY_CHRDEV:\r
118         return "[CHA] ";\r
119     case EXT4_DIRENTRY_BLKDEV:\r
120         return "[BLK] ";\r
121     case EXT4_DIRENTRY_FIFO:\r
122         return "[FIF] ";\r
123     case EXT4_DIRENTRY_SOCK:\r
124         return "[SOC] ";\r
125     case EXT4_DIRENTRY_SYMLINK:\r
126         return "[SYM] ";\r
127     default:\r
128         break;\r
129     }\r
130     return "[???]";\r
131 }\r
132 \r
133 static void dir_ls(const char *path)\r
134 {\r
135     int j = 0;\r
136     char sss[255];\r
137     ext4_dir d;\r
138     ext4_direntry *de;\r
139 \r
140     printf("**********************************************\n");\r
141 \r
142     ext4_dir_open(&d, path);\r
143     de = ext4_dir_entry_get(&d, j++);\r
144     printf("ls %s\n", path);\r
145 \r
146     while(de){\r
147         memcpy(sss, de->name, de->name_length);\r
148         sss[de->name_length] = 0;\r
149         printf("%s", entry_to_str(de->inode_type));\r
150         printf("%s", sss);\r
151         printf("\n");\r
152         de = ext4_dir_entry_get(&d, j++);\r
153     }\r
154     printf("**********************************************\n");\r
155     ext4_dir_close(&d);\r
156 }\r
157 \r
158 static void mp_stats(void)\r
159 {\r
160     struct ext4_mount_stats stats;\r
161     ext4_mount_point_stats("/mp/", &stats);\r
162 \r
163     printf("**********************************************\n");\r
164     printf("ext4_mount_point_stats\n");\r
165     printf("inodes_count        = %u\n", stats.inodes_count);\r
166     printf("free_inodes_count   = %u\n", stats.free_inodes_count);\r
167     printf("blocks_count        = %u\n", (uint32_t)stats.blocks_count);\r
168     printf("free_blocks_count   = %u\n", (uint32_t)stats.free_blocks_count);\r
169     printf("block_size          = %u\n", stats.block_size);\r
170     printf("block_group_count   = %u\n", stats.block_group_count);\r
171     printf("blocks_per_group    = %u\n", stats.blocks_per_group);\r
172     printf("inodes_per_group    = %u\n", stats.inodes_per_group);\r
173     printf("volume_name         = %s\n", stats.volume_name);\r
174 \r
175     printf("**********************************************\n");\r
176 \r
177 }\r
178 \r
179 static void block_stats(void)\r
180 {\r
181     uint32_t i;\r
182 \r
183     printf("**********************************************\n");\r
184     printf("ext4 blockdev stats\n");\r
185     printf("bdev->bread_ctr          = %u\n", bd->bread_ctr);\r
186     printf("bdev->bwrite_ctr         = %u\n", bd->bwrite_ctr);\r
187 \r
188 \r
189     printf("bcache->ref_blocks       = %u\n", bc->ref_blocks);\r
190     printf("bcache->max_ref_blocks   = %u\n", bc->max_ref_blocks);\r
191     printf("bcache->lru_ctr          = %u\n", bc->lru_ctr);\r
192 \r
193     printf("\n");\r
194     for (i = 0; i < bc->cnt; ++i) {\r
195         printf("bcache->refctr[%d]     = %u\n", i, bc->refctr[i]);\r
196     }\r
197 \r
198     printf("\n");\r
199     for (i = 0; i < bc->cnt; ++i) {\r
200         printf("bcache->lru_id[%d]     = %u\n", i, bc->lru_id[i]);\r
201     }\r
202 \r
203     printf("\n");\r
204     for (i = 0; i < bc->cnt; ++i) {\r
205         printf("bcache->free_delay[%d] = %d\n", i, bc->free_delay[i]);\r
206     }\r
207 \r
208     printf("\n");\r
209     for (i = 0; i < bc->cnt; ++i) {\r
210         printf("bcache->lba[%d]        = %u\n", i, (uint32_t)bc->lba[i]);\r
211     }\r
212 \r
213     printf("**********************************************\n");\r
214 }\r
215 \r
216 static clock_t get_ms(void)\r
217 {\r
218     struct timeval t;\r
219     gettimeofday(&t, NULL);\r
220     return (t.tv_sec * 1000) + (t.tv_usec / 1000);\r
221 }\r
222 \r
223 static bool dir_test(int len)\r
224 {\r
225     ext4_file f;\r
226     int       r;\r
227     int       i;\r
228     char path[64];\r
229     clock_t diff;\r
230     clock_t stop;\r
231     clock_t start;\r
232     start = get_ms();\r
233 \r
234     printf("Directory create: /mp/dir1\n");\r
235     r = ext4_dir_mk("/mp/dir1");\r
236     if(r != EOK){\r
237         printf("Unable to create directory: /mp/dir1\n");\r
238         return false;\r
239     }\r
240 \r
241 \r
242     ext4_cache_write_back("/mp/", 1);\r
243     printf("Add files to: /mp/dir1\n");\r
244     for (i = 0; i < len; ++i) {\r
245         sprintf(path, "/mp/dir1/f%d", i);\r
246         r = ext4_fopen(&f, path, "wb");\r
247         if(r != EOK){\r
248             printf("Unable to create file in directory: /mp/dir1\n");\r
249             return false;\r
250         }\r
251     }\r
252     ext4_cache_write_back("/mp/", 0);\r
253 \r
254     stop =  get_ms();\r
255     diff = stop - start;\r
256     dir_ls("/mp/dir1");\r
257     printf("dir_test time: %d ms\n", (int)diff);\r
258     return true;\r
259 }\r
260 \r
261 \r
262 static bool file_test(void)\r
263 {\r
264     int r;\r
265     uint32_t  size;\r
266     ext4_file f;\r
267     int i;\r
268     clock_t start;\r
269     clock_t stop;\r
270     clock_t diff;\r
271     uint32_t kbps;\r
272     uint64_t size_bytes;\r
273     /*Add hello world file.*/\r
274     r = ext4_fopen(&f, "/mp/hello.txt", "wb");\r
275     r = ext4_fwrite(&f, "Hello World !\n", strlen("Hello World !\n"), 0);\r
276     r = ext4_fclose(&f);\r
277 \r
278 \r
279     printf("ext4_fopen: test1\n");\r
280 \r
281     start = get_ms();\r
282     r = ext4_fopen(&f, "/mp/test1", "wb");\r
283     if(r != EOK){\r
284         printf("ext4_fopen ERROR = %d\n", r);\r
285         return false;\r
286     }\r
287 \r
288     printf("ext4_write: %d * %d ..." , rw_szie, rw_count);\r
289     for (i = 0; i < rw_count; ++i) {\r
290 \r
291         memset(wr_buff, i % 10 + '0', rw_szie);\r
292 \r
293         r = ext4_fwrite(&f, wr_buff, rw_szie, &size);\r
294 \r
295         if((r != EOK) || (size != rw_szie))\r
296             break;\r
297     }\r
298 \r
299     if(i != rw_count){\r
300         printf("ERROR: rw_count = %d\n", i);\r
301         return false;\r
302     }\r
303 \r
304     printf("OK\n");\r
305     stop = get_ms();\r
306     diff = stop - start;\r
307     size_bytes = rw_szie * rw_count;\r
308     size_bytes = (size_bytes * 1000) / 1024;\r
309     kbps = (size_bytes) / (diff + 1);\r
310     printf("file_test write time: %d ms\n", (int)diff);\r
311     printf("file_test write speed: %d KB/s\n", kbps);\r
312     r = ext4_fclose(&f);\r
313     printf("ext4_fopen: test1\n");\r
314 \r
315 \r
316     start = get_ms();\r
317     r = ext4_fopen(&f, "/mp/test1", "r+");\r
318     if(r != EOK){\r
319         printf("ext4_fopen ERROR = %d\n", r);\r
320         return false;\r
321     }\r
322 \r
323     printf("ext4_read: %d * %d ..." , rw_szie, rw_count);\r
324 \r
325     for (i = 0; i < rw_count; ++i) {\r
326         memset(wr_buff, i % 10 + '0', rw_szie);\r
327         r = ext4_fread(&f, rd_buff, rw_szie, &size);\r
328 \r
329         if((r != EOK) || (size != rw_szie))\r
330             break;\r
331 \r
332         if(memcmp(rd_buff, wr_buff, rw_szie)){\r
333             break;\r
334         }\r
335     }\r
336     if(i != rw_count){\r
337         printf("ERROR: rw_count = %d\n", i);\r
338         return false;\r
339     }\r
340     printf("OK\n");\r
341     stop = get_ms();\r
342     diff = stop - start;\r
343     size_bytes = rw_szie * rw_count;\r
344     size_bytes = (size_bytes * 1000) / 1024;\r
345     kbps = (size_bytes) / (diff + 1);\r
346     printf("file_test read time: %d ms\n", (int)diff);\r
347     printf("file_test read speed: %d KB/s\n", kbps);\r
348     r = ext4_fclose(&f);\r
349 \r
350     return true;\r
351 \r
352 }\r
353 static void cleanup(void)\r
354 {\r
355     clock_t start;\r
356     clock_t stop;\r
357     clock_t diff;\r
358 \r
359     ext4_fremove("/mp/hello.txt");\r
360 \r
361     printf("cleanup: remove /mp/test1\n");\r
362     start = get_ms();\r
363     ext4_fremove("/mp/test1");\r
364     stop = get_ms();\r
365     diff = stop - start;\r
366     printf("cleanup: time: %d ms\n", (int)diff);\r
367 \r
368 \r
369     printf("cleanup: remove /mp/dir1\n");\r
370     start =get_ms();\r
371     ext4_dir_rm("/mp/dir1");\r
372     stop = get_ms();\r
373     diff = stop - start;\r
374     printf("cleanup: time: %d ms\n", (int)diff);\r
375 }\r
376 \r
377 static bool open_filedev(void)\r
378 {\r
379     ext4_filedev_filename(input_name);\r
380     bd = ext4_filedev_get();\r
381     if(!bd){\r
382         printf("Block device ERROR\n");\r
383         return false;\r
384     }\r
385     return true;\r
386 }\r
387 \r
388 static bool open_winpartition(void)\r
389 {\r
390 #ifdef WIN32\r
391     ext4_io_raw_filename(input_name);\r
392     bd = ext4_io_raw_dev_get();\r
393     if(!bd){\r
394         printf("Block device ERROR\n");\r
395         return false;\r
396     }\r
397     return true;\r
398 #else\r
399     printf("open_winpartition: this mode should be used only under windows !\n");\r
400     return false;\r
401 #endif\r
402 }\r
403 \r
404 static bool mount(void)\r
405 {\r
406     int r;\r
407     if(winpart){\r
408         if(!open_winpartition())\r
409             return false;\r
410     }else{\r
411         if(!open_filedev())\r
412             return false;\r
413 \r
414     }\r
415     wr_buff = malloc(rw_szie);\r
416     rd_buff = malloc(rw_szie);\r
417 \r
418     if(!wr_buff || !rd_buff){\r
419         printf("Read-Write allocation ERROR\n");\r
420         return EXIT_FAILURE;\r
421     }\r
422 \r
423     ext4_dmask_set(EXT4_DEBUG_ALL);\r
424 \r
425     r = ext4_device_register(bd, cache_mode ? 0 : bc, "ext4_filesim");\r
426     if(r != EOK){\r
427         printf("ext4_device_register ERROR = %d\n", r);\r
428         return false;\r
429     }\r
430 \r
431     r = ext4_mount("ext4_filesim", "/mp/");\r
432     if(r != EOK){\r
433         printf("ext4_mount ERROR = %d\n", r);\r
434         return false;\r
435     }\r
436 \r
437     return true;\r
438 }\r
439 \r
440 static bool umount(void)\r
441 {\r
442     int r = ext4_umount("/mp/");\r
443     if(r != EOK){\r
444         printf("ext4_umount: FAIL %d", r);\r
445         return false;\r
446     }\r
447     return true;\r
448 }\r
449 \r
450 static bool parse_opt(int argc, char **argv)\r
451 {\r
452     int option_index = 0;\r
453     int c;\r
454 \r
455     static struct option long_options[] =\r
456     {\r
457             {"in",      required_argument, 0, 'a'},\r
458             {"rws",     required_argument, 0, 'b'},\r
459             {"rwc",     required_argument, 0, 'c'},\r
460             {"cache",   required_argument, 0, 'd'},\r
461             {"dirs",    required_argument, 0, 'e'},\r
462             {"clean",   no_argument,       0, 'f'},\r
463             {"bstat",   no_argument,       0, 'g'},\r
464             {"sbstat",  no_argument,       0, 'h'},\r
465             {"wpart",   no_argument,       0, 'i'},\r
466             {0, 0, 0, 0}\r
467     };\r
468 \r
469     while(-1 != (c = getopt_long (argc, argv, "a:b:c:d:e:fghi", long_options, &option_index))) {\r
470 \r
471         switch(c){\r
472         case 'a':\r
473             strcpy(input_name, optarg);\r
474             break;\r
475         case 'b':\r
476             rw_szie = atoi(optarg);\r
477             break;\r
478         case 'c':\r
479             rw_count = atoi(optarg);\r
480             break;\r
481         case 'd':\r
482             cache_mode = atoi(optarg);\r
483             break;\r
484         case 'e':\r
485             dir_cnt = atoi(optarg);\r
486             break;\r
487         case 'f':\r
488             cleanup_flag = true;\r
489             break;\r
490         case 'g':\r
491             bstat = true;\r
492             break;\r
493         case 'h':\r
494             sbstat = true;\r
495             break;\r
496         case 'i':\r
497             winpart = true;\r
498             break;\r
499         default:\r
500             printf("%s", usage);\r
501             return false;\r
502 \r
503         }\r
504     }\r
505     return true;\r
506 }\r
507 \r
508 int main(int argc, char **argv)\r
509 {\r
510     if(!parse_opt(argc, argv))\r
511         return EXIT_FAILURE;\r
512 \r
513     printf("Test conditions:\n");\r
514     printf("Imput name: %s\n", input_name);\r
515     printf("RW size: %d\n",  rw_szie);\r
516     printf("RW count: %d\n", rw_count);\r
517     printf("Cache mode: %s\n", cache_mode ? "dynamic" : "static");\r
518 \r
519     if(!mount())\r
520         return EXIT_FAILURE;\r
521 \r
522 \r
523     cleanup();\r
524 \r
525     if(sbstat)\r
526         mp_stats();\r
527 \r
528     dir_ls("/mp/");\r
529     fflush(stdout);\r
530     if(!dir_test(dir_cnt))\r
531         return EXIT_FAILURE;\r
532 \r
533     fflush(stdout);\r
534     if(!file_test())\r
535         return EXIT_FAILURE;\r
536 \r
537     fflush(stdout);\r
538     dir_ls("/mp/");\r
539 \r
540     if(sbstat)\r
541         mp_stats();\r
542 \r
543     if(cleanup_flag)\r
544         cleanup();\r
545 \r
546     if(bstat)\r
547         block_stats();\r
548 \r
549     if(!umount())\r
550         return EXIT_FAILURE;\r
551 \r
552     printf("Test finish: OK\n");\r
553     return EXIT_SUCCESS;\r
554 \r
555 }\r