BUGFIX:
[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 \r
37 #include <ext4_filedev.h>\r
38 #include <io_raw.h>\r
39 #include <ext4.h>\r
40 \r
41 /**@brief   Input stream name.*/\r
42 char input_name[128] = "ext2";\r
43 \r
44 /**@brief       Read-write size*/\r
45 static int rw_szie  = 1024 * 1024;\r
46 \r
47 /**@brief       Read-write size*/\r
48 static int rw_count = 10;\r
49 \r
50 /**@brief   Directory test count*/\r
51 static int dir_cnt  = 0;\r
52 \r
53 /**@brief   Static or dynamic cache mode*/\r
54 static bool cache_mode = true;\r
55 \r
56 /**@brief   Cleanup after test.*/\r
57 static bool cleanup_flag = false;\r
58 \r
59 /**@brief   Block device stats.*/\r
60 static bool bstat = false;\r
61 \r
62 /**@brief   Superblock stats.*/\r
63 static bool sbstat = false;\r
64 \r
65 /**@brief   Indicates that input is windows partition.*/\r
66 static bool winpart = false;\r
67 \r
68 /**@brief       File write buffer*/\r
69 static uint8_t  *wr_buff;\r
70 \r
71 /**@brief       File read buffer.*/\r
72 static uint8_t  *rd_buff;\r
73 \r
74 /**@brief       Block device handle.*/\r
75 static struct ext4_blockdev *bd;\r
76 \r
77 /**@brief       Block cache handle.*/\r
78 static struct ext4_bcache   *bc;\r
79 \r
80 static const char *usage = "                                                                    \n\\r
81 Welcome in ext4 generic demo.                                                                   \n\\r
82 Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)  \n\\r
83 Usage:                                                                                                                  \n\\r
84     --i   - input file             (default = ext2)                             \n\\r
85     --rws - single R/W size        (default = 1024)                             \n\\r
86     --rwc - R/W count              (default = 10000)                    \n\\r
87     --cache  - 0 static, 1 dynamic  (default = 1)                \n\\r
88     --dirs   - directory test count (default = 0)                \n\\r
89     --clean  - clean up after test                               \n\\r
90     --bstat  - block device stats                                \n\\r
91     --sbstat - superblock stats                                  \n\\r
92     --wpart  - windows partition mode                            \n\\r
93 \n";\r
94 \r
95 static char* entry_to_str(uint8_t type)\r
96 {\r
97         switch(type){\r
98         case EXT4_DIRENTRY_UNKNOWN:\r
99                 return "[UNK] ";\r
100         case EXT4_DIRENTRY_REG_FILE:\r
101                 return "[FIL] ";\r
102         case EXT4_DIRENTRY_DIR:\r
103                 return "[DIR] ";\r
104         case EXT4_DIRENTRY_CHRDEV:\r
105                 return "[CHA] ";\r
106         case EXT4_DIRENTRY_BLKDEV:\r
107                 return "[BLK] ";\r
108         case EXT4_DIRENTRY_FIFO:\r
109                 return "[FIF] ";\r
110         case EXT4_DIRENTRY_SOCK:\r
111                 return "[SOC] ";\r
112         case EXT4_DIRENTRY_SYMLINK:\r
113                 return "[SYM] ";\r
114         default:\r
115                 break;\r
116         }\r
117         return "[???]";\r
118 }\r
119 \r
120 static void dir_ls(const char *path)\r
121 {\r
122         int j = 0;\r
123         char sss[255];\r
124         ext4_dir d;\r
125         ext4_direntry *de;\r
126 \r
127         printf("**********************************************\n");\r
128 \r
129         ext4_dir_open(&d, path);\r
130         de = ext4_dir_entry_get(&d, j++);\r
131         printf("ls %s\n", path);\r
132 \r
133         while(de){\r
134                 memcpy(sss, de->name, de->name_length);\r
135                 sss[de->name_length] = 0;\r
136                 printf("%s", entry_to_str(de->inode_type));\r
137                 printf("%s", sss);\r
138                 printf("\n");\r
139                 de = ext4_dir_entry_get(&d, j++);\r
140         }\r
141         printf("**********************************************\n");\r
142         ext4_dir_close(&d);\r
143 }\r
144 \r
145 static void mp_stats(void)\r
146 {\r
147     struct ext4_mount_stats stats;\r
148     ext4_mount_point_stats("/mp/", &stats);\r
149 \r
150     printf("**********************************************\n");\r
151     printf("ext4_mount_point_stats\n");\r
152     printf("inodes_count        = %u\n", stats.inodes_count);\r
153     printf("free_inodes_count   = %u\n", stats.free_inodes_count);\r
154     printf("blocks_count        = %u\n", (uint32_t)stats.blocks_count);\r
155     printf("free_blocks_count   = %u\n", (uint32_t)stats.free_blocks_count);\r
156     printf("block_size          = %u\n", stats.block_size);\r
157     printf("block_group_count   = %u\n", stats.block_group_count);\r
158     printf("blocks_per_group    = %u\n", stats.blocks_per_group);\r
159     printf("inodes_per_group    = %u\n", stats.inodes_per_group);\r
160     printf("volume_name         = %s\n", stats.volume_name);\r
161 \r
162     printf("**********************************************\n");\r
163 \r
164 }\r
165 \r
166 static void block_stats(void)\r
167 {\r
168     uint32_t i;\r
169 \r
170     printf("**********************************************\n");\r
171     printf("ext4 blockdev stats\n");\r
172     printf("bdev->bread_ctr          = %u\n", bd->bread_ctr);\r
173     printf("bdev->bwrite_ctr         = %u\n", bd->bwrite_ctr);\r
174 \r
175 \r
176     printf("bcache->ref_blocks       = %u\n", bc->ref_blocks);\r
177     printf("bcache->max_ref_blocks   = %u\n", bc->max_ref_blocks);\r
178     printf("bcache->lru_ctr          = %u\n", bc->lru_ctr);\r
179 \r
180     printf("\n");\r
181     for (i = 0; i < bc->cnt; ++i) {\r
182         printf("bcache->refctr[%d]     = %u\n", i, bc->refctr[i]);\r
183     }\r
184 \r
185     printf("\n");\r
186     for (i = 0; i < bc->cnt; ++i) {\r
187         printf("bcache->lru_id[%d]     = %u\n", i, bc->lru_id[i]);\r
188     }\r
189 \r
190     printf("\n");\r
191     for (i = 0; i < bc->cnt; ++i) {\r
192         printf("bcache->free_delay[%d] = %d\n", i, bc->free_delay[i]);\r
193     }\r
194 \r
195     printf("\n");\r
196     for (i = 0; i < bc->cnt; ++i) {\r
197         printf("bcache->lba[%d]        = %u\n", i, (uint32_t)bc->lba[i]);\r
198     }\r
199 \r
200     printf("**********************************************\n");\r
201 }\r
202 \r
203 static bool dir_test(int len)\r
204 {\r
205     ext4_file f;\r
206     int       r;\r
207     int       i;\r
208     char path[64];\r
209     clock_t diff;\r
210     clock_t stop;\r
211     clock_t start;\r
212     start = clock() / (CLOCKS_PER_SEC / 1000);\r
213 \r
214     printf("Directory create: /mp/dir1\n");\r
215     r = ext4_dir_mk("/mp/dir1");\r
216     if(r != EOK){\r
217         printf("Unable to create directory: /mp/dir1\n");\r
218         return false;\r
219     }\r
220 \r
221 \r
222     printf("Add files to: /mp/dir1\n");\r
223     for (i = 0; i < len; ++i) {\r
224         sprintf(path, "/mp/dir1/f%d", i);\r
225         r = ext4_fopen(&f, path, "wb");\r
226         if(r != EOK){\r
227             printf("Unable to create file in directory: /mp/dir1\n");\r
228             return false;\r
229         }\r
230     }\r
231 \r
232     stop = clock() / (CLOCKS_PER_SEC / 1000);\r
233     diff = stop - start;\r
234     dir_ls("/mp/dir1");\r
235     printf("dir_test time: %d ms\n", (int)diff);\r
236     return true;\r
237 }\r
238 \r
239 \r
240 static bool file_test(void)\r
241 {\r
242     int r;\r
243     uint32_t  size;\r
244     ext4_file f;\r
245     int i;\r
246     clock_t start;\r
247     clock_t stop;\r
248     clock_t diff;\r
249     uint32_t kbps;\r
250     uint64_t size_bytes;\r
251     /*Add hello world file.*/\r
252     r = ext4_fopen(&f, "/mp/hello.txt", "wb");\r
253     r = ext4_fwrite(&f, "Hello World !\n", strlen("Hello World !\n"), 0);\r
254     r = ext4_fclose(&f);\r
255 \r
256 \r
257     printf("ext4_fopen: test1\n");\r
258 \r
259     start = clock() / (CLOCKS_PER_SEC / 1000);\r
260     r = ext4_fopen(&f, "/mp/test1", "wb");\r
261     if(r != EOK){\r
262         printf("ext4_fopen ERROR = %d\n", r);\r
263         return false;\r
264     }\r
265 \r
266     printf("ext4_write: %d * %d ..." , rw_szie, rw_count);\r
267     for (i = 0; i < rw_count; ++i) {\r
268 \r
269         memset(wr_buff, i % 10 + '0', rw_szie);\r
270 \r
271         r = ext4_fwrite(&f, wr_buff, rw_szie, &size);\r
272 \r
273         if((r != EOK) || (size != rw_szie))\r
274             break;\r
275     }\r
276 \r
277     if(i != rw_count){\r
278         printf("ERROR: rw_count = %d\n", i);\r
279         return false;\r
280     }\r
281 \r
282     printf("OK\n");\r
283     stop = clock() / (CLOCKS_PER_SEC / 1000);\r
284     diff = stop - start;\r
285     size_bytes = rw_szie * rw_count;\r
286     size_bytes = (size_bytes * 1000) / 1024;\r
287     kbps = (size_bytes) / (diff + 1);\r
288     printf("file_test write time: %d ms\n", (int)diff);\r
289     printf("file_test write speed: %d KB/s\n", kbps);\r
290     r = ext4_fclose(&f);\r
291     printf("ext4_fopen: test1\n");\r
292 \r
293 \r
294     start = clock() / (CLOCKS_PER_SEC / 1000);\r
295     r = ext4_fopen(&f, "/mp/test1", "r+");\r
296     if(r != EOK){\r
297         printf("ext4_fopen ERROR = %d\n", r);\r
298         return false;\r
299     }\r
300 \r
301     printf("ext4_read: %d * %d ..." , rw_szie, rw_count);\r
302 \r
303     for (i = 0; i < rw_count; ++i) {\r
304         memset(wr_buff, i % 10 + '0', rw_szie);\r
305         r = ext4_fread(&f, rd_buff, rw_szie, &size);\r
306 \r
307         if((r != EOK) || (size != rw_szie))\r
308             break;\r
309 \r
310         if(memcmp(rd_buff, wr_buff, rw_szie)){\r
311             break;\r
312         }\r
313     }\r
314     if(i != rw_count){\r
315         printf("ERROR: rw_count = %d\n", i);\r
316         return false;\r
317     }\r
318     printf("OK\n");\r
319     stop = clock() / (CLOCKS_PER_SEC / 1000);\r
320     diff = stop - start;\r
321     size_bytes = rw_szie * rw_count;\r
322     size_bytes = (size_bytes * 1000) / 1024;\r
323     kbps = (size_bytes) / (diff + 1);\r
324     printf("file_test read time: %d ms\n", (int)diff);\r
325     printf("file_test read speed: %d KB/s\n", kbps);\r
326     r = ext4_fclose(&f);\r
327 \r
328     return true;\r
329 \r
330 }\r
331 static void cleanup(void)\r
332 {\r
333     clock_t start;\r
334     clock_t stop;\r
335     clock_t diff;\r
336 \r
337     ext4_fremove("/mp/hello.txt");\r
338 \r
339     printf("cleanup: remove /mp/test1\n");\r
340     start = clock() / (CLOCKS_PER_SEC / 1000);\r
341     ext4_fremove("/mp/test1");\r
342     stop = clock() / (CLOCKS_PER_SEC / 1000);\r
343     diff = stop - start;\r
344     printf("cleanup: time: %d ms\n", (int)diff);\r
345 \r
346 \r
347     printf("cleanup: remove /mp/test1\n");\r
348     start = clock() / (CLOCKS_PER_SEC / 1000);\r
349     ext4_dir_rm("/mp/dir1");\r
350     stop = clock() / (CLOCKS_PER_SEC / 1000);\r
351     diff = stop - start;\r
352     printf("cleanup: time: %d ms\n", (int)diff);\r
353 }\r
354 \r
355 static bool open_filedev(void)\r
356 {\r
357     ext4_filedev_filename(input_name);\r
358     bd = ext4_filedev_get();\r
359     bc = ext4_filecache_get();\r
360     if(!bd || !bc){\r
361         printf("Block device ERROR\n");\r
362         return false;\r
363     }\r
364     return true;\r
365 }\r
366 \r
367 static bool open_winpartition(void)\r
368 {\r
369 #ifdef WIN32\r
370     ext4_io_raw_filename(input_name);\r
371     bd = ext4_io_raw_dev_get();\r
372     bc = ext4_io_raw_cache_get();\r
373     if(!bd || !bc){\r
374         printf("Block device ERROR\n");\r
375         return false;\r
376     }\r
377     return true;\r
378 #else\r
379     printf("open_winpartition: this mode shouls be used only under windows !\n");\r
380     return false;\r
381 #endif\r
382 }\r
383 \r
384 static bool mount(void)\r
385 {\r
386     int r;\r
387     if(winpart){\r
388          if(!open_winpartition())\r
389              return false;\r
390     }else{\r
391         if(!open_filedev())\r
392             return false;\r
393 \r
394     }\r
395     wr_buff = malloc(rw_szie);\r
396     rd_buff = malloc(rw_szie);\r
397 \r
398     if(!wr_buff || !rd_buff){\r
399         printf("Read-Write allocation ERROR\n");\r
400         return EXIT_FAILURE;\r
401     }\r
402 \r
403     ext4_dmask_set(EXT4_DEBUG_ALL);\r
404 \r
405     r = ext4_device_register(bd, cache_mode ? 0 : bc, "ext4_filesim");\r
406     if(r != EOK){\r
407         printf("ext4_device_register ERROR = %d\n", r);\r
408         return false;\r
409     }\r
410 \r
411     r = ext4_mount("ext4_filesim", "/mp/");\r
412     if(r != EOK){\r
413         printf("ext4_mount ERROR = %d\n", r);\r
414         return false;\r
415     }\r
416 \r
417     return true;\r
418 }\r
419 \r
420 static bool umount(void)\r
421 {\r
422     int r = ext4_umount("/mp/");\r
423     if(r != EOK){\r
424         printf("ext4_umount: FAIL %d", r);\r
425         return false;\r
426     }\r
427     return true;\r
428 }\r
429 \r
430 static bool parse_opt(int argc, char **argv)\r
431 {\r
432     int option_index = 0;\r
433     int c;\r
434 \r
435     static struct option long_options[] =\r
436       {\r
437         {"in",      required_argument, 0, 'a'},\r
438         {"rws",     required_argument, 0, 'b'},\r
439         {"rwc",     required_argument, 0, 'c'},\r
440         {"cache",   required_argument, 0, 'd'},\r
441         {"dirs",    required_argument, 0, 'e'},\r
442         {"clean",   no_argument,       0, 'f'},\r
443         {"bstat",   no_argument,       0, 'g'},\r
444         {"sbstat",  no_argument,       0, 'h'},\r
445         {"wpart",   no_argument,       0, 'i'},\r
446         {0, 0, 0, 0}\r
447       };\r
448 \r
449     while(-1 != (c = getopt_long (argc, argv, "a:b:c:d:e:fghi", long_options, &option_index))) {\r
450 \r
451         switch(c){\r
452             case 'a':\r
453                 strcpy(input_name, optarg);\r
454                 break;\r
455             case 'b':\r
456                 rw_szie = atoi(optarg);\r
457                 break;\r
458             case 'c':\r
459                 rw_count = atoi(optarg);\r
460                 break;\r
461             case 'd':\r
462                 cache_mode = atoi(optarg);\r
463                 break;\r
464             case 'e':\r
465                 dir_cnt = atoi(optarg);\r
466                 break;\r
467             case 'f':\r
468                 cleanup_flag = true;\r
469                 break;\r
470             case 'g':\r
471                 bstat = true;\r
472                 break;\r
473             case 'h':\r
474                 sbstat = true;\r
475                 break;\r
476             case 'i':\r
477                 winpart = true;\r
478                 break;\r
479             default:\r
480                 printf("%s", usage);\r
481                 return false;\r
482 \r
483         }\r
484     }\r
485     return true;\r
486 }\r
487 \r
488 int main(int argc, char **argv)\r
489 {\r
490     if(!parse_opt(argc, argv))\r
491         return EXIT_FAILURE;\r
492 \r
493     printf("Test conditions:\n");\r
494     printf("Imput name: %s\n", input_name);\r
495     printf("RW size: %d\n",  rw_szie);\r
496     printf("RW count: %d\n", rw_count);\r
497     printf("Cache mode: %s\n", cache_mode ? "dynamic" : "static");\r
498 \r
499     if(!mount())\r
500         return EXIT_FAILURE;\r
501 \r
502 \r
503     cleanup();\r
504 \r
505     if(sbstat)\r
506         mp_stats();\r
507 \r
508     dir_ls("/mp/");\r
509     fflush(stdout);\r
510     if(!dir_test(dir_cnt))\r
511             return EXIT_FAILURE;\r
512 \r
513     fflush(stdout);\r
514         if(!file_test())\r
515             return EXIT_FAILURE;\r
516 \r
517         fflush(stdout);\r
518         dir_ls("/mp/");\r
519 \r
520         if(sbstat)\r
521             mp_stats();\r
522 \r
523         if(cleanup_flag)\r
524             cleanup();\r
525 \r
526     if(bstat)\r
527         block_stats();\r
528 \r
529     if(!umount())\r
530         return EXIT_FAILURE;\r
531 \r
532     printf("Test finish: OK\n");\r
533     return EXIT_SUCCESS;\r
534 \r
535 }\r