xref: /freebsd/tests/sys/fs/fusefs/read.cc (revision 315ee00f)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
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 
31 extern "C" {
32 #include <sys/param.h>
33 #include <sys/mman.h>
34 #include <sys/socket.h>
35 #include <sys/sysctl.h>
36 #include <sys/uio.h>
37 
38 #include <aio.h>
39 #include <fcntl.h>
40 #include <semaphore.h>
41 #include <setjmp.h>
42 #include <signal.h>
43 #include <unistd.h>
44 }
45 
46 #include "mockfs.hh"
47 #include "utils.hh"
48 
49 using namespace testing;
50 
51 class Read: public FuseTest {
52 
53 public:
54 void expect_lookup(const char *relpath, uint64_t ino, uint64_t size)
55 {
56 	FuseTest::expect_lookup(relpath, ino, S_IFREG | 0644, size, 1);
57 }
58 };
59 
60 class Read_7_8: public FuseTest {
61 public:
62 virtual void SetUp() {
63 	m_kernel_minor_version = 8;
64 	FuseTest::SetUp();
65 }
66 
67 void expect_lookup(const char *relpath, uint64_t ino, uint64_t size)
68 {
69 	FuseTest::expect_lookup_7_8(relpath, ino, S_IFREG | 0644, size, 1);
70 }
71 };
72 
73 class AioRead: public Read {
74 public:
75 virtual void SetUp() {
76 	if (!is_unsafe_aio_enabled())
77 		GTEST_SKIP() <<
78 			"vfs.aio.enable_unsafe must be set for this test";
79 	FuseTest::SetUp();
80 }
81 };
82 
83 class AsyncRead: public AioRead {
84 	virtual void SetUp() {
85 		m_init_flags = FUSE_ASYNC_READ;
86 		AioRead::SetUp();
87 	}
88 };
89 
90 class ReadAhead: public Read,
91 		 public WithParamInterface<tuple<bool, int>>
92 {
93 	virtual void SetUp() {
94 		int val;
95 		const char *node = "vfs.maxbcachebuf";
96 		size_t size = sizeof(val);
97 		ASSERT_EQ(0, sysctlbyname(node, &val, &size, NULL, 0))
98 			<< strerror(errno);
99 
100 		m_maxreadahead = val * get<1>(GetParam());
101 		m_noclusterr = get<0>(GetParam());
102 		Read::SetUp();
103 	}
104 };
105 
106 class ReadNoatime: public Read {
107 	virtual void SetUp() {
108 		m_noatime = true;
109 		Read::SetUp();
110 	}
111 };
112 
113 class ReadSigbus: public Read
114 {
115 public:
116 static jmp_buf s_jmpbuf;
117 static void *s_si_addr;
118 
119 void TearDown() {
120 	struct sigaction sa;
121 
122 	bzero(&sa, sizeof(sa));
123 	sa.sa_handler = SIG_DFL;
124 	sigaction(SIGBUS, &sa, NULL);
125 
126 	FuseTest::TearDown();
127 }
128 
129 };
130 
131 static void
132 handle_sigbus(int signo __unused, siginfo_t *info, void *uap __unused) {
133 	ReadSigbus::s_si_addr = info->si_addr;
134 	longjmp(ReadSigbus::s_jmpbuf, 1);
135 }
136 
137 jmp_buf ReadSigbus::s_jmpbuf;
138 void *ReadSigbus::s_si_addr;
139 
140 class TimeGran: public Read, public WithParamInterface<unsigned> {
141 public:
142 virtual void SetUp() {
143 	m_time_gran = 1 << GetParam();
144 	Read::SetUp();
145 }
146 };
147 
148 /* AIO reads need to set the header's pid field correctly */
149 /* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236379 */
150 TEST_F(AioRead, aio_read)
151 {
152 	const char FULLPATH[] = "mountpoint/some_file.txt";
153 	const char RELPATH[] = "some_file.txt";
154 	const char *CONTENTS = "abcdefgh";
155 	uint64_t ino = 42;
156 	int fd;
157 	ssize_t bufsize = strlen(CONTENTS);
158 	uint8_t buf[bufsize];
159 	struct aiocb iocb, *piocb;
160 
161 	expect_lookup(RELPATH, ino, bufsize);
162 	expect_open(ino, 0, 1);
163 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
164 
165 	fd = open(FULLPATH, O_RDONLY);
166 	ASSERT_LE(0, fd) << strerror(errno);
167 
168 	iocb.aio_nbytes = bufsize;
169 	iocb.aio_fildes = fd;
170 	iocb.aio_buf = buf;
171 	iocb.aio_offset = 0;
172 	iocb.aio_sigevent.sigev_notify = SIGEV_NONE;
173 	ASSERT_EQ(0, aio_read(&iocb)) << strerror(errno);
174 	ASSERT_EQ(bufsize, aio_waitcomplete(&piocb, NULL)) << strerror(errno);
175 	ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize));
176 
177 	leak(fd);
178 }
179 
180 /*
181  * Without the FUSE_ASYNC_READ mount option, fuse(4) should ensure that there
182  * is at most one outstanding read operation per file handle
183  */
184 TEST_F(AioRead, async_read_disabled)
185 {
186 	const char FULLPATH[] = "mountpoint/some_file.txt";
187 	const char RELPATH[] = "some_file.txt";
188 	uint64_t ino = 42;
189 	int fd;
190 	ssize_t bufsize = 50;
191 	char buf0[bufsize], buf1[bufsize];
192 	off_t off0 = 0;
193 	off_t off1 = m_maxbcachebuf;
194 	struct aiocb iocb0, iocb1;
195 	volatile sig_atomic_t read_count = 0;
196 
197 	expect_lookup(RELPATH, ino, 131072);
198 	expect_open(ino, 0, 1);
199 	EXPECT_CALL(*m_mock, process(
200 		ResultOf([=](auto in) {
201 			return (in.header.opcode == FUSE_READ &&
202 				in.header.nodeid == ino &&
203 				in.body.read.fh == FH &&
204 				in.body.read.offset == (uint64_t)off0);
205 		}, Eq(true)),
206 		_)
207 	).WillRepeatedly(Invoke([&](auto in __unused, auto &out __unused) {
208 		read_count++;
209 		/* Filesystem is slow to respond */
210 	}));
211 	EXPECT_CALL(*m_mock, process(
212 		ResultOf([=](auto in) {
213 			return (in.header.opcode == FUSE_READ &&
214 				in.header.nodeid == ino &&
215 				in.body.read.fh == FH &&
216 				in.body.read.offset == (uint64_t)off1);
217 		}, Eq(true)),
218 		_)
219 	).WillRepeatedly(Invoke([&](auto in __unused, auto &out __unused) {
220 		read_count++;
221 		/* Filesystem is slow to respond */
222 	}));
223 
224 	fd = open(FULLPATH, O_RDONLY);
225 	ASSERT_LE(0, fd) << strerror(errno);
226 
227 	/*
228 	 * Submit two AIO read requests, and respond to neither.  If the
229 	 * filesystem ever gets the second read request, then we failed to
230 	 * limit outstanding reads.
231 	 */
232 	iocb0.aio_nbytes = bufsize;
233 	iocb0.aio_fildes = fd;
234 	iocb0.aio_buf = buf0;
235 	iocb0.aio_offset = off0;
236 	iocb0.aio_sigevent.sigev_notify = SIGEV_NONE;
237 	ASSERT_EQ(0, aio_read(&iocb0)) << strerror(errno);
238 
239 	iocb1.aio_nbytes = bufsize;
240 	iocb1.aio_fildes = fd;
241 	iocb1.aio_buf = buf1;
242 	iocb1.aio_offset = off1;
243 	iocb1.aio_sigevent.sigev_notify = SIGEV_NONE;
244 	ASSERT_EQ(0, aio_read(&iocb1)) << strerror(errno);
245 
246 	/*
247 	 * Sleep for awhile to make sure the kernel has had a chance to issue
248 	 * the second read, even though the first has not yet returned
249 	 */
250 	nap();
251 	EXPECT_EQ(read_count, 1);
252 
253 	m_mock->kill_daemon();
254 	/* Wait for AIO activity to complete, but ignore errors */
255 	(void)aio_waitcomplete(NULL, NULL);
256 
257 	leak(fd);
258 }
259 
260 /*
261  * With the FUSE_ASYNC_READ mount option, fuse(4) may issue multiple
262  * simultaneous read requests on the same file handle.
263  */
264 TEST_F(AsyncRead, async_read)
265 {
266 	const char FULLPATH[] = "mountpoint/some_file.txt";
267 	const char RELPATH[] = "some_file.txt";
268 	uint64_t ino = 42;
269 	int fd;
270 	ssize_t bufsize = 50;
271 	char buf0[bufsize], buf1[bufsize];
272 	off_t off0 = 0;
273 	off_t off1 = m_maxbcachebuf;
274 	off_t fsize = 2 * m_maxbcachebuf;
275 	struct aiocb iocb0, iocb1;
276 	sem_t sem;
277 
278 	ASSERT_EQ(0, sem_init(&sem, 0, 0)) << strerror(errno);
279 
280 	expect_lookup(RELPATH, ino, fsize);
281 	expect_open(ino, 0, 1);
282 	EXPECT_CALL(*m_mock, process(
283 		ResultOf([=](auto in) {
284 			return (in.header.opcode == FUSE_READ &&
285 				in.header.nodeid == ino &&
286 				in.body.read.fh == FH &&
287 				in.body.read.offset == (uint64_t)off0);
288 		}, Eq(true)),
289 		_)
290 	).WillOnce(Invoke([&](auto in __unused, auto &out __unused) {
291 		sem_post(&sem);
292 		/* Filesystem is slow to respond */
293 	}));
294 	EXPECT_CALL(*m_mock, process(
295 		ResultOf([=](auto in) {
296 			return (in.header.opcode == FUSE_READ &&
297 				in.header.nodeid == ino &&
298 				in.body.read.fh == FH &&
299 				in.body.read.offset == (uint64_t)off1);
300 		}, Eq(true)),
301 		_)
302 	).WillOnce(Invoke([&](auto in __unused, auto &out __unused) {
303 		sem_post(&sem);
304 		/* Filesystem is slow to respond */
305 	}));
306 
307 	fd = open(FULLPATH, O_RDONLY);
308 	ASSERT_LE(0, fd) << strerror(errno);
309 
310 	/*
311 	 * Submit two AIO read requests, but respond to neither.  Ensure that
312 	 * we received both.
313 	 */
314 	iocb0.aio_nbytes = bufsize;
315 	iocb0.aio_fildes = fd;
316 	iocb0.aio_buf = buf0;
317 	iocb0.aio_offset = off0;
318 	iocb0.aio_sigevent.sigev_notify = SIGEV_NONE;
319 	ASSERT_EQ(0, aio_read(&iocb0)) << strerror(errno);
320 
321 	iocb1.aio_nbytes = bufsize;
322 	iocb1.aio_fildes = fd;
323 	iocb1.aio_buf = buf1;
324 	iocb1.aio_offset = off1;
325 	iocb1.aio_sigevent.sigev_notify = SIGEV_NONE;
326 	ASSERT_EQ(0, aio_read(&iocb1)) << strerror(errno);
327 
328 	/* Wait until both reads have reached the daemon */
329 	ASSERT_EQ(0, sem_wait(&sem)) << strerror(errno);
330 	ASSERT_EQ(0, sem_wait(&sem)) << strerror(errno);
331 
332 	m_mock->kill_daemon();
333 	/* Wait for AIO activity to complete, but ignore errors */
334 	(void)aio_waitcomplete(NULL, NULL);
335 
336 	leak(fd);
337 }
338 
339 /* The kernel should update the cached atime attribute during a read */
340 TEST_F(Read, atime)
341 {
342 	const char FULLPATH[] = "mountpoint/some_file.txt";
343 	const char RELPATH[] = "some_file.txt";
344 	const char *CONTENTS = "abcdefgh";
345 	struct stat sb1, sb2;
346 	uint64_t ino = 42;
347 	int fd;
348 	ssize_t bufsize = strlen(CONTENTS);
349 	uint8_t buf[bufsize];
350 
351 	expect_lookup(RELPATH, ino, bufsize);
352 	expect_open(ino, 0, 1);
353 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
354 
355 	fd = open(FULLPATH, O_RDONLY);
356 	ASSERT_LE(0, fd) << strerror(errno);
357 	ASSERT_EQ(0, fstat(fd, &sb1));
358 
359 	/* Ensure atime will be different than it was during lookup */
360 	nap();
361 
362 	ASSERT_EQ(bufsize, read(fd, buf, bufsize)) << strerror(errno);
363 	ASSERT_EQ(0, fstat(fd, &sb2));
364 
365 	/* The kernel should automatically update atime during read */
366 	EXPECT_TRUE(timespeccmp(&sb1.st_atim, &sb2.st_atim, <));
367 	EXPECT_TRUE(timespeccmp(&sb1.st_ctim, &sb2.st_ctim, ==));
368 	EXPECT_TRUE(timespeccmp(&sb1.st_mtim, &sb2.st_mtim, ==));
369 
370 	leak(fd);
371 }
372 
373 /* The kernel should update the cached atime attribute during a cached read */
374 TEST_F(Read, atime_cached)
375 {
376 	const char FULLPATH[] = "mountpoint/some_file.txt";
377 	const char RELPATH[] = "some_file.txt";
378 	const char *CONTENTS = "abcdefgh";
379 	struct stat sb1, sb2;
380 	uint64_t ino = 42;
381 	int fd;
382 	ssize_t bufsize = strlen(CONTENTS);
383 	uint8_t buf[bufsize];
384 
385 	expect_lookup(RELPATH, ino, bufsize);
386 	expect_open(ino, 0, 1);
387 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
388 
389 	fd = open(FULLPATH, O_RDONLY);
390 	ASSERT_LE(0, fd) << strerror(errno);
391 
392 	ASSERT_EQ(bufsize, pread(fd, buf, bufsize, 0)) << strerror(errno);
393 	ASSERT_EQ(0, fstat(fd, &sb1));
394 
395 	/* Ensure atime will be different than it was during the first read */
396 	nap();
397 
398 	ASSERT_EQ(bufsize, pread(fd, buf, bufsize, 0)) << strerror(errno);
399 	ASSERT_EQ(0, fstat(fd, &sb2));
400 
401 	/* The kernel should automatically update atime during read */
402 	EXPECT_TRUE(timespeccmp(&sb1.st_atim, &sb2.st_atim, <));
403 	EXPECT_TRUE(timespeccmp(&sb1.st_ctim, &sb2.st_ctim, ==));
404 	EXPECT_TRUE(timespeccmp(&sb1.st_mtim, &sb2.st_mtim, ==));
405 
406 	leak(fd);
407 }
408 
409 /* dirty atime values should be flushed during close */
410 TEST_F(Read, atime_during_close)
411 {
412 	const char FULLPATH[] = "mountpoint/some_file.txt";
413 	const char RELPATH[] = "some_file.txt";
414 	const char *CONTENTS = "abcdefgh";
415 	struct stat sb;
416 	uint64_t ino = 42;
417 	const mode_t newmode = 0755;
418 	int fd;
419 	ssize_t bufsize = strlen(CONTENTS);
420 	uint8_t buf[bufsize];
421 
422 	expect_lookup(RELPATH, ino, bufsize);
423 	expect_open(ino, 0, 1);
424 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
425 	EXPECT_CALL(*m_mock, process(
426 		ResultOf([&](auto in) {
427 			uint32_t valid = FATTR_ATIME;
428 			return (in.header.opcode == FUSE_SETATTR &&
429 				in.header.nodeid == ino &&
430 				in.body.setattr.valid == valid &&
431 				(time_t)in.body.setattr.atime ==
432 					sb.st_atim.tv_sec &&
433 				(long)in.body.setattr.atimensec ==
434 					sb.st_atim.tv_nsec);
435 		}, Eq(true)),
436 		_)
437 	).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
438 		SET_OUT_HEADER_LEN(out, attr);
439 		out.body.attr.attr.ino = ino;
440 		out.body.attr.attr.mode = S_IFREG | newmode;
441 	})));
442 	expect_flush(ino, 1, ReturnErrno(0));
443 	expect_release(ino, FuseTest::FH);
444 
445 	fd = open(FULLPATH, O_RDONLY);
446 	ASSERT_LE(0, fd) << strerror(errno);
447 
448 	/* Ensure atime will be different than during lookup */
449 	nap();
450 
451 	ASSERT_EQ(bufsize, read(fd, buf, bufsize)) << strerror(errno);
452 	ASSERT_EQ(0, fstat(fd, &sb));
453 
454 	close(fd);
455 }
456 
457 /* A cached atime should be flushed during FUSE_SETATTR */
458 TEST_F(Read, atime_during_setattr)
459 {
460 	const char FULLPATH[] = "mountpoint/some_file.txt";
461 	const char RELPATH[] = "some_file.txt";
462 	const char *CONTENTS = "abcdefgh";
463 	struct stat sb;
464 	uint64_t ino = 42;
465 	const mode_t newmode = 0755;
466 	int fd;
467 	ssize_t bufsize = strlen(CONTENTS);
468 	uint8_t buf[bufsize];
469 
470 	expect_lookup(RELPATH, ino, bufsize);
471 	expect_open(ino, 0, 1);
472 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
473 	EXPECT_CALL(*m_mock, process(
474 		ResultOf([&](auto in) {
475 			uint32_t valid = FATTR_MODE | FATTR_ATIME;
476 			return (in.header.opcode == FUSE_SETATTR &&
477 				in.header.nodeid == ino &&
478 				in.body.setattr.valid == valid &&
479 				(time_t)in.body.setattr.atime ==
480 					sb.st_atim.tv_sec &&
481 				(long)in.body.setattr.atimensec ==
482 					sb.st_atim.tv_nsec);
483 		}, Eq(true)),
484 		_)
485 	).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
486 		SET_OUT_HEADER_LEN(out, attr);
487 		out.body.attr.attr.ino = ino;
488 		out.body.attr.attr.mode = S_IFREG | newmode;
489 	})));
490 
491 	fd = open(FULLPATH, O_RDONLY);
492 	ASSERT_LE(0, fd) << strerror(errno);
493 
494 	/* Ensure atime will be different than during lookup */
495 	nap();
496 
497 	ASSERT_EQ(bufsize, read(fd, buf, bufsize)) << strerror(errno);
498 	ASSERT_EQ(0, fstat(fd, &sb));
499 	ASSERT_EQ(0, fchmod(fd, newmode)) << strerror(errno);
500 
501 	leak(fd);
502 }
503 
504 /* 0-length reads shouldn't cause any confusion */
505 TEST_F(Read, direct_io_read_nothing)
506 {
507 	const char FULLPATH[] = "mountpoint/some_file.txt";
508 	const char RELPATH[] = "some_file.txt";
509 	uint64_t ino = 42;
510 	int fd;
511 	uint64_t offset = 100;
512 	char buf[80];
513 
514 	expect_lookup(RELPATH, ino, offset + 1000);
515 	expect_open(ino, FOPEN_DIRECT_IO, 1);
516 
517 	fd = open(FULLPATH, O_RDONLY);
518 	ASSERT_LE(0, fd) << strerror(errno);
519 
520 	ASSERT_EQ(0, pread(fd, buf, 0, offset)) << strerror(errno);
521 	leak(fd);
522 }
523 
524 /*
525  * With direct_io, reads should not fill the cache.  They should go straight to
526  * the daemon
527  */
528 TEST_F(Read, direct_io_pread)
529 {
530 	const char FULLPATH[] = "mountpoint/some_file.txt";
531 	const char RELPATH[] = "some_file.txt";
532 	const char *CONTENTS = "abcdefgh";
533 	uint64_t ino = 42;
534 	int fd;
535 	uint64_t offset = 100;
536 	ssize_t bufsize = strlen(CONTENTS);
537 	uint8_t buf[bufsize];
538 
539 	expect_lookup(RELPATH, ino, offset + bufsize);
540 	expect_open(ino, FOPEN_DIRECT_IO, 1);
541 	expect_read(ino, offset, bufsize, bufsize, CONTENTS);
542 
543 	fd = open(FULLPATH, O_RDONLY);
544 	ASSERT_LE(0, fd) << strerror(errno);
545 
546 	ASSERT_EQ(bufsize, pread(fd, buf, bufsize, offset)) << strerror(errno);
547 	ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize));
548 
549 	// With FOPEN_DIRECT_IO, the cache should be bypassed.  The server will
550 	// get a 2nd read request.
551 	expect_read(ino, offset, bufsize, bufsize, CONTENTS);
552 	ASSERT_EQ(bufsize, pread(fd, buf, bufsize, offset)) << strerror(errno);
553 	ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize));
554 	leak(fd);
555 }
556 
557 /*
558  * With direct_io, filesystems are allowed to return less data than is
559  * requested.  fuse(4) should return a short read to userland.
560  */
561 TEST_F(Read, direct_io_short_read)
562 {
563 	const char FULLPATH[] = "mountpoint/some_file.txt";
564 	const char RELPATH[] = "some_file.txt";
565 	const char *CONTENTS = "abcdefghijklmnop";
566 	uint64_t ino = 42;
567 	int fd;
568 	uint64_t offset = 100;
569 	ssize_t bufsize = strlen(CONTENTS);
570 	ssize_t halfbufsize = bufsize / 2;
571 	uint8_t buf[bufsize];
572 
573 	expect_lookup(RELPATH, ino, offset + bufsize);
574 	expect_open(ino, FOPEN_DIRECT_IO, 1);
575 	expect_read(ino, offset, bufsize, halfbufsize, CONTENTS);
576 
577 	fd = open(FULLPATH, O_RDONLY);
578 	ASSERT_LE(0, fd) << strerror(errno);
579 
580 	ASSERT_EQ(halfbufsize, pread(fd, buf, bufsize, offset))
581 		<< strerror(errno);
582 	ASSERT_EQ(0, memcmp(buf, CONTENTS, halfbufsize));
583 	leak(fd);
584 }
585 
586 TEST_F(Read, eio)
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 	int fd;
593 	ssize_t bufsize = strlen(CONTENTS);
594 	uint8_t buf[bufsize];
595 
596 	expect_lookup(RELPATH, ino, bufsize);
597 	expect_open(ino, 0, 1);
598 	EXPECT_CALL(*m_mock, process(
599 		ResultOf([=](auto in) {
600 			return (in.header.opcode == FUSE_READ);
601 		}, Eq(true)),
602 		_)
603 	).WillOnce(Invoke(ReturnErrno(EIO)));
604 
605 	fd = open(FULLPATH, O_RDONLY);
606 	ASSERT_LE(0, fd) << strerror(errno);
607 
608 	ASSERT_EQ(-1, read(fd, buf, bufsize)) << strerror(errno);
609 	ASSERT_EQ(EIO, errno);
610 	leak(fd);
611 }
612 
613 /*
614  * If the server returns a short read when direct io is not in use, that
615  * indicates EOF, because of a server-side truncation.  We should invalidate
616  * all cached attributes.  We may update the file size,
617  */
618 TEST_F(Read, eof)
619 {
620 	const char FULLPATH[] = "mountpoint/some_file.txt";
621 	const char RELPATH[] = "some_file.txt";
622 	const char *CONTENTS = "abcdefghijklmnop";
623 	uint64_t ino = 42;
624 	int fd;
625 	uint64_t offset = 100;
626 	ssize_t bufsize = strlen(CONTENTS);
627 	ssize_t partbufsize = 3 * bufsize / 4;
628 	ssize_t r;
629 	uint8_t buf[bufsize];
630 	struct stat sb;
631 
632 	expect_lookup(RELPATH, ino, offset + bufsize);
633 	expect_open(ino, 0, 1);
634 	expect_read(ino, 0, offset + bufsize, offset + partbufsize, CONTENTS);
635 	expect_getattr(ino, offset + partbufsize);
636 
637 	fd = open(FULLPATH, O_RDONLY);
638 	ASSERT_LE(0, fd) << strerror(errno);
639 
640 	r = pread(fd, buf, bufsize, offset);
641 	ASSERT_LE(0, r) << strerror(errno);
642 	EXPECT_EQ(partbufsize, r) << strerror(errno);
643 	ASSERT_EQ(0, fstat(fd, &sb));
644 	EXPECT_EQ((off_t)(offset + partbufsize), sb.st_size);
645 	leak(fd);
646 }
647 
648 /* Like Read.eof, but causes an entire buffer to be invalidated */
649 TEST_F(Read, eof_of_whole_buffer)
650 {
651 	const char FULLPATH[] = "mountpoint/some_file.txt";
652 	const char RELPATH[] = "some_file.txt";
653 	const char *CONTENTS = "abcdefghijklmnop";
654 	uint64_t ino = 42;
655 	int fd;
656 	ssize_t bufsize = strlen(CONTENTS);
657 	off_t old_filesize = m_maxbcachebuf * 2 + bufsize;
658 	uint8_t buf[bufsize];
659 	struct stat sb;
660 
661 	expect_lookup(RELPATH, ino, old_filesize);
662 	expect_open(ino, 0, 1);
663 	expect_read(ino, 2 * m_maxbcachebuf, bufsize, bufsize, CONTENTS);
664 	expect_read(ino, m_maxbcachebuf, m_maxbcachebuf, 0, CONTENTS);
665 	expect_getattr(ino, m_maxbcachebuf);
666 
667 	fd = open(FULLPATH, O_RDONLY);
668 	ASSERT_LE(0, fd) << strerror(errno);
669 
670 	/* Cache the third block */
671 	ASSERT_EQ(bufsize, pread(fd, buf, bufsize, m_maxbcachebuf * 2))
672 		<< strerror(errno);
673 	/* Try to read the 2nd block, but it's past EOF */
674 	ASSERT_EQ(0, pread(fd, buf, bufsize, m_maxbcachebuf))
675 		<< strerror(errno);
676 	ASSERT_EQ(0, fstat(fd, &sb));
677 	EXPECT_EQ((off_t)(m_maxbcachebuf), sb.st_size);
678 	leak(fd);
679 }
680 
681 /*
682  * With the keep_cache option, the kernel may keep its read cache across
683  * multiple open(2)s.
684  */
685 TEST_F(Read, keep_cache)
686 {
687 	const char FULLPATH[] = "mountpoint/some_file.txt";
688 	const char RELPATH[] = "some_file.txt";
689 	const char *CONTENTS = "abcdefgh";
690 	uint64_t ino = 42;
691 	int fd0, fd1;
692 	ssize_t bufsize = strlen(CONTENTS);
693 	uint8_t buf[bufsize];
694 
695 	FuseTest::expect_lookup(RELPATH, ino, S_IFREG | 0644, bufsize, 2);
696 	expect_open(ino, FOPEN_KEEP_CACHE, 2);
697 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
698 
699 	fd0 = open(FULLPATH, O_RDONLY);
700 	ASSERT_LE(0, fd0) << strerror(errno);
701 	ASSERT_EQ(bufsize, read(fd0, buf, bufsize)) << strerror(errno);
702 
703 	fd1 = open(FULLPATH, O_RDWR);
704 	ASSERT_LE(0, fd1) << strerror(errno);
705 
706 	/*
707 	 * This read should be serviced by cache, even though it's on the other
708 	 * file descriptor
709 	 */
710 	ASSERT_EQ(bufsize, read(fd1, buf, bufsize)) << strerror(errno);
711 
712 	leak(fd0);
713 	leak(fd1);
714 }
715 
716 /*
717  * Without the keep_cache option, the kernel should drop its read caches on
718  * every open
719  */
720 TEST_F(Read, keep_cache_disabled)
721 {
722 	const char FULLPATH[] = "mountpoint/some_file.txt";
723 	const char RELPATH[] = "some_file.txt";
724 	const char *CONTENTS = "abcdefgh";
725 	uint64_t ino = 42;
726 	int fd0, fd1;
727 	ssize_t bufsize = strlen(CONTENTS);
728 	uint8_t buf[bufsize];
729 
730 	FuseTest::expect_lookup(RELPATH, ino, S_IFREG | 0644, bufsize, 2);
731 	expect_open(ino, 0, 2);
732 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
733 
734 	fd0 = open(FULLPATH, O_RDONLY);
735 	ASSERT_LE(0, fd0) << strerror(errno);
736 	ASSERT_EQ(bufsize, read(fd0, buf, bufsize)) << strerror(errno);
737 
738 	fd1 = open(FULLPATH, O_RDWR);
739 	ASSERT_LE(0, fd1) << strerror(errno);
740 
741 	/*
742 	 * This read should not be serviced by cache, even though it's on the
743 	 * original file descriptor
744 	 */
745 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
746 	ASSERT_EQ(0, lseek(fd0, 0, SEEK_SET)) << strerror(errno);
747 	ASSERT_EQ(bufsize, read(fd0, buf, bufsize)) << strerror(errno);
748 
749 	leak(fd0);
750 	leak(fd1);
751 }
752 
753 TEST_F(Read, mmap)
754 {
755 	const char FULLPATH[] = "mountpoint/some_file.txt";
756 	const char RELPATH[] = "some_file.txt";
757 	const char *CONTENTS = "abcdefgh";
758 	uint64_t ino = 42;
759 	int fd;
760 	ssize_t len;
761 	size_t bufsize = strlen(CONTENTS);
762 	void *p;
763 
764 	len = getpagesize();
765 
766 	expect_lookup(RELPATH, ino, bufsize);
767 	expect_open(ino, 0, 1);
768 	EXPECT_CALL(*m_mock, process(
769 		ResultOf([=](auto in) {
770 			return (in.header.opcode == FUSE_READ &&
771 				in.header.nodeid == ino &&
772 				in.body.read.fh == Read::FH &&
773 				in.body.read.offset == 0 &&
774 				in.body.read.size == bufsize);
775 		}, Eq(true)),
776 		_)
777 	).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
778 		out.header.len = sizeof(struct fuse_out_header) + bufsize;
779 		memmove(out.body.bytes, CONTENTS, bufsize);
780 	})));
781 
782 	fd = open(FULLPATH, O_RDONLY);
783 	ASSERT_LE(0, fd) << strerror(errno);
784 
785 	p = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
786 	ASSERT_NE(MAP_FAILED, p) << strerror(errno);
787 
788 	ASSERT_EQ(0, memcmp(p, CONTENTS, bufsize));
789 
790 	ASSERT_EQ(0, munmap(p, len)) << strerror(errno);
791 	leak(fd);
792 }
793 
794 /*
795  * The kernel should not update the cached atime attribute during a read, if
796  * MNT_NOATIME is used.
797  */
798 TEST_F(ReadNoatime, atime)
799 {
800 	const char FULLPATH[] = "mountpoint/some_file.txt";
801 	const char RELPATH[] = "some_file.txt";
802 	const char *CONTENTS = "abcdefgh";
803 	struct stat sb1, sb2;
804 	uint64_t ino = 42;
805 	int fd;
806 	ssize_t bufsize = strlen(CONTENTS);
807 	uint8_t buf[bufsize];
808 
809 	expect_lookup(RELPATH, ino, bufsize);
810 	expect_open(ino, 0, 1);
811 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
812 
813 	fd = open(FULLPATH, O_RDONLY);
814 	ASSERT_LE(0, fd) << strerror(errno);
815 	ASSERT_EQ(0, fstat(fd, &sb1));
816 
817 	nap();
818 
819 	ASSERT_EQ(bufsize, read(fd, buf, bufsize)) << strerror(errno);
820 	ASSERT_EQ(0, fstat(fd, &sb2));
821 
822 	/* The kernel should not update atime during read */
823 	EXPECT_TRUE(timespeccmp(&sb1.st_atim, &sb2.st_atim, ==));
824 	EXPECT_TRUE(timespeccmp(&sb1.st_ctim, &sb2.st_ctim, ==));
825 	EXPECT_TRUE(timespeccmp(&sb1.st_mtim, &sb2.st_mtim, ==));
826 
827 	leak(fd);
828 }
829 
830 /*
831  * The kernel should not update the cached atime attribute during a cached
832  * read, if MNT_NOATIME is used.
833  */
834 TEST_F(ReadNoatime, atime_cached)
835 {
836 	const char FULLPATH[] = "mountpoint/some_file.txt";
837 	const char RELPATH[] = "some_file.txt";
838 	const char *CONTENTS = "abcdefgh";
839 	struct stat sb1, sb2;
840 	uint64_t ino = 42;
841 	int fd;
842 	ssize_t bufsize = strlen(CONTENTS);
843 	uint8_t buf[bufsize];
844 
845 	expect_lookup(RELPATH, ino, bufsize);
846 	expect_open(ino, 0, 1);
847 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
848 
849 	fd = open(FULLPATH, O_RDONLY);
850 	ASSERT_LE(0, fd) << strerror(errno);
851 
852 	ASSERT_EQ(bufsize, pread(fd, buf, bufsize, 0)) << strerror(errno);
853 	ASSERT_EQ(0, fstat(fd, &sb1));
854 
855 	nap();
856 
857 	ASSERT_EQ(bufsize, pread(fd, buf, bufsize, 0)) << strerror(errno);
858 	ASSERT_EQ(0, fstat(fd, &sb2));
859 
860 	/* The kernel should automatically update atime during read */
861 	EXPECT_TRUE(timespeccmp(&sb1.st_atim, &sb2.st_atim, ==));
862 	EXPECT_TRUE(timespeccmp(&sb1.st_ctim, &sb2.st_ctim, ==));
863 	EXPECT_TRUE(timespeccmp(&sb1.st_mtim, &sb2.st_mtim, ==));
864 
865 	leak(fd);
866 }
867 
868 /* Read of an mmap()ed file fails */
869 TEST_F(ReadSigbus, mmap_eio)
870 {
871 	const char FULLPATH[] = "mountpoint/some_file.txt";
872 	const char RELPATH[] = "some_file.txt";
873 	const char *CONTENTS = "abcdefgh";
874 	struct sigaction sa;
875 	uint64_t ino = 42;
876 	int fd;
877 	ssize_t len;
878 	size_t bufsize = strlen(CONTENTS);
879 	void *p;
880 
881 	len = getpagesize();
882 
883 	expect_lookup(RELPATH, ino, bufsize);
884 	expect_open(ino, 0, 1);
885 	EXPECT_CALL(*m_mock, process(
886 		ResultOf([=](auto in) {
887 			return (in.header.opcode == FUSE_READ &&
888 				in.header.nodeid == ino &&
889 				in.body.read.fh == Read::FH);
890 		}, Eq(true)),
891 		_)
892 	).WillRepeatedly(Invoke(ReturnErrno(EIO)));
893 
894 	fd = open(FULLPATH, O_RDONLY);
895 	ASSERT_LE(0, fd) << strerror(errno);
896 
897 	p = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
898 	ASSERT_NE(MAP_FAILED, p) << strerror(errno);
899 
900 	/* Accessing the mapped page should return SIGBUS.  */
901 
902 	bzero(&sa, sizeof(sa));
903 	sa.sa_handler = SIG_DFL;
904 	sa.sa_sigaction = handle_sigbus;
905 	sa.sa_flags = SA_RESETHAND | SA_SIGINFO;
906 	ASSERT_EQ(0, sigaction(SIGBUS, &sa, NULL)) << strerror(errno);
907 	if (setjmp(ReadSigbus::s_jmpbuf) == 0) {
908 		atomic_signal_fence(std::memory_order::memory_order_seq_cst);
909 		volatile char x __unused = *(volatile char*)p;
910 		FAIL() << "shouldn't get here";
911 	}
912 
913 	ASSERT_EQ(p, ReadSigbus::s_si_addr);
914 	ASSERT_EQ(0, munmap(p, len)) << strerror(errno);
915 	leak(fd);
916 }
917 
918 /*
919  * A read via mmap comes up short, indicating that the file was truncated
920  * server-side.
921  */
922 TEST_F(Read, mmap_eof)
923 {
924 	const char FULLPATH[] = "mountpoint/some_file.txt";
925 	const char RELPATH[] = "some_file.txt";
926 	const char *CONTENTS = "abcdefgh";
927 	uint64_t ino = 42;
928 	int fd;
929 	ssize_t len;
930 	size_t bufsize = strlen(CONTENTS);
931 	struct stat sb;
932 	void *p;
933 
934 	len = getpagesize();
935 
936 	expect_lookup(RELPATH, ino, m_maxbcachebuf);
937 	expect_open(ino, 0, 1);
938 	EXPECT_CALL(*m_mock, process(
939 		ResultOf([=](auto in) {
940 			return (in.header.opcode == FUSE_READ &&
941 				in.header.nodeid == ino &&
942 				in.body.read.fh == Read::FH &&
943 				in.body.read.offset == 0 &&
944 				in.body.read.size == (uint32_t)m_maxbcachebuf);
945 		}, Eq(true)),
946 		_)
947 	).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
948 		out.header.len = sizeof(struct fuse_out_header) + bufsize;
949 		memmove(out.body.bytes, CONTENTS, bufsize);
950 	})));
951 	expect_getattr(ino, bufsize);
952 
953 	fd = open(FULLPATH, O_RDONLY);
954 	ASSERT_LE(0, fd) << strerror(errno);
955 
956 	p = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
957 	ASSERT_NE(MAP_FAILED, p) << strerror(errno);
958 
959 	/* The file size should be automatically truncated */
960 	ASSERT_EQ(0, memcmp(p, CONTENTS, bufsize));
961 	ASSERT_EQ(0, fstat(fd, &sb)) << strerror(errno);
962 	EXPECT_EQ((off_t)bufsize, sb.st_size);
963 
964 	ASSERT_EQ(0, munmap(p, len)) << strerror(errno);
965 	leak(fd);
966 }
967 
968 /*
969  * During VOP_GETPAGES, the FUSE server fails a FUSE_GETATTR operation.  This
970  * almost certainly indicates a buggy FUSE server, and our goal should be not
971  * to panic.  Instead, generate SIGBUS.
972  */
973 TEST_F(ReadSigbus, mmap_getblksz_fail)
974 {
975 	const char FULLPATH[] = "mountpoint/some_file.txt";
976 	const char RELPATH[] = "some_file.txt";
977 	const char *CONTENTS = "abcdefgh";
978 	struct sigaction sa;
979 	Sequence seq;
980 	uint64_t ino = 42;
981 	int fd;
982 	ssize_t len;
983 	size_t bufsize = strlen(CONTENTS);
984 	mode_t mode = S_IFREG | 0644;
985 	void *p;
986 
987 	len = getpagesize();
988 
989 	FuseTest::expect_lookup(RELPATH, ino, mode, bufsize, 1, 0);
990 	/* Expect two GETATTR calls that succeed, followed by one that fail. */
991 	EXPECT_CALL(*m_mock, process(
992 		ResultOf([=](auto in) {
993 			return (in.header.opcode == FUSE_GETATTR &&
994 				in.header.nodeid == ino);
995 		}, Eq(true)),
996 		_)
997 	).Times(2)
998 	.InSequence(seq)
999 	.WillRepeatedly(Invoke(ReturnImmediate([=](auto i __unused, auto& out) {
1000 		SET_OUT_HEADER_LEN(out, attr);
1001 		out.body.attr.attr.ino = ino;
1002 		out.body.attr.attr.mode = mode;
1003 		out.body.attr.attr.size = bufsize;
1004 		out.body.attr.attr_valid = 0;
1005 	})));
1006 	EXPECT_CALL(*m_mock, process(
1007 		ResultOf([=](auto in) {
1008 			return (in.header.opcode == FUSE_GETATTR &&
1009 				in.header.nodeid == ino);
1010 		}, Eq(true)),
1011 		_)
1012 	).InSequence(seq)
1013 	.WillRepeatedly(Invoke(ReturnErrno(EIO)));
1014 	expect_open(ino, 0, 1);
1015 	EXPECT_CALL(*m_mock, process(
1016 		ResultOf([=](auto in) {
1017 			return (in.header.opcode == FUSE_READ);
1018 		}, Eq(true)),
1019 		_)
1020 	).Times(0);
1021 
1022 	fd = open(FULLPATH, O_RDONLY);
1023 	ASSERT_LE(0, fd) << strerror(errno);
1024 
1025 	p = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
1026 	ASSERT_NE(MAP_FAILED, p) << strerror(errno);
1027 
1028 	/* Accessing the mapped page should return SIGBUS.  */
1029 	bzero(&sa, sizeof(sa));
1030 	sa.sa_handler = SIG_DFL;
1031 	sa.sa_sigaction = handle_sigbus;
1032 	sa.sa_flags = SA_RESETHAND | SA_SIGINFO;
1033 	ASSERT_EQ(0, sigaction(SIGBUS, &sa, NULL)) << strerror(errno);
1034 	if (setjmp(ReadSigbus::s_jmpbuf) == 0) {
1035 		atomic_signal_fence(std::memory_order::memory_order_seq_cst);
1036 		volatile char x __unused = *(volatile char*)p;
1037 		FAIL() << "shouldn't get here";
1038 	}
1039 
1040 	ASSERT_EQ(p, ReadSigbus::s_si_addr);
1041 	ASSERT_EQ(0, munmap(p, len)) << strerror(errno);
1042 	leak(fd);
1043 }
1044 
1045 /*
1046  * Just as when FOPEN_DIRECT_IO is used, reads with O_DIRECT should bypass
1047  * cache and to straight to the daemon
1048  */
1049 TEST_F(Read, o_direct)
1050 {
1051 	const char FULLPATH[] = "mountpoint/some_file.txt";
1052 	const char RELPATH[] = "some_file.txt";
1053 	const char *CONTENTS = "abcdefgh";
1054 	uint64_t ino = 42;
1055 	int fd;
1056 	ssize_t bufsize = strlen(CONTENTS);
1057 	uint8_t buf[bufsize];
1058 
1059 	expect_lookup(RELPATH, ino, bufsize);
1060 	expect_open(ino, 0, 1);
1061 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
1062 
1063 	fd = open(FULLPATH, O_RDONLY);
1064 	ASSERT_LE(0, fd) << strerror(errno);
1065 
1066 	// Fill the cache
1067 	ASSERT_EQ(bufsize, read(fd, buf, bufsize)) << strerror(errno);
1068 	ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize));
1069 
1070 	// Reads with o_direct should bypass the cache
1071 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
1072 	ASSERT_EQ(0, fcntl(fd, F_SETFL, O_DIRECT)) << strerror(errno);
1073 	ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)) << strerror(errno);
1074 	ASSERT_EQ(bufsize, read(fd, buf, bufsize)) << strerror(errno);
1075 	ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize));
1076 
1077 	leak(fd);
1078 }
1079 
1080 TEST_F(Read, pread)
1081 {
1082 	const char FULLPATH[] = "mountpoint/some_file.txt";
1083 	const char RELPATH[] = "some_file.txt";
1084 	const char *CONTENTS = "abcdefgh";
1085 	uint64_t ino = 42;
1086 	int fd;
1087 	/*
1088 	 * Set offset to a maxbcachebuf boundary so we'll be sure what offset
1089 	 * to read from.  Without this, the read might start at a lower offset.
1090 	 */
1091 	uint64_t offset = m_maxbcachebuf;
1092 	ssize_t bufsize = strlen(CONTENTS);
1093 	uint8_t buf[bufsize];
1094 
1095 	expect_lookup(RELPATH, ino, offset + bufsize);
1096 	expect_open(ino, 0, 1);
1097 	expect_read(ino, offset, bufsize, bufsize, CONTENTS);
1098 
1099 	fd = open(FULLPATH, O_RDONLY);
1100 	ASSERT_LE(0, fd) << strerror(errno);
1101 
1102 	ASSERT_EQ(bufsize, pread(fd, buf, bufsize, offset)) << strerror(errno);
1103 	ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize));
1104 	leak(fd);
1105 }
1106 
1107 TEST_F(Read, read)
1108 {
1109 	const char FULLPATH[] = "mountpoint/some_file.txt";
1110 	const char RELPATH[] = "some_file.txt";
1111 	const char *CONTENTS = "abcdefgh";
1112 	uint64_t ino = 42;
1113 	int fd;
1114 	ssize_t bufsize = strlen(CONTENTS);
1115 	uint8_t buf[bufsize];
1116 
1117 	expect_lookup(RELPATH, ino, bufsize);
1118 	expect_open(ino, 0, 1);
1119 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
1120 
1121 	fd = open(FULLPATH, O_RDONLY);
1122 	ASSERT_LE(0, fd) << strerror(errno);
1123 
1124 	ASSERT_EQ(bufsize, read(fd, buf, bufsize)) << strerror(errno);
1125 	ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize));
1126 
1127 	leak(fd);
1128 }
1129 
1130 TEST_F(Read_7_8, read)
1131 {
1132 	const char FULLPATH[] = "mountpoint/some_file.txt";
1133 	const char RELPATH[] = "some_file.txt";
1134 	const char *CONTENTS = "abcdefgh";
1135 	uint64_t ino = 42;
1136 	int fd;
1137 	ssize_t bufsize = strlen(CONTENTS);
1138 	uint8_t buf[bufsize];
1139 
1140 	expect_lookup(RELPATH, ino, bufsize);
1141 	expect_open(ino, 0, 1);
1142 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
1143 
1144 	fd = open(FULLPATH, O_RDONLY);
1145 	ASSERT_LE(0, fd) << strerror(errno);
1146 
1147 	ASSERT_EQ(bufsize, read(fd, buf, bufsize)) << strerror(errno);
1148 	ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize));
1149 
1150 	leak(fd);
1151 }
1152 
1153 /*
1154  * If cacheing is enabled, the kernel should try to read an entire cache block
1155  * at a time.
1156  */
1157 TEST_F(Read, cache_block)
1158 {
1159 	const char FULLPATH[] = "mountpoint/some_file.txt";
1160 	const char RELPATH[] = "some_file.txt";
1161 	const char *CONTENTS0 = "abcdefghijklmnop";
1162 	uint64_t ino = 42;
1163 	int fd;
1164 	ssize_t bufsize = 8;
1165 	ssize_t filesize = m_maxbcachebuf * 2;
1166 	char *contents;
1167 	char buf[bufsize];
1168 	const char *contents1 = CONTENTS0 + bufsize;
1169 
1170 	contents = (char*)calloc(1, filesize);
1171 	ASSERT_NE(nullptr, contents);
1172 	memmove(contents, CONTENTS0, strlen(CONTENTS0));
1173 
1174 	expect_lookup(RELPATH, ino, filesize);
1175 	expect_open(ino, 0, 1);
1176 	expect_read(ino, 0, m_maxbcachebuf, m_maxbcachebuf,
1177 		contents);
1178 
1179 	fd = open(FULLPATH, O_RDONLY);
1180 	ASSERT_LE(0, fd) << strerror(errno);
1181 
1182 	ASSERT_EQ(bufsize, read(fd, buf, bufsize)) << strerror(errno);
1183 	ASSERT_EQ(0, memcmp(buf, CONTENTS0, bufsize));
1184 
1185 	/* A subsequent read should be serviced by cache */
1186 	ASSERT_EQ(bufsize, read(fd, buf, bufsize)) << strerror(errno);
1187 	ASSERT_EQ(0, memcmp(buf, contents1, bufsize));
1188 	leak(fd);
1189 	free(contents);
1190 }
1191 
1192 /* Reading with sendfile should work (though it obviously won't be 0-copy) */
1193 TEST_F(Read, sendfile)
1194 {
1195 	const char FULLPATH[] = "mountpoint/some_file.txt";
1196 	const char RELPATH[] = "some_file.txt";
1197 	const char *CONTENTS = "abcdefgh";
1198 	uint64_t ino = 42;
1199 	int fd;
1200 	size_t bufsize = strlen(CONTENTS);
1201 	uint8_t buf[bufsize];
1202 	int sp[2];
1203 	off_t sbytes;
1204 
1205 	expect_lookup(RELPATH, ino, bufsize);
1206 	expect_open(ino, 0, 1);
1207 	EXPECT_CALL(*m_mock, process(
1208 		ResultOf([=](auto in) {
1209 			return (in.header.opcode == FUSE_READ &&
1210 				in.header.nodeid == ino &&
1211 				in.body.read.fh == Read::FH &&
1212 				in.body.read.offset == 0 &&
1213 				in.body.read.size == bufsize);
1214 		}, Eq(true)),
1215 		_)
1216 	).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
1217 		out.header.len = sizeof(struct fuse_out_header) + bufsize;
1218 		memmove(out.body.bytes, CONTENTS, bufsize);
1219 	})));
1220 
1221 	ASSERT_EQ(0, socketpair(PF_LOCAL, SOCK_STREAM, 0, sp))
1222 		<< strerror(errno);
1223 	fd = open(FULLPATH, O_RDONLY);
1224 	ASSERT_LE(0, fd) << strerror(errno);
1225 
1226 	ASSERT_EQ(0, sendfile(fd, sp[1], 0, bufsize, NULL, &sbytes, 0))
1227 		<< strerror(errno);
1228 	ASSERT_EQ(static_cast<ssize_t>(bufsize), read(sp[0], buf, bufsize))
1229 		<< strerror(errno);
1230 	ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize));
1231 
1232 	close(sp[1]);
1233 	close(sp[0]);
1234 	leak(fd);
1235 }
1236 
1237 /* sendfile should fail gracefully if fuse declines the read */
1238 /* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236466 */
1239 TEST_F(Read, sendfile_eio)
1240 {
1241 	const char FULLPATH[] = "mountpoint/some_file.txt";
1242 	const char RELPATH[] = "some_file.txt";
1243 	const char *CONTENTS = "abcdefgh";
1244 	uint64_t ino = 42;
1245 	int fd;
1246 	ssize_t bufsize = strlen(CONTENTS);
1247 	int sp[2];
1248 	off_t sbytes;
1249 
1250 	expect_lookup(RELPATH, ino, bufsize);
1251 	expect_open(ino, 0, 1);
1252 	EXPECT_CALL(*m_mock, process(
1253 		ResultOf([=](auto in) {
1254 			return (in.header.opcode == FUSE_READ);
1255 		}, Eq(true)),
1256 		_)
1257 	).WillOnce(Invoke(ReturnErrno(EIO)));
1258 
1259 	ASSERT_EQ(0, socketpair(PF_LOCAL, SOCK_STREAM, 0, sp))
1260 		<< strerror(errno);
1261 	fd = open(FULLPATH, O_RDONLY);
1262 	ASSERT_LE(0, fd) << strerror(errno);
1263 
1264 	ASSERT_NE(0, sendfile(fd, sp[1], 0, bufsize, NULL, &sbytes, 0));
1265 
1266 	close(sp[1]);
1267 	close(sp[0]);
1268 	leak(fd);
1269 }
1270 
1271 /*
1272  * Sequential reads should use readahead.  And if allowed, large reads should
1273  * be clustered.
1274  */
1275 TEST_P(ReadAhead, readahead) {
1276 	const char FULLPATH[] = "mountpoint/some_file.txt";
1277 	const char RELPATH[] = "some_file.txt";
1278 	uint64_t ino = 42;
1279 	int fd, maxcontig, clustersize;
1280 	ssize_t bufsize = 4 * m_maxbcachebuf;
1281 	ssize_t filesize = bufsize;
1282 	uint64_t len;
1283 	char *rbuf, *contents;
1284 	off_t offs;
1285 
1286 	contents = (char*)malloc(filesize);
1287 	ASSERT_NE(nullptr, contents);
1288 	memset(contents, 'X', filesize);
1289 	rbuf = (char*)calloc(1, bufsize);
1290 
1291 	expect_lookup(RELPATH, ino, filesize);
1292 	expect_open(ino, 0, 1);
1293 	maxcontig = m_noclusterr ? m_maxbcachebuf :
1294 		m_maxbcachebuf + m_maxreadahead;
1295 	clustersize = MIN(maxcontig, m_maxphys);
1296 	for (offs = 0; offs < bufsize; offs += clustersize) {
1297 		len = std::min((size_t)clustersize, (size_t)(filesize - offs));
1298 		expect_read(ino, offs, len, len, contents + offs);
1299 	}
1300 
1301 	fd = open(FULLPATH, O_RDONLY);
1302 	ASSERT_LE(0, fd) << strerror(errno);
1303 
1304 	/* Set the internal readahead counter to a "large" value */
1305 	ASSERT_EQ(0, fcntl(fd, F_READAHEAD, 1'000'000'000)) << strerror(errno);
1306 
1307 	ASSERT_EQ(bufsize, read(fd, rbuf, bufsize)) << strerror(errno);
1308 	ASSERT_EQ(0, memcmp(rbuf, contents, bufsize));
1309 
1310 	leak(fd);
1311 	free(rbuf);
1312 	free(contents);
1313 }
1314 
1315 INSTANTIATE_TEST_SUITE_P(RA, ReadAhead,
1316 	Values(tuple<bool, int>(false, 0),
1317 	       tuple<bool, int>(false, 1),
1318 	       tuple<bool, int>(false, 2),
1319 	       tuple<bool, int>(false, 3),
1320 	       tuple<bool, int>(true, 0),
1321 	       tuple<bool, int>(true, 1),
1322 	       tuple<bool, int>(true, 2)));
1323 
1324 /* fuse_init_out.time_gran controls the granularity of timestamps */
1325 TEST_P(TimeGran, atime_during_setattr)
1326 {
1327 	const char FULLPATH[] = "mountpoint/some_file.txt";
1328 	const char RELPATH[] = "some_file.txt";
1329 	const char *CONTENTS = "abcdefgh";
1330 	ssize_t bufsize = strlen(CONTENTS);
1331 	uint8_t buf[bufsize];
1332 	uint64_t ino = 42;
1333 	const mode_t newmode = 0755;
1334 	int fd;
1335 
1336 	expect_lookup(RELPATH, ino, bufsize);
1337 	expect_open(ino, 0, 1);
1338 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
1339 	EXPECT_CALL(*m_mock, process(
1340 		ResultOf([=](auto in) {
1341 			uint32_t valid = FATTR_MODE | FATTR_ATIME;
1342 			return (in.header.opcode == FUSE_SETATTR &&
1343 				in.header.nodeid == ino &&
1344 				in.body.setattr.valid == valid &&
1345 				in.body.setattr.atimensec % m_time_gran == 0);
1346 		}, Eq(true)),
1347 		_)
1348 	).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
1349 		SET_OUT_HEADER_LEN(out, attr);
1350 		out.body.attr.attr.ino = ino;
1351 		out.body.attr.attr.mode = S_IFREG | newmode;
1352 	})));
1353 
1354 	fd = open(FULLPATH, O_RDWR);
1355 	ASSERT_LE(0, fd) << strerror(errno);
1356 
1357 	ASSERT_EQ(bufsize, read(fd, buf, bufsize)) << strerror(errno);
1358 	ASSERT_EQ(0, fchmod(fd, newmode)) << strerror(errno);
1359 
1360 	leak(fd);
1361 }
1362 
1363 INSTANTIATE_TEST_SUITE_P(TG, TimeGran, Range(0u, 10u));
1364