1 #include <stdio.h>
2 #include <sys/mman.h>
3 #include <sys/ioctl.h>
4 #include <sys/socket.h>
5 #include <sys/stat.h>
6 #include <sys/types.h>
7 #include <sys/time.h>
8 #include <unistd.h>
9 #include <sys/wait.h>
10 #include <sys/syscall.h>
11 #include <errno.h>
12 #include <fcntl.h>
13 #include <getopt.h>
14 #include <string.h>
15 #include <stdlib.h>
16
17 #define F2FS_IOCTL_MAGIC 0xf5
18 #define F2FS_IOC_START_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 1)
19 #define F2FS_IOC_COMMIT_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 2)
20 #define F2FS_IOC_START_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 3)
21 #define F2FS_IOC_RELEASE_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 4)
22 #define F2FS_IOC_ABORT_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 5)
23 #define F2FS_IOC_GARBAGE_COLLECT _IO(F2FS_IOCTL_MAGIC, 6)
24
25 #define DB1_PATH "/data/database_file1"
26 #define DB2_PATH "/sdcard/database_file2"
27 #define FILE_PATH "/data/testfile"
28
29 #define BLOCK 4096
30 #define BLOCKS (2 * BLOCK)
31
32 int buf[BLOCKS];
33 char cmd[BLOCK];
34
run(char * cmd)35 static int run(char *cmd)
36 {
37 int status;
38
39 fflush(stdout);
40
41 switch (fork()) {
42 case 0:
43 /* redirect stderr to stdout */
44 dup2(1, 2);
45 execl("/system/bin/sh", "sh", "-c", cmd, (char *) 0);
46 default:
47 wait(&status);
48 }
49 return 0;
50 }
51
test_atomic_write(char * path)52 static int test_atomic_write(char *path)
53 {
54 int db, ret, written;
55
56 printf("\tOpen %s... \n", path);
57 db = open(path, O_RDWR|O_CREAT, 0666);
58 if (db < 0) {
59 printf("open failed errno:%d\n", errno);
60 return -1;
61 }
62 printf("\tStart ... \n");
63 ret = ioctl(db, F2FS_IOC_START_ATOMIC_WRITE);
64 if (ret) {
65 printf("ioctl failed errno:%d\n", errno);
66 return -1;
67 }
68 printf("\tWrite to the %dkB ... \n", BLOCKS / 1024);
69 written = write(db, buf, BLOCKS);
70 if (written != BLOCKS) {
71 printf("write fail written:%d, errno:%d\n", written, errno);
72 return -1;
73 }
74 printf("\tCheck : Atomic in-memory count: 2\n");
75 run("cat /sys/kernel/debug/f2fs/status | grep atomic");
76
77 printf("\tCommit ... \n");
78 ret = ioctl(db, F2FS_IOC_COMMIT_ATOMIC_WRITE);
79 if (ret) {
80 printf("ioctl failed errno:%d\n", errno);
81 return -1;
82 }
83 return 0;
84 }
85
test_bad_write_call(char * path)86 static int test_bad_write_call(char *path)
87 {
88 int fd, written;
89 struct stat sb;
90 int large_size = 1024 * 1024 * 100; /* 100 MB */
91
92 printf("\tOpen %s... \n", path);
93 fd = open(path, O_RDWR|O_CREAT|O_TRUNC, 0666);
94 if (fd < 0) {
95 printf("open failed errno:%d\n", errno);
96 return -1;
97 }
98
99 /* 8KB-sized buffer, but submit 100 MB size */
100 printf("\tWrite to the %dkB ... \n", BLOCKS / 1024);
101 written = write(fd, buf, large_size);
102 if (written != BLOCKS)
103 printf("Ok: write fail written:%d, errno:%d\n", written, errno);
104 close(fd);
105
106 fd = open(path, O_RDONLY);
107 if (fd < 0) {
108 printf("open failed errno:%d\n", errno);
109 return -1;
110 }
111
112 if (stat(path, &sb) == -1) {
113 printf("stat failed errno:%d\n", errno);
114 return -1;
115 }
116
117 if ((long long)sb.st_size / 512 != (long long)sb.st_blocks) {
118 printf("FAIL: Mismatch i_size and i_blocks: %lld %lld\n",
119 (long long)sb.st_size, (long long)sb.st_blocks);
120 printf("FAIL: missing patch "
121 "\"f2fs: do not preallocate blocks which has wrong buffer\"\n");
122 }
123 close(fd);
124 unlink(path);
125 return 0;
126 }
127
main(void)128 int main(void)
129 {
130 memset(buf, 0xff, BLOCKS);
131
132 printf("# Test 0: Check F2FS support\n");
133 run("cat /proc/filesystems");
134
135 printf("# Test 1: Check F2FS status on /userdata\n");
136 printf("\t= FS type /userdata\n");
137 run("mount | grep data");
138
139 printf("\n\t= F2FS features\n");
140 run("ls -1 /sys/fs/f2fs/features/");
141 run("find /sys/fs/f2fs -type f -name \"features\" -print -exec cat {} \\;");
142 run("find /sys/fs/f2fs -type f -name \"ipu_policy\" -print -exec cat {} \\;");
143 run("find /sys/fs/f2fs -type f -name \"discard_granularity\" -print -exec cat {} \\;");
144 run("cat /sys/kernel/debug/f2fs/status");
145
146 printf("\n\n# Test 2: Atomic_write on /userdata\n");
147 if (test_atomic_write(DB1_PATH))
148 return 0;
149
150 printf("# Test 3: Atomic_write on /sdcard\n");
151 if (test_atomic_write(DB2_PATH))
152 return 0;
153
154 printf("# Test 4: Bad write(2) call\n");
155 if (test_bad_write_call(FILE_PATH))
156 return 0;
157 return 0;
158 }
159