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