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