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