xref: /linux/tools/testing/selftests/filesystems/fuse/write_extend_eof_test.c (revision 67f8bc848ee31831336bd478e57d2f993551902e)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Regression test for the fuse write-extend partial-EOF-page zeroing bug.
4  *
5  * A buffered write that extends i_size past a non-page-aligned EOF must zero
6  * the tail of the old last page.  If an application has mmap'd that page and
7  * stored into the post-EOF region (undefined until the file grows), the
8  * now-in-bounds tail must read back as zero, not as the stale stored bytes.
9  *
10  * The bug is exposed on a non-writeback_cache server that keeps the page cache
11  * across the write (FOPEN_KEEP_CACHE without FOPEN_DIRECT_IO).  This test is a
12  * raw /dev/fuse server in that mode; the backing data is always zero in the
13  * hole, so any non-zero byte a read sees is stale page-cache data.
14  *
15  * Requires root to mount fuse.
16  */
17 #define _GNU_SOURCE
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <linux/falloc.h>
21 #include <pthread.h>
22 #include <stdint.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <sys/mman.h>
26 #include <sys/mount.h>
27 #include <sys/stat.h>
28 #include <sys/uio.h>
29 #include <linux/fuse.h>
30 
31 #include "../../kselftest_harness.h"
32 
33 #define FUSE_ROOT_ID	1
34 #define FILE_INO	2
35 #define MAX_WRITE	(128 * 1024)
36 #define BACKING_SIZE	(4 * 1024 * 1024)
37 #define POLLUTE		0xee
38 
39 /* Server-side state, shared with the responder thread. */
40 struct server {
41 	int fd;
42 	unsigned char backing[BACKING_SIZE];	/* authoritative bytes */
43 	uint64_t size;
44 };
45 
46 static void reply(int fd, uint64_t unique, int error, void *data, size_t len)
47 {
48 	struct fuse_out_header oh = {
49 		.len = sizeof(oh) + (data ? len : 0),
50 		.error = error,
51 		.unique = unique,
52 	};
53 	struct iovec iov[2] = { { &oh, sizeof(oh) }, { data, len } };
54 
55 	/* Errors here are teardown races (device closed on unmount); ignore. */
56 	if (writev(fd, iov, data ? 2 : 1) < 0)
57 		return;
58 }
59 
60 static void fill_attr(struct fuse_attr *a, uint64_t ino, uint32_t mode,
61 		      uint64_t size)
62 {
63 	memset(a, 0, sizeof(*a));
64 	a->ino = ino;
65 	a->mode = mode;
66 	a->nlink = 1;
67 	a->size = size;
68 	a->blksize = sysconf(_SC_PAGESIZE);
69 }
70 
71 static void *server_thread(void *arg)
72 {
73 	struct server *s = arg;
74 	static char buf[MAX_WRITE + 4096];
75 
76 	for (;;) {
77 		ssize_t n = read(s->fd, buf, sizeof(buf));
78 		struct fuse_in_header *ih = (void *)buf;
79 
80 		if (n < 0) {
81 			if (errno == EINTR || errno == EAGAIN)
82 				continue;
83 			return NULL;	/* device closed on unmount */
84 		}
85 		if (n < (ssize_t)sizeof(*ih))
86 			continue;
87 
88 		switch (ih->opcode) {
89 		case FUSE_INIT: {
90 			struct fuse_init_in *in = (void *)(ih + 1);
91 			struct fuse_init_out out = {0};
92 
93 			/* No FUSE_WRITEBACK_CACHE: the exposed configuration. */
94 			out.major = FUSE_KERNEL_VERSION;
95 			out.minor = FUSE_KERNEL_MINOR_VERSION;
96 			out.max_readahead = in->max_readahead;
97 			out.max_write = MAX_WRITE;
98 			out.max_background = 16;
99 			out.congestion_threshold = 12;
100 			out.flags = FUSE_MAX_PAGES;
101 			out.max_pages = MAX_WRITE / sysconf(_SC_PAGESIZE);
102 			reply(s->fd, ih->unique, 0, &out, sizeof(out));
103 			break;
104 		}
105 		case FUSE_GETATTR: {
106 			struct fuse_attr_out out = {0};
107 			int root = ih->nodeid == FUSE_ROOT_ID;
108 
109 			out.attr_valid = 3600;
110 			fill_attr(&out.attr, ih->nodeid,
111 				  root ? (S_IFDIR | 0755) : (S_IFREG | 0644),
112 				  root ? 0 : s->size);
113 			reply(s->fd, ih->unique, 0, &out, sizeof(out));
114 			break;
115 		}
116 		case FUSE_LOOKUP: {
117 			struct fuse_entry_out out = {0};
118 
119 			out.nodeid = FILE_INO;
120 			out.attr_valid = 3600;
121 			out.entry_valid = 3600;
122 			fill_attr(&out.attr, FILE_INO, S_IFREG | 0644, s->size);
123 			reply(s->fd, ih->unique, 0, &out, sizeof(out));
124 			break;
125 		}
126 		case FUSE_OPEN:
127 		case FUSE_OPENDIR: {
128 			struct fuse_open_out out = {0};
129 
130 			/* Keep the cache across the write, but not direct I/O. */
131 			out.open_flags = FOPEN_KEEP_CACHE;
132 			reply(s->fd, ih->unique, 0, &out, sizeof(out));
133 			break;
134 		}
135 		case FUSE_READ: {
136 			struct fuse_read_in *in = (void *)(ih + 1);
137 			uint64_t off = in->offset;
138 			uint32_t size = in->size;
139 
140 			if (off >= BACKING_SIZE)
141 				size = 0;
142 			else if (off + size > BACKING_SIZE)
143 				size = BACKING_SIZE - off;
144 			reply(s->fd, ih->unique, 0, s->backing + off, size);
145 			break;
146 		}
147 		case FUSE_WRITE: {
148 			struct fuse_write_in *in = (void *)(ih + 1);
149 			struct fuse_write_out out = {0};
150 			uint64_t off = in->offset;
151 			uint32_t size = in->size;
152 
153 			if (off < BACKING_SIZE) {
154 				uint32_t c = size;
155 
156 				if (off + c > BACKING_SIZE)
157 					c = BACKING_SIZE - off;
158 				memcpy(s->backing + off, in + 1, c);
159 				if (off + c > s->size)
160 					s->size = off + c;
161 			}
162 			out.size = size;
163 			reply(s->fd, ih->unique, 0, &out, sizeof(out));
164 			break;
165 		}
166 		case FUSE_SETATTR: {
167 			struct fuse_setattr_in *in = (void *)(ih + 1);
168 			struct fuse_attr_out out = {0};
169 
170 			if ((in->valid & FATTR_SIZE) && in->size <= BACKING_SIZE) {
171 				if (in->size > s->size)
172 					memset(s->backing + s->size, 0,
173 					       in->size - s->size);
174 				s->size = in->size;
175 			}
176 			out.attr_valid = 3600;
177 			fill_attr(&out.attr, ih->nodeid, S_IFREG | 0644, s->size);
178 			reply(s->fd, ih->unique, 0, &out, sizeof(out));
179 			break;
180 		}
181 		case FUSE_FALLOCATE: {
182 			struct fuse_fallocate_in *in = (void *)(ih + 1);
183 			uint64_t end = in->offset + in->length;
184 
185 			/* Only plain (size-extending) fallocate is used here. */
186 			if (!(in->mode & FALLOC_FL_KEEP_SIZE) &&
187 			    end <= BACKING_SIZE && end > s->size) {
188 				memset(s->backing + s->size, 0, end - s->size);
189 				s->size = end;
190 			}
191 			reply(s->fd, ih->unique, 0, NULL, 0);
192 			break;
193 		}
194 		case FUSE_FLUSH:
195 		case FUSE_RELEASE:
196 		case FUSE_RELEASEDIR:
197 		case FUSE_FSYNC:
198 		case FUSE_ACCESS:
199 			reply(s->fd, ih->unique, 0, NULL, 0);
200 			break;
201 		case FUSE_FORGET:
202 			break;
203 		default:
204 			reply(s->fd, ih->unique, -EOPNOTSUPP, NULL, 0);
205 			break;
206 		}
207 	}
208 }
209 
210 FIXTURE(fuse)
211 {
212 	struct server *srv;
213 	pthread_t thread;
214 	char dir[64];
215 	long page;		/* runtime page size */
216 	off_t eof;		/* mid-page EOF, page-relative */
217 	int fd;			/* open test file */
218 	char *map;		/* mmap of the EOF page */
219 	int mounted;
220 };
221 
222 FIXTURE_SETUP(fuse)
223 {
224 	char opts[128];
225 	pthread_t t;
226 
227 	if (geteuid() != 0)
228 		SKIP(return, "need root to mount fuse");
229 
230 	self->page = sysconf(_SC_PAGESIZE);
231 	self->fd = -1;
232 	self->map = MAP_FAILED;
233 
234 	self->srv = mmap(NULL, sizeof(*self->srv), PROT_READ | PROT_WRITE,
235 			 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
236 	ASSERT_NE(MAP_FAILED, self->srv);
237 
238 	self->srv->fd = open("/dev/fuse", O_RDWR);
239 	ASSERT_GE(self->srv->fd, 0);
240 
241 	strcpy(self->dir, "/tmp/fuse_weof_XXXXXX");
242 	ASSERT_NE(NULL, mkdtemp(self->dir));
243 
244 	snprintf(opts, sizeof(opts),
245 		 "fd=%d,rootmode=40000,user_id=0,group_id=0",
246 		 self->srv->fd);
247 	ASSERT_EQ(0, mount("fuse", self->dir, "fuse", 0, opts));
248 	self->mounted = 1;
249 
250 	ASSERT_EQ(0, pthread_create(&t, NULL, server_thread, self->srv));
251 	self->thread = t;
252 }
253 
254 FIXTURE_TEARDOWN(fuse)
255 {
256 	if (self->map != MAP_FAILED)
257 		munmap(self->map, self->page);
258 	if (self->fd >= 0)
259 		close(self->fd);
260 	if (self->mounted)
261 		umount2(self->dir, MNT_DETACH);
262 	if (self->srv && self->srv != MAP_FAILED) {
263 		if (self->srv->fd > 0)
264 			close(self->srv->fd);
265 		munmap(self->srv, sizeof(*self->srv));
266 	}
267 	if (self->dir[0])
268 		rmdir(self->dir);
269 }
270 
271 /*
272  * Create the test file with a mid-page EOF and mmap-store POLLUTE into its
273  * post-EOF tail (a legal store, undefined until the file grows).  Leaves the
274  * file open and the EOF page mapped in the fixture for the caller to extend.
275  */
276 static void pollute_eof_tail(struct __test_metadata *_metadata,
277 			     FIXTURE_DATA(fuse) * self)
278 {
279 	off_t eof = 2 * self->page + self->page / 4;
280 	char path[128];
281 	char *buf;
282 
283 	snprintf(path, sizeof(path), "%s/file", self->dir);
284 	self->fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0644);
285 	ASSERT_GE(self->fd, 0);
286 	self->eof = eof;
287 
288 	buf = malloc(eof);
289 	ASSERT_NE(NULL, buf);
290 	memset(buf, 'A', eof);
291 	ASSERT_EQ(eof, pwrite(self->fd, buf, eof, 0));
292 	free(buf);
293 
294 	self->map = mmap(NULL, self->page, PROT_READ | PROT_WRITE, MAP_SHARED,
295 			 self->fd, eof & ~(self->page - 1));
296 	ASSERT_NE(MAP_FAILED, self->map);
297 	memset(self->map + (eof & (self->page - 1)), POLLUTE,
298 	       self->page - (eof & (self->page - 1)));
299 }
300 
301 /* Assert the old post-EOF tail [eof, end of its page) now reads back as zero. */
302 static void assert_tail_zeroed(struct __test_metadata *_metadata,
303 			       FIXTURE_DATA(fuse) * self)
304 {
305 	off_t base = self->eof & ~(self->page - 1);
306 	char *tail = malloc(self->page);
307 	int i;
308 
309 	ASSERT_NE(NULL, tail);
310 	ASSERT_EQ(self->page, pread(self->fd, tail, self->page, base));
311 	for (i = self->eof & (self->page - 1); i < self->page; i++)
312 		ASSERT_EQ(0, tail[i]);
313 	free(tail);
314 }
315 
316 /* Basic: pollute the post-EOF tail, extend past it by a later write. */
317 TEST_F(fuse, write_extend)
318 {
319 	pollute_eof_tail(_metadata, self);
320 	ASSERT_EQ(4, pwrite(self->fd, "data", 4, 5 * self->page + self->page / 3));
321 	assert_tail_zeroed(_metadata, self);
322 }
323 
324 /* Extend via ftruncate() rather than a write. */
325 TEST_F(fuse, ftruncate_extend)
326 {
327 	pollute_eof_tail(_metadata, self);
328 	ASSERT_EQ(0, ftruncate(self->fd, 8 * self->page));
329 	assert_tail_zeroed(_metadata, self);
330 }
331 
332 /* Extend via fallocate() starting at the old EOF. */
333 TEST_F(fuse, fallocate_extend)
334 {
335 	pollute_eof_tail(_metadata, self);
336 	ASSERT_EQ(0, fallocate(self->fd, 0, self->eof, 4 * self->page));
337 	assert_tail_zeroed(_metadata, self);
338 }
339 
340 /* A write landing inside the old EOF page must not clobber its own data. */
341 TEST_F(fuse, extend_into_eof_page_preserves_data)
342 {
343 	off_t base, wr;
344 	char *buf, *rd;
345 	int i;
346 
347 	pollute_eof_tail(_metadata, self);
348 	base = self->eof & ~(self->page - 1);
349 	wr = base + 3 * self->page / 4;		/* starts in the EOF page */
350 
351 	buf = malloc(2 * self->page);
352 	ASSERT_NE(NULL, buf);
353 	memset(buf, 'B', 2 * self->page);
354 	ASSERT_EQ(2 * self->page, pwrite(self->fd, buf, 2 * self->page, wr));
355 	free(buf);
356 
357 	rd = malloc(self->page);
358 	ASSERT_NE(NULL, rd);
359 	ASSERT_EQ(self->page, pread(self->fd, rd, self->page, base));
360 	/* [eof, wr) is hole -> zero; [wr, page) is written data -> 'B'. */
361 	for (i = self->eof & (self->page - 1); i < wr - base; i++)
362 		ASSERT_EQ(0, rd[i]);
363 	for (i = wr - base; i < self->page; i++)
364 		ASSERT_EQ('B', rd[i]);
365 	free(rd);
366 }
367 
368 TEST_HARNESS_MAIN
369