1/******************************************************************************/
2/*                                                                            */
3/* Copyright (c) 2009 FUJITSU LIMITED                                         */
4/*                                                                            */
5/* This program is free software;  you can redistribute it and/or modify      */
6/* it under the terms of the GNU General Public License as published by       */
7/* the Free Software Foundation; either version 2 of the License, or          */
8/* (at your option) any later version.                                        */
9/*                                                                            */
10/* This program is distributed in the hope that it will be useful,            */
11/* but WITHOUT ANY WARRANTY;  without even the implied warranty of            */
12/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See                  */
13/* the GNU General Public License for more details.                           */
14/*                                                                            */
15/* You should have received a copy of the GNU General Public License          */
16/* along with this program;  if not, write to the Free Software               */
17/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA    */
18/*                                                                            */
19/* Author: Li Zefan <lizf@cn.fujitsu.com>                                     */
20/*                                                                            */
21/******************************************************************************/
22
23#include <unistd.h>
24#include <sys/wait.h>
25#include <string.h>
26#include <stdlib.h>
27#include <stdio.h>
28#include <fcntl.h>
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <sys/mman.h>
32
33char *filename;
34char *filepath;
35int fd;
36
37int old_inode_version;
38int new_inode_version;
39
40int get_inode_version(void)
41{
42	char buf[1024];
43
44	sprintf(buf, "ext4_get_inode_version.sh %s 1", filename);
45
46	/* sync before run debugfs to get inode version */
47	sync();
48
49	return WEXITSTATUS(system(buf));
50}
51
52void test_chmod(void)
53{
54	if (fchmod(fd, S_IRUSR | S_IWUSR)) {
55		fprintf(stderr, "fchmod failed\n");
56		exit(1);
57	}
58}
59
60void test_chown(void)
61{
62	if (fchown(fd, 1, 1)) {
63		fprintf(stderr, "fchown failed\n");
64		exit(1);
65	}
66}
67
68void test_read(void)
69{
70	char buf[2];
71
72	/* write something before read */
73	if (write(fd, "abc", 4) == -1) {
74		perror("write");
75		exit(1);
76	}
77	close(fd);
78
79	if (open(filepath, O_RDONLY) == -1) {
80		perror("open");
81		exit(1);
82	}
83
84	old_inode_version = get_inode_version();
85
86	if (read(fd, buf, 1) == -1) {
87		perror("read");
88		exit(1);
89	}
90}
91
92void test_write(void)
93{
94	if (write(fd, "a", 1) == -1) {
95		fprintf(stderr, "write failed\n");
96		exit(1);
97	}
98}
99
100void test_mmap_read(void)
101{
102	char *p;
103	char c;
104
105	/* write something before read */
106	if (write(fd, "abc", 4) == -1) {
107		perror("write");
108		exit(1);
109	}
110	close(fd);
111
112	if (open(filepath, O_RDONLY) == -1) {
113		perror("open");
114		exit(1);
115	}
116
117	old_inode_version = get_inode_version();
118
119	p = mmap(NULL, 1, PROT_READ, MAP_PRIVATE | MAP_FILE, fd, 0);
120	if (p == (void *)-1) {
121		perror("mmap");
122		exit(1);
123	}
124	c = *p;
125
126	new_inode_version = get_inode_version();
127
128	msync(p, 1, MS_SYNC);
129}
130
131void test_mmap_write(void)
132{
133	char *p;
134
135	if (write(fd, "abc", 4) == -1) {
136		perror("write");
137		exit(1);
138	}
139	close(fd);
140
141	if (open(filepath, O_RDWR) == -1) {
142		perror("open");
143		exit(1);
144	}
145
146	old_inode_version = get_inode_version();
147
148	p = mmap(NULL, 1, PROT_WRITE, MAP_PRIVATE | MAP_FILE, fd, 0);
149	if (p == (void *)-1) {
150		perror("mmap");
151		exit(1);
152	}
153	*p = 'x';
154
155	new_inode_version = get_inode_version();
156
157	msync(p, 1, MS_SYNC);
158}
159
160/**
161 * argv[1]: file operation
162 * argv[2]: file to test (with path)
163 * argv[3]: file to test (without path)
164 */
165int main(int argc, char *argv[])
166{
167	if (argc != 4) {
168		fprintf(stderr, "wrong argument number\n");
169		return 1;
170	}
171	filepath = argv[2];
172	filename = argv[3];
173
174	/* create file and get the initial inode version */
175	fd = creat(argv[2], O_RDWR);
176	if (fd == -1) {
177		fprintf(stderr, "failed to create file: %s\n", argv[2]);
178		return 1;
179	}
180
181	old_inode_version = get_inode_version();
182
183	if (strcmp(argv[1], "create") == 0) {
184		printf("%d\n", old_inode_version);
185		return 0;
186	} else if (strcmp(argv[1], "chmod") == 0) {
187		test_chmod();
188	} else if (strcmp(argv[1], "chown") == 0) {
189		test_chown();
190	} else if (strcmp(argv[1], "read") == 0) {
191		test_read();
192	} else if (strcmp(argv[1], "write") == 0) {
193		test_write();
194	} else if (strcmp(argv[1], "mmap_read") == 0) {
195		test_mmap_read();
196	} else if (strcmp(argv[1], "mmap_write") == 0) {
197		test_mmap_write();
198	} else {
199		fprintf(stderr, "wrong file operation: %s\n", argv[1]);
200		return 1;
201	}
202
203	new_inode_version = get_inode_version();
204#if 0
205	fprintf(stderr, "test_inode_version: old - %d\n", old_inode_version);
206	fprintf(stderr, "test_inode_version: new - %d\n", new_inode_version);
207#endif
208	/* wrong inode version, test failed */
209	if (new_inode_version <= old_inode_version)
210		return 1;
211
212	printf("%d\n", new_inode_version);
213
214	close(fd);
215
216	return 0;
217}
218