xref: /freebsd/tests/sys/fs/fusefs/write.cc (revision 4e4e43dc9e1afc863670a031cc5cc75eb5e668d6)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2019 The FreeBSD Foundation
5  *
6  * This software was developed by BFF Storage Systems, LLC under sponsorship
7  * from the FreeBSD Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * $FreeBSD$
31  */
32 
33 extern "C" {
34 #include <sys/param.h>
35 #include <sys/mman.h>
36 #include <sys/resource.h>
37 #include <sys/stat.h>
38 #include <sys/time.h>
39 #include <sys/uio.h>
40 
41 #include <aio.h>
42 #include <fcntl.h>
43 #include <signal.h>
44 #include <unistd.h>
45 }
46 
47 #include "mockfs.hh"
48 #include "utils.hh"
49 
50 using namespace testing;
51 
52 class Write: public FuseTest {
53 
54 public:
55 static sig_atomic_t s_sigxfsz;
56 
57 void SetUp() {
58 	s_sigxfsz = 0;
59 	FuseTest::SetUp();
60 }
61 
62 void TearDown() {
63 	struct sigaction sa;
64 
65 	bzero(&sa, sizeof(sa));
66 	sa.sa_handler = SIG_DFL;
67 	sigaction(SIGXFSZ, &sa, NULL);
68 
69 	FuseTest::TearDown();
70 }
71 
72 void expect_lookup(const char *relpath, uint64_t ino, uint64_t size)
73 {
74 	FuseTest::expect_lookup(relpath, ino, S_IFREG | 0644, size, 1);
75 }
76 
77 void expect_release(uint64_t ino, ProcessMockerT r)
78 {
79 	EXPECT_CALL(*m_mock, process(
80 		ResultOf([=](auto in) {
81 			return (in.header.opcode == FUSE_RELEASE &&
82 				in.header.nodeid == ino);
83 		}, Eq(true)),
84 		_)
85 	).WillRepeatedly(Invoke(r));
86 }
87 
88 void expect_write(uint64_t ino, uint64_t offset, uint64_t isize,
89 	uint64_t osize, const void *contents)
90 {
91 	FuseTest::expect_write(ino, offset, isize, osize, 0, 0, contents);
92 }
93 
94 /* Expect a write that may or may not come, depending on the cache mode */
95 void maybe_expect_write(uint64_t ino, uint64_t offset, uint64_t size,
96 	const void *contents)
97 {
98 	EXPECT_CALL(*m_mock, process(
99 		ResultOf([=](auto in) {
100 			const char *buf = (const char*)in.body.bytes +
101 				sizeof(struct fuse_write_in);
102 
103 			return (in.header.opcode == FUSE_WRITE &&
104 				in.header.nodeid == ino &&
105 				in.body.write.offset == offset  &&
106 				in.body.write.size == size &&
107 				0 == bcmp(buf, contents, size));
108 		}, Eq(true)),
109 		_)
110 	).Times(AtMost(1))
111 	.WillRepeatedly(Invoke(
112 		ReturnImmediate([=](auto in __unused, auto& out) {
113 			SET_OUT_HEADER_LEN(out, write);
114 			out.body.write.size = size;
115 		})
116 	));
117 }
118 
119 };
120 
121 sig_atomic_t Write::s_sigxfsz = 0;
122 
123 class Write_7_8: public FuseTest {
124 
125 public:
126 virtual void SetUp() {
127 	m_kernel_minor_version = 8;
128 	FuseTest::SetUp();
129 }
130 
131 void expect_lookup(const char *relpath, uint64_t ino, uint64_t size)
132 {
133 	FuseTest::expect_lookup_7_8(relpath, ino, S_IFREG | 0644, size, 1);
134 }
135 
136 };
137 
138 class AioWrite: public Write {
139 virtual void SetUp() {
140 	if (!is_unsafe_aio_enabled())
141 		GTEST_SKIP() <<
142 			"vfs.aio.enable_unsafe must be set for this test";
143 	FuseTest::SetUp();
144 }
145 };
146 
147 /* Tests for the writeback cache mode */
148 class WriteBack: public Write {
149 public:
150 virtual void SetUp() {
151 	m_init_flags |= FUSE_WRITEBACK_CACHE;
152 	FuseTest::SetUp();
153 	if (IsSkipped())
154 		return;
155 }
156 
157 void expect_write(uint64_t ino, uint64_t offset, uint64_t isize,
158 	uint64_t osize, const void *contents)
159 {
160 	FuseTest::expect_write(ino, offset, isize, osize, FUSE_WRITE_CACHE, 0,
161 		contents);
162 }
163 };
164 
165 class WriteBackAsync: public WriteBack {
166 public:
167 virtual void SetUp() {
168 	m_async = true;
169 	m_maxwrite = 65536;
170 	WriteBack::SetUp();
171 }
172 };
173 
174 class TimeGran: public WriteBackAsync, public WithParamInterface<unsigned> {
175 public:
176 virtual void SetUp() {
177 	m_time_gran = 1 << GetParam();
178 	WriteBackAsync::SetUp();
179 }
180 };
181 
182 /* Tests for clustered writes with WriteBack cacheing */
183 class WriteCluster: public WriteBack {
184 public:
185 virtual void SetUp() {
186 	m_async = true;
187 	m_maxwrite = 1 << 25;	// Anything larger than MAXPHYS will suffice
188 	WriteBack::SetUp();
189 	if (m_maxphys < 2 * DFLTPHYS)
190 		GTEST_SKIP() << "MAXPHYS must be at least twice DFLTPHYS"
191 			<< " for this test";
192 	if (m_maxphys < 2 * m_maxbcachebuf)
193 		GTEST_SKIP() << "MAXPHYS must be at least twice maxbcachebuf"
194 			<< " for this test";
195 }
196 };
197 
198 /* Tests relating to the server's max_write property */
199 class WriteMaxWrite: public Write {
200 public:
201 virtual void SetUp() {
202 	/*
203 	 * For this test, m_maxwrite must be less than either m_maxbcachebuf or
204 	 * maxphys.
205 	 */
206 	m_maxwrite = 32768;
207 	Write::SetUp();
208 }
209 };
210 
211 void sigxfsz_handler(int __unused sig) {
212 	Write::s_sigxfsz = 1;
213 }
214 
215 /* AIO writes need to set the header's pid field correctly */
216 /* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236379 */
217 TEST_F(AioWrite, DISABLED_aio_write)
218 {
219 	const char FULLPATH[] = "mountpoint/some_file.txt";
220 	const char RELPATH[] = "some_file.txt";
221 	const char *CONTENTS = "abcdefgh";
222 	uint64_t ino = 42;
223 	uint64_t offset = 4096;
224 	int fd;
225 	ssize_t bufsize = strlen(CONTENTS);
226 	struct aiocb iocb, *piocb;
227 
228 	expect_lookup(RELPATH, ino, 0);
229 	expect_open(ino, 0, 1);
230 	expect_write(ino, offset, bufsize, bufsize, CONTENTS);
231 
232 	fd = open(FULLPATH, O_WRONLY);
233 	ASSERT_LE(0, fd) << strerror(errno);
234 
235 	iocb.aio_nbytes = bufsize;
236 	iocb.aio_fildes = fd;
237 	iocb.aio_buf = __DECONST(void *, CONTENTS);
238 	iocb.aio_offset = offset;
239 	iocb.aio_sigevent.sigev_notify = SIGEV_NONE;
240 	ASSERT_EQ(0, aio_write(&iocb)) << strerror(errno);
241 	ASSERT_EQ(bufsize, aio_waitcomplete(&piocb, NULL)) << strerror(errno);
242 	leak(fd);
243 }
244 
245 /*
246  * When a file is opened with O_APPEND, we should forward that flag to
247  * FUSE_OPEN (tested by Open.o_append) but still attempt to calculate the
248  * offset internally.  That way we'll work both with filesystems that
249  * understand O_APPEND (and ignore the offset) and filesystems that don't (and
250  * simply use the offset).
251  *
252  * Note that verifying the O_APPEND flag in FUSE_OPEN is done in the
253  * Open.o_append test.
254  */
255 TEST_F(Write, append)
256 {
257 	const ssize_t BUFSIZE = 9;
258 	const char FULLPATH[] = "mountpoint/some_file.txt";
259 	const char RELPATH[] = "some_file.txt";
260 	const char CONTENTS[BUFSIZE] = "abcdefgh";
261 	uint64_t ino = 42;
262 	/*
263 	 * Set offset to a maxbcachebuf boundary so we don't need to RMW when
264 	 * using writeback caching
265 	 */
266 	uint64_t initial_offset = m_maxbcachebuf;
267 	int fd;
268 
269 	expect_lookup(RELPATH, ino, initial_offset);
270 	expect_open(ino, 0, 1);
271 	expect_write(ino, initial_offset, BUFSIZE, BUFSIZE, CONTENTS);
272 
273 	/* Must open O_RDWR or fuse(4) implicitly sets direct_io */
274 	fd = open(FULLPATH, O_RDWR | O_APPEND);
275 	ASSERT_LE(0, fd) << strerror(errno);
276 
277 	ASSERT_EQ(BUFSIZE, write(fd, CONTENTS, BUFSIZE)) << strerror(errno);
278 	leak(fd);
279 }
280 
281 /* If a file is cached, then appending to the end should not cause a read */
282 TEST_F(Write, append_to_cached)
283 {
284 	const ssize_t BUFSIZE = 9;
285 	const char FULLPATH[] = "mountpoint/some_file.txt";
286 	const char RELPATH[] = "some_file.txt";
287 	char *oldcontents, *oldbuf;
288 	const char CONTENTS[BUFSIZE] = "abcdefgh";
289 	uint64_t ino = 42;
290 	/*
291 	 * Set offset in between maxbcachebuf boundary to test buffer handling
292 	 */
293 	uint64_t oldsize = m_maxbcachebuf / 2;
294 	int fd;
295 
296 	oldcontents = (char*)calloc(1, oldsize);
297 	ASSERT_NE(nullptr, oldcontents) << strerror(errno);
298 	oldbuf = (char*)malloc(oldsize);
299 	ASSERT_NE(nullptr, oldbuf) << strerror(errno);
300 
301 	expect_lookup(RELPATH, ino, oldsize);
302 	expect_open(ino, 0, 1);
303 	expect_read(ino, 0, oldsize, oldsize, oldcontents);
304 	maybe_expect_write(ino, oldsize, BUFSIZE, CONTENTS);
305 
306 	/* Must open O_RDWR or fuse(4) implicitly sets direct_io */
307 	fd = open(FULLPATH, O_RDWR | O_APPEND);
308 	ASSERT_LE(0, fd) << strerror(errno);
309 
310 	/* Read the old data into the cache */
311 	ASSERT_EQ((ssize_t)oldsize, read(fd, oldbuf, oldsize))
312 		<< strerror(errno);
313 
314 	/* Write the new data.  There should be no more read operations */
315 	ASSERT_EQ(BUFSIZE, write(fd, CONTENTS, BUFSIZE)) << strerror(errno);
316 	leak(fd);
317 	free(oldbuf);
318 	free(oldcontents);
319 }
320 
321 TEST_F(Write, append_direct_io)
322 {
323 	const ssize_t BUFSIZE = 9;
324 	const char FULLPATH[] = "mountpoint/some_file.txt";
325 	const char RELPATH[] = "some_file.txt";
326 	const char CONTENTS[BUFSIZE] = "abcdefgh";
327 	uint64_t ino = 42;
328 	uint64_t initial_offset = 4096;
329 	int fd;
330 
331 	expect_lookup(RELPATH, ino, initial_offset);
332 	expect_open(ino, FOPEN_DIRECT_IO, 1);
333 	expect_write(ino, initial_offset, BUFSIZE, BUFSIZE, CONTENTS);
334 
335 	fd = open(FULLPATH, O_WRONLY | O_APPEND);
336 	ASSERT_LE(0, fd) << strerror(errno);
337 
338 	ASSERT_EQ(BUFSIZE, write(fd, CONTENTS, BUFSIZE)) << strerror(errno);
339 	leak(fd);
340 }
341 
342 /* A direct write should evict any overlapping cached data */
343 TEST_F(Write, direct_io_evicts_cache)
344 {
345 	const char FULLPATH[] = "mountpoint/some_file.txt";
346 	const char RELPATH[] = "some_file.txt";
347 	const char CONTENTS0[] = "abcdefgh";
348 	const char CONTENTS1[] = "ijklmnop";
349 	uint64_t ino = 42;
350 	int fd;
351 	ssize_t bufsize = strlen(CONTENTS0) + 1;
352 	char readbuf[bufsize];
353 
354 	expect_lookup(RELPATH, ino, bufsize);
355 	expect_open(ino, 0, 1);
356 	expect_read(ino, 0, bufsize, bufsize, CONTENTS0);
357 	expect_write(ino, 0, bufsize, bufsize, CONTENTS1);
358 
359 	fd = open(FULLPATH, O_RDWR);
360 	ASSERT_LE(0, fd) << strerror(errno);
361 
362 	// Prime cache
363 	ASSERT_EQ(bufsize, read(fd, readbuf, bufsize)) << strerror(errno);
364 
365 	// Write directly, evicting cache
366 	ASSERT_EQ(0, fcntl(fd, F_SETFL, O_DIRECT)) << strerror(errno);
367 	ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)) << strerror(errno);
368 	ASSERT_EQ(bufsize, write(fd, CONTENTS1, bufsize)) << strerror(errno);
369 
370 	// Read again.  Cache should be bypassed
371 	expect_read(ino, 0, bufsize, bufsize, CONTENTS1);
372 	ASSERT_EQ(0, fcntl(fd, F_SETFL, 0)) << strerror(errno);
373 	ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)) << strerror(errno);
374 	ASSERT_EQ(bufsize, read(fd, readbuf, bufsize)) << strerror(errno);
375 	ASSERT_STREQ(readbuf, CONTENTS1);
376 
377 	leak(fd);
378 }
379 
380 /*
381  * If the server doesn't return FOPEN_DIRECT_IO during FUSE_OPEN, then it's not
382  * allowed to return a short write for that file handle.  However, if it does
383  * then we should still do our darndest to handle it by resending the unwritten
384  * portion.
385  */
386 TEST_F(Write, indirect_io_short_write)
387 {
388 	const char FULLPATH[] = "mountpoint/some_file.txt";
389 	const char RELPATH[] = "some_file.txt";
390 	const char *CONTENTS = "abcdefghijklmnop";
391 	uint64_t ino = 42;
392 	int fd;
393 	ssize_t bufsize = strlen(CONTENTS);
394 	ssize_t bufsize0 = 11;
395 	ssize_t bufsize1 = strlen(CONTENTS) - bufsize0;
396 	const char *contents1 = CONTENTS + bufsize0;
397 
398 	expect_lookup(RELPATH, ino, 0);
399 	expect_open(ino, 0, 1);
400 	expect_write(ino, 0, bufsize, bufsize0, CONTENTS);
401 	expect_write(ino, bufsize0, bufsize1, bufsize1, contents1);
402 
403 	fd = open(FULLPATH, O_WRONLY);
404 	ASSERT_LE(0, fd) << strerror(errno);
405 
406 	ASSERT_EQ(bufsize, write(fd, CONTENTS, bufsize)) << strerror(errno);
407 	leak(fd);
408 }
409 
410 /*
411  * When the direct_io option is used, filesystems are allowed to write less
412  * data than requested.  We should return the short write to userland.
413  */
414 TEST_F(Write, direct_io_short_write)
415 {
416 	const char FULLPATH[] = "mountpoint/some_file.txt";
417 	const char RELPATH[] = "some_file.txt";
418 	const char *CONTENTS = "abcdefghijklmnop";
419 	uint64_t ino = 42;
420 	int fd;
421 	ssize_t bufsize = strlen(CONTENTS);
422 	ssize_t halfbufsize = bufsize / 2;
423 
424 	expect_lookup(RELPATH, ino, 0);
425 	expect_open(ino, FOPEN_DIRECT_IO, 1);
426 	expect_write(ino, 0, bufsize, halfbufsize, CONTENTS);
427 
428 	fd = open(FULLPATH, O_WRONLY);
429 	ASSERT_LE(0, fd) << strerror(errno);
430 
431 	ASSERT_EQ(halfbufsize, write(fd, CONTENTS, bufsize)) << strerror(errno);
432 	leak(fd);
433 }
434 
435 /*
436  * An insidious edge case: the filesystem returns a short write, and the
437  * difference between what we requested and what it actually wrote crosses an
438  * iov element boundary
439  */
440 TEST_F(Write, direct_io_short_write_iov)
441 {
442 	const char FULLPATH[] = "mountpoint/some_file.txt";
443 	const char RELPATH[] = "some_file.txt";
444 	const char *CONTENTS0 = "abcdefgh";
445 	const char *CONTENTS1 = "ijklmnop";
446 	const char *EXPECTED0 = "abcdefghijklmnop";
447 	uint64_t ino = 42;
448 	int fd;
449 	ssize_t size0 = strlen(CONTENTS0) - 1;
450 	ssize_t size1 = strlen(CONTENTS1) + 1;
451 	ssize_t totalsize = size0 + size1;
452 	struct iovec iov[2];
453 
454 	expect_lookup(RELPATH, ino, 0);
455 	expect_open(ino, FOPEN_DIRECT_IO, 1);
456 	expect_write(ino, 0, totalsize, size0, EXPECTED0);
457 
458 	fd = open(FULLPATH, O_WRONLY);
459 	ASSERT_LE(0, fd) << strerror(errno);
460 
461 	iov[0].iov_base = __DECONST(void*, CONTENTS0);
462 	iov[0].iov_len = strlen(CONTENTS0);
463 	iov[1].iov_base = __DECONST(void*, CONTENTS1);
464 	iov[1].iov_len = strlen(CONTENTS1);
465 	ASSERT_EQ(size0, writev(fd, iov, 2)) << strerror(errno);
466 	leak(fd);
467 }
468 
469 /* fusefs should respect RLIMIT_FSIZE */
470 TEST_F(Write, rlimit_fsize)
471 {
472 	const char FULLPATH[] = "mountpoint/some_file.txt";
473 	const char RELPATH[] = "some_file.txt";
474 	const char *CONTENTS = "abcdefgh";
475 	struct rlimit rl;
476 	ssize_t bufsize = strlen(CONTENTS);
477 	off_t offset = 1'000'000'000;
478 	uint64_t ino = 42;
479 	int fd;
480 
481 	expect_lookup(RELPATH, ino, 0);
482 	expect_open(ino, 0, 1);
483 
484 	rl.rlim_cur = offset;
485 	rl.rlim_max = 10 * offset;
486 	ASSERT_EQ(0, setrlimit(RLIMIT_FSIZE, &rl)) << strerror(errno);
487 	ASSERT_NE(SIG_ERR, signal(SIGXFSZ, sigxfsz_handler)) << strerror(errno);
488 
489 	fd = open(FULLPATH, O_WRONLY);
490 
491 	ASSERT_LE(0, fd) << strerror(errno);
492 
493 	ASSERT_EQ(-1, pwrite(fd, CONTENTS, bufsize, offset));
494 	EXPECT_EQ(EFBIG, errno);
495 	EXPECT_EQ(1, s_sigxfsz);
496 	leak(fd);
497 }
498 
499 /*
500  * A short read indicates EOF.  Test that nothing bad happens if we get EOF
501  * during the R of a RMW operation.
502  */
503 TEST_F(Write, eof_during_rmw)
504 {
505 	const char FULLPATH[] = "mountpoint/some_file.txt";
506 	const char RELPATH[] = "some_file.txt";
507 	const char *CONTENTS = "abcdefgh";
508 	const char *INITIAL   = "XXXXXXXXXX";
509 	uint64_t ino = 42;
510 	uint64_t offset = 1;
511 	ssize_t bufsize = strlen(CONTENTS);
512 	off_t orig_fsize = 10;
513 	off_t truncated_fsize = 5;
514 	off_t final_fsize = bufsize;
515 	int fd;
516 
517 	FuseTest::expect_lookup(RELPATH, ino, S_IFREG | 0644, orig_fsize, 1);
518 	expect_open(ino, 0, 1);
519 	expect_read(ino, 0, orig_fsize, truncated_fsize, INITIAL, O_RDWR);
520 	expect_getattr(ino, truncated_fsize);
521 	expect_read(ino, 0, final_fsize, final_fsize, INITIAL, O_RDWR);
522 	maybe_expect_write(ino, offset, bufsize, CONTENTS);
523 
524 	fd = open(FULLPATH, O_RDWR);
525 	ASSERT_LE(0, fd) << strerror(errno);
526 
527 	ASSERT_EQ(bufsize, pwrite(fd, CONTENTS, bufsize, offset))
528 		<< strerror(errno);
529 	leak(fd);
530 }
531 
532 /*
533  * If the kernel cannot be sure which uid, gid, or pid was responsible for a
534  * write, then it must set the FUSE_WRITE_CACHE bit
535  */
536 /* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236378 */
537 TEST_F(Write, mmap)
538 {
539 	const char FULLPATH[] = "mountpoint/some_file.txt";
540 	const char RELPATH[] = "some_file.txt";
541 	const char *CONTENTS = "abcdefgh";
542 	uint64_t ino = 42;
543 	int fd;
544 	ssize_t bufsize = strlen(CONTENTS);
545 	void *p;
546 	uint64_t offset = 10;
547 	size_t len;
548 	void *zeros, *expected;
549 
550 	len = getpagesize();
551 
552 	zeros = calloc(1, len);
553 	ASSERT_NE(nullptr, zeros);
554 	expected = calloc(1, len);
555 	ASSERT_NE(nullptr, expected);
556 	memmove((uint8_t*)expected + offset, CONTENTS, bufsize);
557 
558 	expect_lookup(RELPATH, ino, len);
559 	expect_open(ino, 0, 1);
560 	expect_read(ino, 0, len, len, zeros);
561 	/*
562 	 * Writes from the pager may or may not be associated with the correct
563 	 * pid, so they must set FUSE_WRITE_CACHE.
564 	 */
565 	FuseTest::expect_write(ino, 0, len, len, FUSE_WRITE_CACHE, 0, expected);
566 	expect_flush(ino, 1, ReturnErrno(0));
567 	expect_release(ino, ReturnErrno(0));
568 
569 	fd = open(FULLPATH, O_RDWR);
570 	ASSERT_LE(0, fd) << strerror(errno);
571 
572 	p = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
573 	ASSERT_NE(MAP_FAILED, p) << strerror(errno);
574 
575 	memmove((uint8_t*)p + offset, CONTENTS, bufsize);
576 
577 	ASSERT_EQ(0, munmap(p, len)) << strerror(errno);
578 	close(fd);	// Write mmap'd data on close
579 
580 	free(expected);
581 	free(zeros);
582 
583 	leak(fd);
584 }
585 
586 TEST_F(Write, pwrite)
587 {
588 	const char FULLPATH[] = "mountpoint/some_file.txt";
589 	const char RELPATH[] = "some_file.txt";
590 	const char *CONTENTS = "abcdefgh";
591 	uint64_t ino = 42;
592 	uint64_t offset = m_maxbcachebuf;
593 	int fd;
594 	ssize_t bufsize = strlen(CONTENTS);
595 
596 	expect_lookup(RELPATH, ino, 0);
597 	expect_open(ino, 0, 1);
598 	expect_write(ino, offset, bufsize, bufsize, CONTENTS);
599 
600 	fd = open(FULLPATH, O_WRONLY);
601 	ASSERT_LE(0, fd) << strerror(errno);
602 
603 	ASSERT_EQ(bufsize, pwrite(fd, CONTENTS, bufsize, offset))
604 		<< strerror(errno);
605 	leak(fd);
606 }
607 
608 /* Writing a file should update its cached mtime and ctime */
609 TEST_F(Write, timestamps)
610 {
611 	const char FULLPATH[] = "mountpoint/some_file.txt";
612 	const char RELPATH[] = "some_file.txt";
613 	const char *CONTENTS = "abcdefgh";
614 	ssize_t bufsize = strlen(CONTENTS);
615 	uint64_t ino = 42;
616 	struct stat sb0, sb1;
617 	int fd;
618 
619 	expect_lookup(RELPATH, ino, 0);
620 	expect_open(ino, 0, 1);
621 	maybe_expect_write(ino, 0, bufsize, CONTENTS);
622 
623 	fd = open(FULLPATH, O_RDWR);
624 	ASSERT_LE(0, fd) << strerror(errno);
625 	ASSERT_EQ(0, fstat(fd, &sb0)) << strerror(errno);
626 	ASSERT_EQ(bufsize, write(fd, CONTENTS, bufsize)) << strerror(errno);
627 
628 	nap();
629 
630 	ASSERT_EQ(0, fstat(fd, &sb1)) << strerror(errno);
631 
632 	EXPECT_EQ(sb0.st_atime, sb1.st_atime);
633 	EXPECT_NE(sb0.st_mtime, sb1.st_mtime);
634 	EXPECT_NE(sb0.st_ctime, sb1.st_ctime);
635 
636 	leak(fd);
637 }
638 
639 TEST_F(Write, write)
640 {
641 	const char FULLPATH[] = "mountpoint/some_file.txt";
642 	const char RELPATH[] = "some_file.txt";
643 	const char *CONTENTS = "abcdefgh";
644 	uint64_t ino = 42;
645 	int fd;
646 	ssize_t bufsize = strlen(CONTENTS);
647 
648 	expect_lookup(RELPATH, ino, 0);
649 	expect_open(ino, 0, 1);
650 	expect_write(ino, 0, bufsize, bufsize, CONTENTS);
651 
652 	fd = open(FULLPATH, O_WRONLY);
653 	ASSERT_LE(0, fd) << strerror(errno);
654 
655 	ASSERT_EQ(bufsize, write(fd, CONTENTS, bufsize)) << strerror(errno);
656 	leak(fd);
657 }
658 
659 /* fuse(4) should not issue writes of greater size than the daemon requests */
660 TEST_F(WriteMaxWrite, write)
661 {
662 	const char FULLPATH[] = "mountpoint/some_file.txt";
663 	const char RELPATH[] = "some_file.txt";
664 	int *contents;
665 	uint64_t ino = 42;
666 	int fd;
667 	ssize_t halfbufsize, bufsize;
668 
669 	halfbufsize = m_mock->m_maxwrite;
670 	if (halfbufsize >= m_maxbcachebuf || halfbufsize >= m_maxphys)
671 		GTEST_SKIP() << "Must lower m_maxwrite for this test";
672 	bufsize = halfbufsize * 2;
673 	contents = (int*)malloc(bufsize);
674 	ASSERT_NE(nullptr, contents);
675 	for (int i = 0; i < (int)bufsize / (int)sizeof(i); i++) {
676 		contents[i] = i;
677 	}
678 
679 	expect_lookup(RELPATH, ino, 0);
680 	expect_open(ino, 0, 1);
681 	maybe_expect_write(ino, 0, halfbufsize, contents);
682 	maybe_expect_write(ino, halfbufsize, halfbufsize,
683 		&contents[halfbufsize / sizeof(int)]);
684 
685 	fd = open(FULLPATH, O_WRONLY);
686 	ASSERT_LE(0, fd) << strerror(errno);
687 
688 	ASSERT_EQ(bufsize, write(fd, contents, bufsize)) << strerror(errno);
689 	leak(fd);
690 
691 	free(contents);
692 }
693 
694 TEST_F(Write, write_nothing)
695 {
696 	const char FULLPATH[] = "mountpoint/some_file.txt";
697 	const char RELPATH[] = "some_file.txt";
698 	const char *CONTENTS = "";
699 	uint64_t ino = 42;
700 	int fd;
701 	ssize_t bufsize = 0;
702 
703 	expect_lookup(RELPATH, ino, 0);
704 	expect_open(ino, 0, 1);
705 
706 	fd = open(FULLPATH, O_WRONLY);
707 	ASSERT_LE(0, fd) << strerror(errno);
708 
709 	ASSERT_EQ(bufsize, write(fd, CONTENTS, bufsize)) << strerror(errno);
710 	leak(fd);
711 }
712 
713 TEST_F(Write_7_8, write)
714 {
715 	const char FULLPATH[] = "mountpoint/some_file.txt";
716 	const char RELPATH[] = "some_file.txt";
717 	const char *CONTENTS = "abcdefgh";
718 	uint64_t ino = 42;
719 	int fd;
720 	ssize_t bufsize = strlen(CONTENTS);
721 
722 	expect_lookup(RELPATH, ino, 0);
723 	expect_open(ino, 0, 1);
724 	expect_write_7_8(ino, 0, bufsize, bufsize, CONTENTS);
725 
726 	fd = open(FULLPATH, O_WRONLY);
727 	ASSERT_LE(0, fd) << strerror(errno);
728 
729 	ASSERT_EQ(bufsize, write(fd, CONTENTS, bufsize)) << strerror(errno);
730 	leak(fd);
731 }
732 
733 /* In writeback mode, dirty data should be written on close */
734 TEST_F(WriteBackAsync, close)
735 {
736 	const char FULLPATH[] = "mountpoint/some_file.txt";
737 	const char RELPATH[] = "some_file.txt";
738 	const char *CONTENTS = "abcdefgh";
739 	uint64_t ino = 42;
740 	int fd;
741 	ssize_t bufsize = strlen(CONTENTS);
742 
743 	expect_lookup(RELPATH, ino, 0);
744 	expect_open(ino, 0, 1);
745 	expect_write(ino, 0, bufsize, bufsize, CONTENTS);
746 	EXPECT_CALL(*m_mock, process(
747 		ResultOf([=](auto in) {
748 			return (in.header.opcode == FUSE_SETATTR);
749 		}, Eq(true)),
750 		_)
751 	).WillRepeatedly(Invoke(ReturnImmediate([=](auto i __unused, auto& out) {
752 		SET_OUT_HEADER_LEN(out, attr);
753 		out.body.attr.attr.ino = ino;	// Must match nodeid
754 	})));
755 	expect_flush(ino, 1, ReturnErrno(0));
756 	expect_release(ino, ReturnErrno(0));
757 
758 	fd = open(FULLPATH, O_RDWR);
759 	ASSERT_LE(0, fd) << strerror(errno);
760 
761 	ASSERT_EQ(bufsize, write(fd, CONTENTS, bufsize)) << strerror(errno);
762 	close(fd);
763 }
764 
765 /* In writeback mode, adjacent writes will be clustered together */
766 TEST_F(WriteCluster, clustering)
767 {
768 	const char FULLPATH[] = "mountpoint/some_file.txt";
769 	const char RELPATH[] = "some_file.txt";
770 	uint64_t ino = 42;
771 	int i, fd;
772 	void *wbuf, *wbuf2x;
773 	ssize_t bufsize = m_maxbcachebuf;
774 	off_t filesize = 5 * bufsize;
775 
776 	wbuf = malloc(bufsize);
777 	ASSERT_NE(nullptr, wbuf) << strerror(errno);
778 	memset(wbuf, 'X', bufsize);
779 	wbuf2x = malloc(2 * bufsize);
780 	ASSERT_NE(nullptr, wbuf2x) << strerror(errno);
781 	memset(wbuf2x, 'X', 2 * bufsize);
782 
783 	expect_lookup(RELPATH, ino, filesize);
784 	expect_open(ino, 0, 1);
785 	/*
786 	 * Writes of bufsize-bytes each should be clustered into greater sizes.
787 	 * The amount of clustering is adaptive, so the first write actually
788 	 * issued will be 2x bufsize and subsequent writes may be larger
789 	 */
790 	expect_write(ino, 0, 2 * bufsize, 2 * bufsize, wbuf2x);
791 	expect_write(ino, 2 * bufsize, 2 * bufsize, 2 * bufsize, wbuf2x);
792 	expect_flush(ino, 1, ReturnErrno(0));
793 	expect_release(ino, ReturnErrno(0));
794 
795 	fd = open(FULLPATH, O_RDWR);
796 	ASSERT_LE(0, fd) << strerror(errno);
797 
798 	for (i = 0; i < 4; i++) {
799 		ASSERT_EQ(bufsize, write(fd, wbuf, bufsize))
800 			<< strerror(errno);
801 	}
802 	close(fd);
803 	free(wbuf2x);
804 	free(wbuf);
805 }
806 
807 /*
808  * When clustering writes, an I/O error to any of the cluster's children should
809  * not panic the system on unmount
810  */
811 /*
812  * Disabled because it panics.
813  * https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=238565
814  */
815 TEST_F(WriteCluster, DISABLED_cluster_write_err)
816 {
817 	const char FULLPATH[] = "mountpoint/some_file.txt";
818 	const char RELPATH[] = "some_file.txt";
819 	uint64_t ino = 42;
820 	int i, fd;
821 	void *wbuf;
822 	ssize_t bufsize = m_maxbcachebuf;
823 	off_t filesize = 4 * bufsize;
824 
825 	wbuf = malloc(bufsize);
826 	ASSERT_NE(nullptr, wbuf) << strerror(errno);
827 	memset(wbuf, 'X', bufsize);
828 
829 	expect_lookup(RELPATH, ino, filesize);
830 	expect_open(ino, 0, 1);
831 	EXPECT_CALL(*m_mock, process(
832 		ResultOf([=](auto in) {
833 			return (in.header.opcode == FUSE_WRITE);
834 		}, Eq(true)),
835 		_)
836 	).WillRepeatedly(Invoke(ReturnErrno(EIO)));
837 	expect_flush(ino, 1, ReturnErrno(0));
838 	expect_release(ino, ReturnErrno(0));
839 
840 	fd = open(FULLPATH, O_RDWR);
841 	ASSERT_LE(0, fd) << strerror(errno);
842 
843 	for (i = 0; i < 3; i++) {
844 		ASSERT_EQ(bufsize, write(fd, wbuf, bufsize))
845 			<< strerror(errno);
846 	}
847 	close(fd);
848 	free(wbuf);
849 }
850 
851 /*
852  * In writeback mode, writes to an O_WRONLY file could trigger reads from the
853  * server.  The FUSE protocol explicitly allows that.
854  */
855 TEST_F(WriteBack, rmw)
856 {
857 	const char FULLPATH[] = "mountpoint/some_file.txt";
858 	const char RELPATH[] = "some_file.txt";
859 	const char *CONTENTS = "abcdefgh";
860 	const char *INITIAL   = "XXXXXXXXXX";
861 	uint64_t ino = 42;
862 	uint64_t offset = 1;
863 	off_t fsize = 10;
864 	int fd;
865 	ssize_t bufsize = strlen(CONTENTS);
866 
867 	FuseTest::expect_lookup(RELPATH, ino, S_IFREG | 0644, fsize, 1);
868 	expect_open(ino, 0, 1);
869 	expect_read(ino, 0, fsize, fsize, INITIAL, O_WRONLY);
870 	maybe_expect_write(ino, offset, bufsize, CONTENTS);
871 
872 	fd = open(FULLPATH, O_WRONLY);
873 	ASSERT_LE(0, fd) << strerror(errno);
874 
875 	ASSERT_EQ(bufsize, pwrite(fd, CONTENTS, bufsize, offset))
876 		<< strerror(errno);
877 	leak(fd);
878 }
879 
880 /*
881  * Without direct_io, writes should be committed to cache
882  */
883 TEST_F(WriteBack, cache)
884 {
885 	const char FULLPATH[] = "mountpoint/some_file.txt";
886 	const char RELPATH[] = "some_file.txt";
887 	const char *CONTENTS = "abcdefgh";
888 	uint64_t ino = 42;
889 	int fd;
890 	ssize_t bufsize = strlen(CONTENTS);
891 	uint8_t readbuf[bufsize];
892 
893 	expect_lookup(RELPATH, ino, 0);
894 	expect_open(ino, 0, 1);
895 	expect_write(ino, 0, bufsize, bufsize, CONTENTS);
896 
897 	fd = open(FULLPATH, O_RDWR);
898 	ASSERT_LE(0, fd) << strerror(errno);
899 
900 	ASSERT_EQ(bufsize, write(fd, CONTENTS, bufsize)) << strerror(errno);
901 	/*
902 	 * A subsequent read should be serviced by cache, without querying the
903 	 * filesystem daemon
904 	 */
905 	ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)) << strerror(errno);
906 	ASSERT_EQ(bufsize, read(fd, readbuf, bufsize)) << strerror(errno);
907 	leak(fd);
908 }
909 
910 /*
911  * With O_DIRECT, writes should be not committed to cache.  Admittedly this is
912  * an odd test, because it would be unusual to use O_DIRECT for writes but not
913  * reads.
914  */
915 TEST_F(WriteBack, o_direct)
916 {
917 	const char FULLPATH[] = "mountpoint/some_file.txt";
918 	const char RELPATH[] = "some_file.txt";
919 	const char *CONTENTS = "abcdefgh";
920 	uint64_t ino = 42;
921 	int fd;
922 	ssize_t bufsize = strlen(CONTENTS);
923 	uint8_t readbuf[bufsize];
924 
925 	expect_lookup(RELPATH, ino, 0);
926 	expect_open(ino, 0, 1);
927 	FuseTest::expect_write(ino, 0, bufsize, bufsize, 0, FUSE_WRITE_CACHE,
928 		CONTENTS);
929 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
930 
931 	fd = open(FULLPATH, O_RDWR | O_DIRECT);
932 	ASSERT_LE(0, fd) << strerror(errno);
933 
934 	ASSERT_EQ(bufsize, write(fd, CONTENTS, bufsize)) << strerror(errno);
935 	/* A subsequent read must query the daemon because cache is empty */
936 	ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)) << strerror(errno);
937 	ASSERT_EQ(0, fcntl(fd, F_SETFL, 0)) << strerror(errno);
938 	ASSERT_EQ(bufsize, read(fd, readbuf, bufsize)) << strerror(errno);
939 	leak(fd);
940 }
941 
942 TEST_F(WriteBack, direct_io)
943 {
944 	const char FULLPATH[] = "mountpoint/some_file.txt";
945 	const char RELPATH[] = "some_file.txt";
946 	const char *CONTENTS = "abcdefgh";
947 	uint64_t ino = 42;
948 	int fd;
949 	ssize_t bufsize = strlen(CONTENTS);
950 	uint8_t readbuf[bufsize];
951 
952 	expect_lookup(RELPATH, ino, 0);
953 	expect_open(ino, FOPEN_DIRECT_IO, 1);
954 	FuseTest::expect_write(ino, 0, bufsize, bufsize, 0, FUSE_WRITE_CACHE,
955 		CONTENTS);
956 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
957 
958 	fd = open(FULLPATH, O_RDWR);
959 	ASSERT_LE(0, fd) << strerror(errno);
960 
961 	ASSERT_EQ(bufsize, write(fd, CONTENTS, bufsize)) << strerror(errno);
962 	/* A subsequent read must query the daemon because cache is empty */
963 	ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)) << strerror(errno);
964 	ASSERT_EQ(0, fcntl(fd, F_SETFL, 0)) << strerror(errno);
965 	ASSERT_EQ(bufsize, read(fd, readbuf, bufsize)) << strerror(errno);
966 	leak(fd);
967 }
968 
969 /*
970  * mmap should still be possible even if the server used direct_io.  Mmap will
971  * still use the cache, though.
972  *
973  * Regression test for bug 247276
974  * https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=247276
975  */
976 TEST_F(WriteBack, mmap_direct_io)
977 {
978 	const char FULLPATH[] = "mountpoint/some_file.txt";
979 	const char RELPATH[] = "some_file.txt";
980 	const char *CONTENTS = "abcdefgh";
981 	uint64_t ino = 42;
982 	int fd;
983 	size_t len;
984 	ssize_t bufsize = strlen(CONTENTS);
985 	void *p, *zeros;
986 
987 	len = getpagesize();
988 	zeros = calloc(1, len);
989 	ASSERT_NE(nullptr, zeros);
990 
991 	expect_lookup(RELPATH, ino, len);
992 	expect_open(ino, FOPEN_DIRECT_IO, 1);
993 	expect_read(ino, 0, len, len, zeros);
994 	expect_flush(ino, 1, ReturnErrno(0));
995 	FuseTest::expect_write(ino, 0, len, len, FUSE_WRITE_CACHE, 0, zeros);
996 	expect_release(ino, ReturnErrno(0));
997 
998 	fd = open(FULLPATH, O_RDWR);
999 	ASSERT_LE(0, fd) << strerror(errno);
1000 
1001 	p = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1002 	ASSERT_NE(MAP_FAILED, p) << strerror(errno);
1003 
1004 	memmove((uint8_t*)p, CONTENTS, bufsize);
1005 
1006 	ASSERT_EQ(0, munmap(p, len)) << strerror(errno);
1007 	close(fd);	// Write mmap'd data on close
1008 
1009 	free(zeros);
1010 }
1011 
1012 /*
1013  * When mounted with -o async, the writeback cache mode should delay writes
1014  */
1015 TEST_F(WriteBackAsync, delay)
1016 {
1017 	const char FULLPATH[] = "mountpoint/some_file.txt";
1018 	const char RELPATH[] = "some_file.txt";
1019 	const char *CONTENTS = "abcdefgh";
1020 	uint64_t ino = 42;
1021 	int fd;
1022 	ssize_t bufsize = strlen(CONTENTS);
1023 
1024 	expect_lookup(RELPATH, ino, 0);
1025 	expect_open(ino, 0, 1);
1026 	/* Write should be cached, but FUSE_WRITE shouldn't be sent */
1027 	EXPECT_CALL(*m_mock, process(
1028 		ResultOf([=](auto in) {
1029 			return (in.header.opcode == FUSE_WRITE);
1030 		}, Eq(true)),
1031 		_)
1032 	).Times(0);
1033 
1034 	fd = open(FULLPATH, O_RDWR);
1035 	ASSERT_LE(0, fd) << strerror(errno);
1036 
1037 	ASSERT_EQ(bufsize, write(fd, CONTENTS, bufsize)) << strerror(errno);
1038 
1039 	/* Don't close the file because that would flush the cache */
1040 	leak(fd);
1041 }
1042 
1043 /*
1044  * A direct write should not evict dirty cached data from outside of its own
1045  * byte range.
1046  */
1047 TEST_F(WriteBackAsync, direct_io_ignores_unrelated_cached)
1048 {
1049 	const char FULLPATH[] = "mountpoint/some_file.txt";
1050 	const char RELPATH[] = "some_file.txt";
1051 	const char CONTENTS0[] = "abcdefgh";
1052 	const char CONTENTS1[] = "ijklmnop";
1053 	uint64_t ino = 42;
1054 	int fd;
1055 	ssize_t bufsize = strlen(CONTENTS0) + 1;
1056 	ssize_t fsize = 2 * m_maxbcachebuf;
1057 	char readbuf[bufsize];
1058 	void *zeros;
1059 
1060 	zeros = calloc(1, m_maxbcachebuf);
1061 	ASSERT_NE(nullptr, zeros);
1062 
1063 	expect_lookup(RELPATH, ino, fsize);
1064 	expect_open(ino, 0, 1);
1065 	expect_read(ino, 0, m_maxbcachebuf, m_maxbcachebuf, zeros);
1066 	FuseTest::expect_write(ino, m_maxbcachebuf, bufsize, bufsize, 0, 0,
1067 		CONTENTS1);
1068 
1069 	fd = open(FULLPATH, O_RDWR);
1070 	ASSERT_LE(0, fd) << strerror(errno);
1071 
1072 	// Cache first block with dirty data.  This will entail first reading
1073 	// the existing data.
1074 	ASSERT_EQ(bufsize, pwrite(fd, CONTENTS0, bufsize, 0))
1075 		<< strerror(errno);
1076 
1077 	// Write directly to second block
1078 	ASSERT_EQ(0, fcntl(fd, F_SETFL, O_DIRECT)) << strerror(errno);
1079 	ASSERT_EQ(bufsize, pwrite(fd, CONTENTS1, bufsize, m_maxbcachebuf))
1080 		<< strerror(errno);
1081 
1082 	// Read from the first block again.  Should be serviced by cache.
1083 	ASSERT_EQ(0, fcntl(fd, F_SETFL, 0)) << strerror(errno);
1084 	ASSERT_EQ(bufsize, pread(fd, readbuf, bufsize, 0)) << strerror(errno);
1085 	ASSERT_STREQ(readbuf, CONTENTS0);
1086 
1087 	leak(fd);
1088 	free(zeros);
1089 }
1090 
1091 /*
1092  * If a direct io write partially overlaps one or two blocks of dirty cached
1093  * data, No dirty data should be lost.  Admittedly this is a weird test,
1094  * because it would be unusual to use O_DIRECT and the writeback cache.
1095  */
1096 TEST_F(WriteBackAsync, direct_io_partially_overlaps_cached_block)
1097 {
1098 	const char FULLPATH[] = "mountpoint/some_file.txt";
1099 	const char RELPATH[] = "some_file.txt";
1100 	uint64_t ino = 42;
1101 	int fd;
1102 	off_t bs = m_maxbcachebuf;
1103 	ssize_t fsize = 3 * bs;
1104 	void *readbuf, *zeros, *ones, *zeroones, *onezeros;
1105 
1106 	readbuf = malloc(bs);
1107 	ASSERT_NE(nullptr, readbuf) << strerror(errno);
1108 	zeros = calloc(1, 3 * bs);
1109 	ASSERT_NE(nullptr, zeros);
1110 	ones = calloc(1, 2 * bs);
1111 	ASSERT_NE(nullptr, ones);
1112 	memset(ones, 1, 2 * bs);
1113 	zeroones = calloc(1, bs);
1114 	ASSERT_NE(nullptr, zeroones);
1115 	memset((uint8_t*)zeroones + bs / 2, 1, bs / 2);
1116 	onezeros = calloc(1, bs);
1117 	ASSERT_NE(nullptr, onezeros);
1118 	memset(onezeros, 1, bs / 2);
1119 
1120 	expect_lookup(RELPATH, ino, fsize);
1121 	expect_open(ino, 0, 1);
1122 
1123 	fd = open(FULLPATH, O_RDWR);
1124 	ASSERT_LE(0, fd) << strerror(errno);
1125 
1126 	/* Cache first and third blocks with dirty data.  */
1127 	ASSERT_EQ(3 * bs, pwrite(fd, zeros, 3 * bs, 0)) << strerror(errno);
1128 
1129 	/*
1130 	 * Write directly to all three blocks.  The partially written blocks
1131 	 * will be flushed because they're dirty.
1132 	 */
1133 	FuseTest::expect_write(ino, 0, bs, bs, 0, 0, zeros);
1134 	FuseTest::expect_write(ino, 2 * bs, bs, bs, 0, 0, zeros);
1135 	/* The direct write is split in two because of the m_maxwrite value */
1136 	FuseTest::expect_write(ino,     bs / 2, bs, bs, 0, 0, ones);
1137 	FuseTest::expect_write(ino, 3 * bs / 2, bs, bs, 0, 0, ones);
1138 	ASSERT_EQ(0, fcntl(fd, F_SETFL, O_DIRECT)) << strerror(errno);
1139 	ASSERT_EQ(2 * bs, pwrite(fd, ones, 2 * bs, bs / 2)) << strerror(errno);
1140 
1141 	/*
1142 	 * Read from both the valid and invalid portions of the first and third
1143 	 * blocks again.  This will entail FUSE_READ operations because these
1144 	 * blocks were invalidated by the direct write.
1145 	 */
1146 	expect_read(ino, 0, bs, bs, zeroones);
1147 	expect_read(ino, 2 * bs, bs, bs, onezeros);
1148 	ASSERT_EQ(0, fcntl(fd, F_SETFL, 0)) << strerror(errno);
1149 	ASSERT_EQ(bs / 2, pread(fd, readbuf, bs / 2, 0)) << strerror(errno);
1150 	EXPECT_EQ(0, memcmp(zeros, readbuf, bs / 2));
1151 	ASSERT_EQ(bs / 2, pread(fd, readbuf, bs / 2, 5 * bs / 2))
1152 		<< strerror(errno);
1153 	EXPECT_EQ(0, memcmp(zeros, readbuf, bs / 2));
1154 	ASSERT_EQ(bs / 2, pread(fd, readbuf, bs / 2, bs / 2))
1155 		<< strerror(errno);
1156 	EXPECT_EQ(0, memcmp(ones, readbuf, bs / 2));
1157 	ASSERT_EQ(bs / 2, pread(fd, readbuf, bs / 2, 2 * bs))
1158 		<< strerror(errno);
1159 	EXPECT_EQ(0, memcmp(ones, readbuf, bs / 2));
1160 
1161 	leak(fd);
1162 	free(zeroones);
1163 	free(onezeros);
1164 	free(ones);
1165 	free(zeros);
1166 	free(readbuf);
1167 }
1168 
1169 /*
1170  * In WriteBack mode, writes may be cached beyond what the server thinks is the
1171  * EOF.  In this case, a short read at EOF should _not_ cause fusefs to update
1172  * the file's size.
1173  */
1174 TEST_F(WriteBackAsync, eof)
1175 {
1176 	const char FULLPATH[] = "mountpoint/some_file.txt";
1177 	const char RELPATH[] = "some_file.txt";
1178 	const char *CONTENTS0 = "abcdefgh";
1179 	const char *CONTENTS1 = "ijklmnop";
1180 	uint64_t ino = 42;
1181 	int fd;
1182 	off_t offset = m_maxbcachebuf;
1183 	ssize_t wbufsize = strlen(CONTENTS1);
1184 	off_t old_filesize = (off_t)strlen(CONTENTS0);
1185 	ssize_t rbufsize = 2 * old_filesize;
1186 	char readbuf[rbufsize];
1187 	size_t holesize = rbufsize - old_filesize;
1188 	char hole[holesize];
1189 	struct stat sb;
1190 	ssize_t r;
1191 
1192 	expect_lookup(RELPATH, ino, 0);
1193 	expect_open(ino, 0, 1);
1194 	expect_read(ino, 0, m_maxbcachebuf, old_filesize, CONTENTS0);
1195 
1196 	fd = open(FULLPATH, O_RDWR);
1197 	ASSERT_LE(0, fd) << strerror(errno);
1198 
1199 	/* Write and cache data beyond EOF */
1200 	ASSERT_EQ(wbufsize, pwrite(fd, CONTENTS1, wbufsize, offset))
1201 		<< strerror(errno);
1202 
1203 	/* Read from the old EOF */
1204 	r = pread(fd, readbuf, rbufsize, 0);
1205 	ASSERT_LE(0, r) << strerror(errno);
1206 	EXPECT_EQ(rbufsize, r) << "read should've synthesized a hole";
1207 	EXPECT_EQ(0, memcmp(CONTENTS0, readbuf, old_filesize));
1208 	bzero(hole, holesize);
1209 	EXPECT_EQ(0, memcmp(hole, readbuf + old_filesize, holesize));
1210 
1211 	/* The file's size should still be what was established by pwrite */
1212 	ASSERT_EQ(0, fstat(fd, &sb)) << strerror(errno);
1213 	EXPECT_EQ(offset + wbufsize, sb.st_size);
1214 	leak(fd);
1215 }
1216 
1217 /*
1218  * When a file has dirty writes that haven't been flushed, the server's notion
1219  * of its mtime and ctime will be wrong.  The kernel should ignore those if it
1220  * gets them from a FUSE_GETATTR before flushing.
1221  */
1222 TEST_F(WriteBackAsync, timestamps)
1223 {
1224 	const char FULLPATH[] = "mountpoint/some_file.txt";
1225 	const char RELPATH[] = "some_file.txt";
1226 	const char *CONTENTS = "abcdefgh";
1227 	ssize_t bufsize = strlen(CONTENTS);
1228 	uint64_t ino = 42;
1229 	uint64_t attr_valid = 0;
1230 	uint64_t attr_valid_nsec = 0;
1231 	uint64_t server_time = 12345;
1232 	mode_t mode = S_IFREG | 0644;
1233 	int fd;
1234 
1235 	struct stat sb;
1236 
1237 	EXPECT_LOOKUP(FUSE_ROOT_ID, RELPATH)
1238 	.WillRepeatedly(Invoke(
1239 		ReturnImmediate([=](auto in __unused, auto& out) {
1240 		SET_OUT_HEADER_LEN(out, entry);
1241 		out.body.entry.attr.mode = mode;
1242 		out.body.entry.nodeid = ino;
1243 		out.body.entry.attr.nlink = 1;
1244 		out.body.entry.attr_valid = attr_valid;
1245 		out.body.entry.attr_valid_nsec = attr_valid_nsec;
1246 	})));
1247 	expect_open(ino, 0, 1);
1248 	EXPECT_CALL(*m_mock, process(
1249 		ResultOf([=](auto in) {
1250 			return (in.header.opcode == FUSE_GETATTR &&
1251 				in.header.nodeid == ino);
1252 		}, Eq(true)),
1253 		_)
1254 	).WillRepeatedly(Invoke(
1255 	ReturnImmediate([=](auto i __unused, auto& out) {
1256 		SET_OUT_HEADER_LEN(out, attr);
1257 		out.body.attr.attr.ino = ino;
1258 		out.body.attr.attr.mode = mode;
1259 		out.body.attr.attr_valid = attr_valid;
1260 		out.body.attr.attr_valid_nsec = attr_valid_nsec;
1261 		out.body.attr.attr.atime = server_time;
1262 		out.body.attr.attr.mtime = server_time;
1263 		out.body.attr.attr.ctime = server_time;
1264 	})));
1265 
1266 	fd = open(FULLPATH, O_RDWR);
1267 	ASSERT_LE(0, fd) << strerror(errno);
1268 	ASSERT_EQ(bufsize, write(fd, CONTENTS, bufsize)) << strerror(errno);
1269 
1270 	ASSERT_EQ(0, fstat(fd, &sb)) << strerror(errno);
1271 	EXPECT_EQ((time_t)server_time, sb.st_atime);
1272 	EXPECT_NE((time_t)server_time, sb.st_mtime);
1273 	EXPECT_NE((time_t)server_time, sb.st_ctime);
1274 
1275 	leak(fd);
1276 }
1277 
1278 /* Any dirty timestamp fields should be flushed during a SETATTR */
1279 TEST_F(WriteBackAsync, timestamps_during_setattr)
1280 {
1281 	const char FULLPATH[] = "mountpoint/some_file.txt";
1282 	const char RELPATH[] = "some_file.txt";
1283 	const char *CONTENTS = "abcdefgh";
1284 	ssize_t bufsize = strlen(CONTENTS);
1285 	uint64_t ino = 42;
1286 	const mode_t newmode = 0755;
1287 	int fd;
1288 
1289 	expect_lookup(RELPATH, ino, 0);
1290 	expect_open(ino, 0, 1);
1291 	EXPECT_CALL(*m_mock, process(
1292 		ResultOf([=](auto in) {
1293 			uint32_t valid = FATTR_MODE | FATTR_MTIME | FATTR_CTIME;
1294 			return (in.header.opcode == FUSE_SETATTR &&
1295 				in.header.nodeid == ino &&
1296 				in.body.setattr.valid == valid);
1297 		}, Eq(true)),
1298 		_)
1299 	).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
1300 		SET_OUT_HEADER_LEN(out, attr);
1301 		out.body.attr.attr.ino = ino;
1302 		out.body.attr.attr.mode = S_IFREG | newmode;
1303 	})));
1304 
1305 	fd = open(FULLPATH, O_RDWR);
1306 	ASSERT_LE(0, fd) << strerror(errno);
1307 	ASSERT_EQ(bufsize, write(fd, CONTENTS, bufsize)) << strerror(errno);
1308 	ASSERT_EQ(0, fchmod(fd, newmode)) << strerror(errno);
1309 
1310 	leak(fd);
1311 }
1312 
1313 /* fuse_init_out.time_gran controls the granularity of timestamps */
1314 TEST_P(TimeGran, timestamps_during_setattr)
1315 {
1316 	const char FULLPATH[] = "mountpoint/some_file.txt";
1317 	const char RELPATH[] = "some_file.txt";
1318 	const char *CONTENTS = "abcdefgh";
1319 	ssize_t bufsize = strlen(CONTENTS);
1320 	uint64_t ino = 42;
1321 	const mode_t newmode = 0755;
1322 	int fd;
1323 
1324 	expect_lookup(RELPATH, ino, 0);
1325 	expect_open(ino, 0, 1);
1326 	EXPECT_CALL(*m_mock, process(
1327 		ResultOf([=](auto in) {
1328 			uint32_t valid = FATTR_MODE | FATTR_MTIME | FATTR_CTIME;
1329 			return (in.header.opcode == FUSE_SETATTR &&
1330 				in.header.nodeid == ino &&
1331 				in.body.setattr.valid == valid &&
1332 				in.body.setattr.mtimensec % m_time_gran == 0 &&
1333 				in.body.setattr.ctimensec % m_time_gran == 0);
1334 		}, Eq(true)),
1335 		_)
1336 	).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
1337 		SET_OUT_HEADER_LEN(out, attr);
1338 		out.body.attr.attr.ino = ino;
1339 		out.body.attr.attr.mode = S_IFREG | newmode;
1340 	})));
1341 
1342 	fd = open(FULLPATH, O_RDWR);
1343 	ASSERT_LE(0, fd) << strerror(errno);
1344 	ASSERT_EQ(bufsize, write(fd, CONTENTS, bufsize)) << strerror(errno);
1345 	ASSERT_EQ(0, fchmod(fd, newmode)) << strerror(errno);
1346 
1347 	leak(fd);
1348 }
1349 
1350 INSTANTIATE_TEST_CASE_P(RA, TimeGran, Range(0u, 10u));
1351 
1352 /*
1353  * Without direct_io, writes should be committed to cache
1354  */
1355 TEST_F(Write, writethrough)
1356 {
1357 	const char FULLPATH[] = "mountpoint/some_file.txt";
1358 	const char RELPATH[] = "some_file.txt";
1359 	const char *CONTENTS = "abcdefgh";
1360 	uint64_t ino = 42;
1361 	int fd;
1362 	ssize_t bufsize = strlen(CONTENTS);
1363 	uint8_t readbuf[bufsize];
1364 
1365 	expect_lookup(RELPATH, ino, 0);
1366 	expect_open(ino, 0, 1);
1367 	expect_write(ino, 0, bufsize, bufsize, CONTENTS);
1368 
1369 	fd = open(FULLPATH, O_RDWR);
1370 	ASSERT_LE(0, fd) << strerror(errno);
1371 
1372 	ASSERT_EQ(bufsize, write(fd, CONTENTS, bufsize)) << strerror(errno);
1373 	/*
1374 	 * A subsequent read should be serviced by cache, without querying the
1375 	 * filesystem daemon
1376 	 */
1377 	ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)) << strerror(errno);
1378 	ASSERT_EQ(bufsize, read(fd, readbuf, bufsize)) << strerror(errno);
1379 	leak(fd);
1380 }
1381 
1382 /* Writes that extend a file should update the cached file size */
1383 TEST_F(Write, update_file_size)
1384 {
1385 	const char FULLPATH[] = "mountpoint/some_file.txt";
1386 	const char RELPATH[] = "some_file.txt";
1387 	const char *CONTENTS = "abcdefgh";
1388 	struct stat sb;
1389 	uint64_t ino = 42;
1390 	int fd;
1391 	ssize_t bufsize = strlen(CONTENTS);
1392 
1393 	expect_lookup(RELPATH, ino, 0);
1394 	expect_open(ino, 0, 1);
1395 	expect_write(ino, 0, bufsize, bufsize, CONTENTS);
1396 
1397 	fd = open(FULLPATH, O_RDWR);
1398 	ASSERT_LE(0, fd) << strerror(errno);
1399 
1400 	ASSERT_EQ(bufsize, write(fd, CONTENTS, bufsize)) << strerror(errno);
1401 	/* Get cached attributes */
1402 	ASSERT_EQ(0, fstat(fd, &sb)) << strerror(errno);
1403 	ASSERT_EQ(bufsize, sb.st_size);
1404 	leak(fd);
1405 }
1406