xref: /freebsd/tests/sys/fs/fusefs/read.cc (revision 3332f1b444d4a73238e9f59cca27bfc95fe936bd)
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/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 ReadSigbus: public Read
109 {
110 public:
111 static jmp_buf s_jmpbuf;
112 static void *s_si_addr;
113 
114 void TearDown() {
115 	struct sigaction sa;
116 
117 	bzero(&sa, sizeof(sa));
118 	sa.sa_handler = SIG_DFL;
119 	sigaction(SIGBUS, &sa, NULL);
120 
121 	FuseTest::TearDown();
122 }
123 
124 };
125 
126 static void
127 handle_sigbus(int signo __unused, siginfo_t *info, void *uap __unused) {
128 	ReadSigbus::s_si_addr = info->si_addr;
129 	longjmp(ReadSigbus::s_jmpbuf, 1);
130 }
131 
132 jmp_buf ReadSigbus::s_jmpbuf;
133 void *ReadSigbus::s_si_addr;
134 
135 /* AIO reads need to set the header's pid field correctly */
136 /* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236379 */
137 TEST_F(AioRead, aio_read)
138 {
139 	const char FULLPATH[] = "mountpoint/some_file.txt";
140 	const char RELPATH[] = "some_file.txt";
141 	const char *CONTENTS = "abcdefgh";
142 	uint64_t ino = 42;
143 	int fd;
144 	ssize_t bufsize = strlen(CONTENTS);
145 	uint8_t buf[bufsize];
146 	struct aiocb iocb, *piocb;
147 
148 	expect_lookup(RELPATH, ino, bufsize);
149 	expect_open(ino, 0, 1);
150 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
151 
152 	fd = open(FULLPATH, O_RDONLY);
153 	ASSERT_LE(0, fd) << strerror(errno);
154 
155 	iocb.aio_nbytes = bufsize;
156 	iocb.aio_fildes = fd;
157 	iocb.aio_buf = buf;
158 	iocb.aio_offset = 0;
159 	iocb.aio_sigevent.sigev_notify = SIGEV_NONE;
160 	ASSERT_EQ(0, aio_read(&iocb)) << strerror(errno);
161 	ASSERT_EQ(bufsize, aio_waitcomplete(&piocb, NULL)) << strerror(errno);
162 	ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize));
163 
164 	leak(fd);
165 }
166 
167 /*
168  * Without the FUSE_ASYNC_READ mount option, fuse(4) should ensure that there
169  * is at most one outstanding read operation per file handle
170  */
171 TEST_F(AioRead, async_read_disabled)
172 {
173 	const char FULLPATH[] = "mountpoint/some_file.txt";
174 	const char RELPATH[] = "some_file.txt";
175 	uint64_t ino = 42;
176 	int fd;
177 	ssize_t bufsize = 50;
178 	char buf0[bufsize], buf1[bufsize];
179 	off_t off0 = 0;
180 	off_t off1 = m_maxbcachebuf;
181 	struct aiocb iocb0, iocb1;
182 	volatile sig_atomic_t read_count = 0;
183 
184 	expect_lookup(RELPATH, ino, 131072);
185 	expect_open(ino, 0, 1);
186 	EXPECT_CALL(*m_mock, process(
187 		ResultOf([=](auto in) {
188 			return (in.header.opcode == FUSE_READ &&
189 				in.header.nodeid == ino &&
190 				in.body.read.fh == FH &&
191 				in.body.read.offset == (uint64_t)off0);
192 		}, Eq(true)),
193 		_)
194 	).WillRepeatedly(Invoke([&](auto in __unused, auto &out __unused) {
195 		read_count++;
196 		/* Filesystem is slow to respond */
197 	}));
198 	EXPECT_CALL(*m_mock, process(
199 		ResultOf([=](auto in) {
200 			return (in.header.opcode == FUSE_READ &&
201 				in.header.nodeid == ino &&
202 				in.body.read.fh == FH &&
203 				in.body.read.offset == (uint64_t)off1);
204 		}, Eq(true)),
205 		_)
206 	).WillRepeatedly(Invoke([&](auto in __unused, auto &out __unused) {
207 		read_count++;
208 		/* Filesystem is slow to respond */
209 	}));
210 
211 	fd = open(FULLPATH, O_RDONLY);
212 	ASSERT_LE(0, fd) << strerror(errno);
213 
214 	/*
215 	 * Submit two AIO read requests, and respond to neither.  If the
216 	 * filesystem ever gets the second read request, then we failed to
217 	 * limit outstanding reads.
218 	 */
219 	iocb0.aio_nbytes = bufsize;
220 	iocb0.aio_fildes = fd;
221 	iocb0.aio_buf = buf0;
222 	iocb0.aio_offset = off0;
223 	iocb0.aio_sigevent.sigev_notify = SIGEV_NONE;
224 	ASSERT_EQ(0, aio_read(&iocb0)) << strerror(errno);
225 
226 	iocb1.aio_nbytes = bufsize;
227 	iocb1.aio_fildes = fd;
228 	iocb1.aio_buf = buf1;
229 	iocb1.aio_offset = off1;
230 	iocb1.aio_sigevent.sigev_notify = SIGEV_NONE;
231 	ASSERT_EQ(0, aio_read(&iocb1)) << strerror(errno);
232 
233 	/*
234 	 * Sleep for awhile to make sure the kernel has had a chance to issue
235 	 * the second read, even though the first has not yet returned
236 	 */
237 	nap();
238 	EXPECT_EQ(read_count, 1);
239 
240 	m_mock->kill_daemon();
241 	/* Wait for AIO activity to complete, but ignore errors */
242 	(void)aio_waitcomplete(NULL, NULL);
243 
244 	leak(fd);
245 }
246 
247 /*
248  * With the FUSE_ASYNC_READ mount option, fuse(4) may issue multiple
249  * simultaneous read requests on the same file handle.
250  */
251 TEST_F(AsyncRead, async_read)
252 {
253 	const char FULLPATH[] = "mountpoint/some_file.txt";
254 	const char RELPATH[] = "some_file.txt";
255 	uint64_t ino = 42;
256 	int fd;
257 	ssize_t bufsize = 50;
258 	char buf0[bufsize], buf1[bufsize];
259 	off_t off0 = 0;
260 	off_t off1 = m_maxbcachebuf;
261 	off_t fsize = 2 * m_maxbcachebuf;
262 	struct aiocb iocb0, iocb1;
263 	sem_t sem;
264 
265 	ASSERT_EQ(0, sem_init(&sem, 0, 0)) << strerror(errno);
266 
267 	expect_lookup(RELPATH, ino, fsize);
268 	expect_open(ino, 0, 1);
269 	EXPECT_CALL(*m_mock, process(
270 		ResultOf([=](auto in) {
271 			return (in.header.opcode == FUSE_READ &&
272 				in.header.nodeid == ino &&
273 				in.body.read.fh == FH &&
274 				in.body.read.offset == (uint64_t)off0);
275 		}, Eq(true)),
276 		_)
277 	).WillOnce(Invoke([&](auto in __unused, auto &out __unused) {
278 		sem_post(&sem);
279 		/* Filesystem is slow to respond */
280 	}));
281 	EXPECT_CALL(*m_mock, process(
282 		ResultOf([=](auto in) {
283 			return (in.header.opcode == FUSE_READ &&
284 				in.header.nodeid == ino &&
285 				in.body.read.fh == FH &&
286 				in.body.read.offset == (uint64_t)off1);
287 		}, Eq(true)),
288 		_)
289 	).WillOnce(Invoke([&](auto in __unused, auto &out __unused) {
290 		sem_post(&sem);
291 		/* Filesystem is slow to respond */
292 	}));
293 
294 	fd = open(FULLPATH, O_RDONLY);
295 	ASSERT_LE(0, fd) << strerror(errno);
296 
297 	/*
298 	 * Submit two AIO read requests, but respond to neither.  Ensure that
299 	 * we received both.
300 	 */
301 	iocb0.aio_nbytes = bufsize;
302 	iocb0.aio_fildes = fd;
303 	iocb0.aio_buf = buf0;
304 	iocb0.aio_offset = off0;
305 	iocb0.aio_sigevent.sigev_notify = SIGEV_NONE;
306 	ASSERT_EQ(0, aio_read(&iocb0)) << strerror(errno);
307 
308 	iocb1.aio_nbytes = bufsize;
309 	iocb1.aio_fildes = fd;
310 	iocb1.aio_buf = buf1;
311 	iocb1.aio_offset = off1;
312 	iocb1.aio_sigevent.sigev_notify = SIGEV_NONE;
313 	ASSERT_EQ(0, aio_read(&iocb1)) << strerror(errno);
314 
315 	/* Wait until both reads have reached the daemon */
316 	ASSERT_EQ(0, sem_wait(&sem)) << strerror(errno);
317 	ASSERT_EQ(0, sem_wait(&sem)) << strerror(errno);
318 
319 	m_mock->kill_daemon();
320 	/* Wait for AIO activity to complete, but ignore errors */
321 	(void)aio_waitcomplete(NULL, NULL);
322 
323 	leak(fd);
324 }
325 
326 /* 0-length reads shouldn't cause any confusion */
327 TEST_F(Read, direct_io_read_nothing)
328 {
329 	const char FULLPATH[] = "mountpoint/some_file.txt";
330 	const char RELPATH[] = "some_file.txt";
331 	uint64_t ino = 42;
332 	int fd;
333 	uint64_t offset = 100;
334 	char buf[80];
335 
336 	expect_lookup(RELPATH, ino, offset + 1000);
337 	expect_open(ino, FOPEN_DIRECT_IO, 1);
338 
339 	fd = open(FULLPATH, O_RDONLY);
340 	ASSERT_LE(0, fd) << strerror(errno);
341 
342 	ASSERT_EQ(0, pread(fd, buf, 0, offset)) << strerror(errno);
343 	leak(fd);
344 }
345 
346 /*
347  * With direct_io, reads should not fill the cache.  They should go straight to
348  * the daemon
349  */
350 TEST_F(Read, direct_io_pread)
351 {
352 	const char FULLPATH[] = "mountpoint/some_file.txt";
353 	const char RELPATH[] = "some_file.txt";
354 	const char *CONTENTS = "abcdefgh";
355 	uint64_t ino = 42;
356 	int fd;
357 	uint64_t offset = 100;
358 	ssize_t bufsize = strlen(CONTENTS);
359 	uint8_t buf[bufsize];
360 
361 	expect_lookup(RELPATH, ino, offset + bufsize);
362 	expect_open(ino, FOPEN_DIRECT_IO, 1);
363 	expect_read(ino, offset, bufsize, bufsize, CONTENTS);
364 
365 	fd = open(FULLPATH, O_RDONLY);
366 	ASSERT_LE(0, fd) << strerror(errno);
367 
368 	ASSERT_EQ(bufsize, pread(fd, buf, bufsize, offset)) << strerror(errno);
369 	ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize));
370 
371 	// With FOPEN_DIRECT_IO, the cache should be bypassed.  The server will
372 	// get a 2nd read request.
373 	expect_read(ino, offset, bufsize, bufsize, CONTENTS);
374 	ASSERT_EQ(bufsize, pread(fd, buf, bufsize, offset)) << strerror(errno);
375 	ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize));
376 	leak(fd);
377 }
378 
379 /*
380  * With direct_io, filesystems are allowed to return less data than is
381  * requested.  fuse(4) should return a short read to userland.
382  */
383 TEST_F(Read, direct_io_short_read)
384 {
385 	const char FULLPATH[] = "mountpoint/some_file.txt";
386 	const char RELPATH[] = "some_file.txt";
387 	const char *CONTENTS = "abcdefghijklmnop";
388 	uint64_t ino = 42;
389 	int fd;
390 	uint64_t offset = 100;
391 	ssize_t bufsize = strlen(CONTENTS);
392 	ssize_t halfbufsize = bufsize / 2;
393 	uint8_t buf[bufsize];
394 
395 	expect_lookup(RELPATH, ino, offset + bufsize);
396 	expect_open(ino, FOPEN_DIRECT_IO, 1);
397 	expect_read(ino, offset, bufsize, halfbufsize, CONTENTS);
398 
399 	fd = open(FULLPATH, O_RDONLY);
400 	ASSERT_LE(0, fd) << strerror(errno);
401 
402 	ASSERT_EQ(halfbufsize, pread(fd, buf, bufsize, offset))
403 		<< strerror(errno);
404 	ASSERT_EQ(0, memcmp(buf, CONTENTS, halfbufsize));
405 	leak(fd);
406 }
407 
408 TEST_F(Read, eio)
409 {
410 	const char FULLPATH[] = "mountpoint/some_file.txt";
411 	const char RELPATH[] = "some_file.txt";
412 	const char *CONTENTS = "abcdefgh";
413 	uint64_t ino = 42;
414 	int fd;
415 	ssize_t bufsize = strlen(CONTENTS);
416 	uint8_t buf[bufsize];
417 
418 	expect_lookup(RELPATH, ino, bufsize);
419 	expect_open(ino, 0, 1);
420 	EXPECT_CALL(*m_mock, process(
421 		ResultOf([=](auto in) {
422 			return (in.header.opcode == FUSE_READ);
423 		}, Eq(true)),
424 		_)
425 	).WillOnce(Invoke(ReturnErrno(EIO)));
426 
427 	fd = open(FULLPATH, O_RDONLY);
428 	ASSERT_LE(0, fd) << strerror(errno);
429 
430 	ASSERT_EQ(-1, read(fd, buf, bufsize)) << strerror(errno);
431 	ASSERT_EQ(EIO, errno);
432 	leak(fd);
433 }
434 
435 /*
436  * If the server returns a short read when direct io is not in use, that
437  * indicates EOF, because of a server-side truncation.  We should invalidate
438  * all cached attributes.  We may update the file size,
439  */
440 TEST_F(Read, eof)
441 {
442 	const char FULLPATH[] = "mountpoint/some_file.txt";
443 	const char RELPATH[] = "some_file.txt";
444 	const char *CONTENTS = "abcdefghijklmnop";
445 	uint64_t ino = 42;
446 	int fd;
447 	uint64_t offset = 100;
448 	ssize_t bufsize = strlen(CONTENTS);
449 	ssize_t partbufsize = 3 * bufsize / 4;
450 	ssize_t r;
451 	uint8_t buf[bufsize];
452 	struct stat sb;
453 
454 	expect_lookup(RELPATH, ino, offset + bufsize);
455 	expect_open(ino, 0, 1);
456 	expect_read(ino, 0, offset + bufsize, offset + partbufsize, CONTENTS);
457 	expect_getattr(ino, offset + partbufsize);
458 
459 	fd = open(FULLPATH, O_RDONLY);
460 	ASSERT_LE(0, fd) << strerror(errno);
461 
462 	r = pread(fd, buf, bufsize, offset);
463 	ASSERT_LE(0, r) << strerror(errno);
464 	EXPECT_EQ(partbufsize, r) << strerror(errno);
465 	ASSERT_EQ(0, fstat(fd, &sb));
466 	EXPECT_EQ((off_t)(offset + partbufsize), sb.st_size);
467 	leak(fd);
468 }
469 
470 /* Like Read.eof, but causes an entire buffer to be invalidated */
471 TEST_F(Read, eof_of_whole_buffer)
472 {
473 	const char FULLPATH[] = "mountpoint/some_file.txt";
474 	const char RELPATH[] = "some_file.txt";
475 	const char *CONTENTS = "abcdefghijklmnop";
476 	uint64_t ino = 42;
477 	int fd;
478 	ssize_t bufsize = strlen(CONTENTS);
479 	off_t old_filesize = m_maxbcachebuf * 2 + bufsize;
480 	uint8_t buf[bufsize];
481 	struct stat sb;
482 
483 	expect_lookup(RELPATH, ino, old_filesize);
484 	expect_open(ino, 0, 1);
485 	expect_read(ino, 2 * m_maxbcachebuf, bufsize, bufsize, CONTENTS);
486 	expect_read(ino, m_maxbcachebuf, m_maxbcachebuf, 0, CONTENTS);
487 	expect_getattr(ino, m_maxbcachebuf);
488 
489 	fd = open(FULLPATH, O_RDONLY);
490 	ASSERT_LE(0, fd) << strerror(errno);
491 
492 	/* Cache the third block */
493 	ASSERT_EQ(bufsize, pread(fd, buf, bufsize, m_maxbcachebuf * 2))
494 		<< strerror(errno);
495 	/* Try to read the 2nd block, but it's past EOF */
496 	ASSERT_EQ(0, pread(fd, buf, bufsize, m_maxbcachebuf))
497 		<< strerror(errno);
498 	ASSERT_EQ(0, fstat(fd, &sb));
499 	EXPECT_EQ((off_t)(m_maxbcachebuf), sb.st_size);
500 	leak(fd);
501 }
502 
503 /*
504  * With the keep_cache option, the kernel may keep its read cache across
505  * multiple open(2)s.
506  */
507 TEST_F(Read, keep_cache)
508 {
509 	const char FULLPATH[] = "mountpoint/some_file.txt";
510 	const char RELPATH[] = "some_file.txt";
511 	const char *CONTENTS = "abcdefgh";
512 	uint64_t ino = 42;
513 	int fd0, fd1;
514 	ssize_t bufsize = strlen(CONTENTS);
515 	uint8_t buf[bufsize];
516 
517 	FuseTest::expect_lookup(RELPATH, ino, S_IFREG | 0644, bufsize, 2);
518 	expect_open(ino, FOPEN_KEEP_CACHE, 2);
519 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
520 
521 	fd0 = open(FULLPATH, O_RDONLY);
522 	ASSERT_LE(0, fd0) << strerror(errno);
523 	ASSERT_EQ(bufsize, read(fd0, buf, bufsize)) << strerror(errno);
524 
525 	fd1 = open(FULLPATH, O_RDWR);
526 	ASSERT_LE(0, fd1) << strerror(errno);
527 
528 	/*
529 	 * This read should be serviced by cache, even though it's on the other
530 	 * file descriptor
531 	 */
532 	ASSERT_EQ(bufsize, read(fd1, buf, bufsize)) << strerror(errno);
533 
534 	leak(fd0);
535 	leak(fd1);
536 }
537 
538 /*
539  * Without the keep_cache option, the kernel should drop its read caches on
540  * every open
541  */
542 TEST_F(Read, keep_cache_disabled)
543 {
544 	const char FULLPATH[] = "mountpoint/some_file.txt";
545 	const char RELPATH[] = "some_file.txt";
546 	const char *CONTENTS = "abcdefgh";
547 	uint64_t ino = 42;
548 	int fd0, fd1;
549 	ssize_t bufsize = strlen(CONTENTS);
550 	uint8_t buf[bufsize];
551 
552 	FuseTest::expect_lookup(RELPATH, ino, S_IFREG | 0644, bufsize, 2);
553 	expect_open(ino, 0, 2);
554 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
555 
556 	fd0 = open(FULLPATH, O_RDONLY);
557 	ASSERT_LE(0, fd0) << strerror(errno);
558 	ASSERT_EQ(bufsize, read(fd0, buf, bufsize)) << strerror(errno);
559 
560 	fd1 = open(FULLPATH, O_RDWR);
561 	ASSERT_LE(0, fd1) << strerror(errno);
562 
563 	/*
564 	 * This read should not be serviced by cache, even though it's on the
565 	 * original file descriptor
566 	 */
567 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
568 	ASSERT_EQ(0, lseek(fd0, 0, SEEK_SET)) << strerror(errno);
569 	ASSERT_EQ(bufsize, read(fd0, buf, bufsize)) << strerror(errno);
570 
571 	leak(fd0);
572 	leak(fd1);
573 }
574 
575 TEST_F(Read, mmap)
576 {
577 	const char FULLPATH[] = "mountpoint/some_file.txt";
578 	const char RELPATH[] = "some_file.txt";
579 	const char *CONTENTS = "abcdefgh";
580 	uint64_t ino = 42;
581 	int fd;
582 	ssize_t len;
583 	size_t bufsize = strlen(CONTENTS);
584 	void *p;
585 
586 	len = getpagesize();
587 
588 	expect_lookup(RELPATH, ino, bufsize);
589 	expect_open(ino, 0, 1);
590 	EXPECT_CALL(*m_mock, process(
591 		ResultOf([=](auto in) {
592 			return (in.header.opcode == FUSE_READ &&
593 				in.header.nodeid == ino &&
594 				in.body.read.fh == Read::FH &&
595 				in.body.read.offset == 0 &&
596 				in.body.read.size == bufsize);
597 		}, Eq(true)),
598 		_)
599 	).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
600 		out.header.len = sizeof(struct fuse_out_header) + bufsize;
601 		memmove(out.body.bytes, CONTENTS, bufsize);
602 	})));
603 
604 	fd = open(FULLPATH, O_RDONLY);
605 	ASSERT_LE(0, fd) << strerror(errno);
606 
607 	p = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
608 	ASSERT_NE(MAP_FAILED, p) << strerror(errno);
609 
610 	ASSERT_EQ(0, memcmp(p, CONTENTS, bufsize));
611 
612 	ASSERT_EQ(0, munmap(p, len)) << strerror(errno);
613 	leak(fd);
614 }
615 
616 /* Read of an mmap()ed file fails */
617 TEST_F(ReadSigbus, mmap_eio)
618 {
619 	const char FULLPATH[] = "mountpoint/some_file.txt";
620 	const char RELPATH[] = "some_file.txt";
621 	const char *CONTENTS = "abcdefgh";
622 	struct sigaction sa;
623 	uint64_t ino = 42;
624 	int fd;
625 	ssize_t len;
626 	size_t bufsize = strlen(CONTENTS);
627 	void *p;
628 
629 	len = getpagesize();
630 
631 	expect_lookup(RELPATH, ino, bufsize);
632 	expect_open(ino, 0, 1);
633 	EXPECT_CALL(*m_mock, process(
634 		ResultOf([=](auto in) {
635 			return (in.header.opcode == FUSE_READ &&
636 				in.header.nodeid == ino &&
637 				in.body.read.fh == Read::FH);
638 		}, Eq(true)),
639 		_)
640 	).WillRepeatedly(Invoke(ReturnErrno(EIO)));
641 
642 	fd = open(FULLPATH, O_RDONLY);
643 	ASSERT_LE(0, fd) << strerror(errno);
644 
645 	p = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
646 	ASSERT_NE(MAP_FAILED, p) << strerror(errno);
647 
648 	/* Accessing the mapped page should return SIGBUS.  */
649 
650 	bzero(&sa, sizeof(sa));
651 	sa.sa_handler = SIG_DFL;
652 	sa.sa_sigaction = handle_sigbus;
653 	sa.sa_flags = SA_RESETHAND | SA_SIGINFO;
654 	ASSERT_EQ(0, sigaction(SIGBUS, &sa, NULL)) << strerror(errno);
655 	if (setjmp(ReadSigbus::s_jmpbuf) == 0) {
656 		atomic_signal_fence(std::memory_order::memory_order_seq_cst);
657 		volatile char x __unused = *(volatile char*)p;
658 		FAIL() << "shouldn't get here";
659 	}
660 
661 	ASSERT_EQ(p, ReadSigbus::s_si_addr);
662 	ASSERT_EQ(0, munmap(p, len)) << strerror(errno);
663 	leak(fd);
664 }
665 
666 /*
667  * A read via mmap comes up short, indicating that the file was truncated
668  * server-side.
669  */
670 TEST_F(Read, mmap_eof)
671 {
672 	const char FULLPATH[] = "mountpoint/some_file.txt";
673 	const char RELPATH[] = "some_file.txt";
674 	const char *CONTENTS = "abcdefgh";
675 	uint64_t ino = 42;
676 	int fd;
677 	ssize_t len;
678 	size_t bufsize = strlen(CONTENTS);
679 	struct stat sb;
680 	void *p;
681 
682 	len = getpagesize();
683 
684 	expect_lookup(RELPATH, ino, m_maxbcachebuf);
685 	expect_open(ino, 0, 1);
686 	EXPECT_CALL(*m_mock, process(
687 		ResultOf([=](auto in) {
688 			return (in.header.opcode == FUSE_READ &&
689 				in.header.nodeid == ino &&
690 				in.body.read.fh == Read::FH &&
691 				in.body.read.offset == 0 &&
692 				in.body.read.size == (uint32_t)m_maxbcachebuf);
693 		}, Eq(true)),
694 		_)
695 	).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
696 		out.header.len = sizeof(struct fuse_out_header) + bufsize;
697 		memmove(out.body.bytes, CONTENTS, bufsize);
698 	})));
699 	expect_getattr(ino, bufsize);
700 
701 	fd = open(FULLPATH, O_RDONLY);
702 	ASSERT_LE(0, fd) << strerror(errno);
703 
704 	p = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
705 	ASSERT_NE(MAP_FAILED, p) << strerror(errno);
706 
707 	/* The file size should be automatically truncated */
708 	ASSERT_EQ(0, memcmp(p, CONTENTS, bufsize));
709 	ASSERT_EQ(0, fstat(fd, &sb)) << strerror(errno);
710 	EXPECT_EQ((off_t)bufsize, sb.st_size);
711 
712 	ASSERT_EQ(0, munmap(p, len)) << strerror(errno);
713 	leak(fd);
714 }
715 
716 /*
717  * During VOP_GETPAGES, the FUSE server fails a FUSE_GETATTR operation.  This
718  * almost certainly indicates a buggy FUSE server, and our goal should be not
719  * to panic.  Instead, generate SIGBUS.
720  */
721 TEST_F(ReadSigbus, mmap_getblksz_fail)
722 {
723 	const char FULLPATH[] = "mountpoint/some_file.txt";
724 	const char RELPATH[] = "some_file.txt";
725 	const char *CONTENTS = "abcdefgh";
726 	struct sigaction sa;
727 	Sequence seq;
728 	uint64_t ino = 42;
729 	int fd;
730 	ssize_t len;
731 	size_t bufsize = strlen(CONTENTS);
732 	mode_t mode = S_IFREG | 0644;
733 	void *p;
734 
735 	len = getpagesize();
736 
737 	FuseTest::expect_lookup(RELPATH, ino, mode, bufsize, 1, 0);
738 	/* Expect two GETATTR calls that succeed, followed by one that fail. */
739 	EXPECT_CALL(*m_mock, process(
740 		ResultOf([=](auto in) {
741 			return (in.header.opcode == FUSE_GETATTR &&
742 				in.header.nodeid == ino);
743 		}, Eq(true)),
744 		_)
745 	).Times(2)
746 	.InSequence(seq)
747 	.WillRepeatedly(Invoke(ReturnImmediate([=](auto i __unused, auto& out) {
748 		SET_OUT_HEADER_LEN(out, attr);
749 		out.body.attr.attr.ino = ino;
750 		out.body.attr.attr.mode = mode;
751 		out.body.attr.attr.size = bufsize;
752 		out.body.attr.attr_valid = 0;
753 	})));
754 	EXPECT_CALL(*m_mock, process(
755 		ResultOf([=](auto in) {
756 			return (in.header.opcode == FUSE_GETATTR &&
757 				in.header.nodeid == ino);
758 		}, Eq(true)),
759 		_)
760 	).InSequence(seq)
761 	.WillRepeatedly(Invoke(ReturnErrno(EIO)));
762 	expect_open(ino, 0, 1);
763 	EXPECT_CALL(*m_mock, process(
764 		ResultOf([=](auto in) {
765 			return (in.header.opcode == FUSE_READ);
766 		}, Eq(true)),
767 		_)
768 	).Times(0);
769 
770 	fd = open(FULLPATH, O_RDONLY);
771 	ASSERT_LE(0, fd) << strerror(errno);
772 
773 	p = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
774 	ASSERT_NE(MAP_FAILED, p) << strerror(errno);
775 
776 	/* Accessing the mapped page should return SIGBUS.  */
777 	bzero(&sa, sizeof(sa));
778 	sa.sa_handler = SIG_DFL;
779 	sa.sa_sigaction = handle_sigbus;
780 	sa.sa_flags = SA_RESETHAND | SA_SIGINFO;
781 	ASSERT_EQ(0, sigaction(SIGBUS, &sa, NULL)) << strerror(errno);
782 	if (setjmp(ReadSigbus::s_jmpbuf) == 0) {
783 		atomic_signal_fence(std::memory_order::memory_order_seq_cst);
784 		volatile char x __unused = *(volatile char*)p;
785 		FAIL() << "shouldn't get here";
786 	}
787 
788 	ASSERT_EQ(p, ReadSigbus::s_si_addr);
789 	ASSERT_EQ(0, munmap(p, len)) << strerror(errno);
790 	leak(fd);
791 }
792 
793 /*
794  * Just as when FOPEN_DIRECT_IO is used, reads with O_DIRECT should bypass
795  * cache and to straight to the daemon
796  */
797 TEST_F(Read, o_direct)
798 {
799 	const char FULLPATH[] = "mountpoint/some_file.txt";
800 	const char RELPATH[] = "some_file.txt";
801 	const char *CONTENTS = "abcdefgh";
802 	uint64_t ino = 42;
803 	int fd;
804 	ssize_t bufsize = strlen(CONTENTS);
805 	uint8_t buf[bufsize];
806 
807 	expect_lookup(RELPATH, ino, bufsize);
808 	expect_open(ino, 0, 1);
809 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
810 
811 	fd = open(FULLPATH, O_RDONLY);
812 	ASSERT_LE(0, fd) << strerror(errno);
813 
814 	// Fill the cache
815 	ASSERT_EQ(bufsize, read(fd, buf, bufsize)) << strerror(errno);
816 	ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize));
817 
818 	// Reads with o_direct should bypass the cache
819 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
820 	ASSERT_EQ(0, fcntl(fd, F_SETFL, O_DIRECT)) << strerror(errno);
821 	ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)) << strerror(errno);
822 	ASSERT_EQ(bufsize, read(fd, buf, bufsize)) << strerror(errno);
823 	ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize));
824 
825 	leak(fd);
826 }
827 
828 TEST_F(Read, pread)
829 {
830 	const char FULLPATH[] = "mountpoint/some_file.txt";
831 	const char RELPATH[] = "some_file.txt";
832 	const char *CONTENTS = "abcdefgh";
833 	uint64_t ino = 42;
834 	int fd;
835 	/*
836 	 * Set offset to a maxbcachebuf boundary so we'll be sure what offset
837 	 * to read from.  Without this, the read might start at a lower offset.
838 	 */
839 	uint64_t offset = m_maxbcachebuf;
840 	ssize_t bufsize = strlen(CONTENTS);
841 	uint8_t buf[bufsize];
842 
843 	expect_lookup(RELPATH, ino, offset + bufsize);
844 	expect_open(ino, 0, 1);
845 	expect_read(ino, offset, bufsize, bufsize, CONTENTS);
846 
847 	fd = open(FULLPATH, O_RDONLY);
848 	ASSERT_LE(0, fd) << strerror(errno);
849 
850 	ASSERT_EQ(bufsize, pread(fd, buf, bufsize, offset)) << strerror(errno);
851 	ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize));
852 	leak(fd);
853 }
854 
855 TEST_F(Read, read)
856 {
857 	const char FULLPATH[] = "mountpoint/some_file.txt";
858 	const char RELPATH[] = "some_file.txt";
859 	const char *CONTENTS = "abcdefgh";
860 	uint64_t ino = 42;
861 	int fd;
862 	ssize_t bufsize = strlen(CONTENTS);
863 	uint8_t buf[bufsize];
864 
865 	expect_lookup(RELPATH, ino, bufsize);
866 	expect_open(ino, 0, 1);
867 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
868 
869 	fd = open(FULLPATH, O_RDONLY);
870 	ASSERT_LE(0, fd) << strerror(errno);
871 
872 	ASSERT_EQ(bufsize, read(fd, buf, bufsize)) << strerror(errno);
873 	ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize));
874 
875 	leak(fd);
876 }
877 
878 TEST_F(Read_7_8, read)
879 {
880 	const char FULLPATH[] = "mountpoint/some_file.txt";
881 	const char RELPATH[] = "some_file.txt";
882 	const char *CONTENTS = "abcdefgh";
883 	uint64_t ino = 42;
884 	int fd;
885 	ssize_t bufsize = strlen(CONTENTS);
886 	uint8_t buf[bufsize];
887 
888 	expect_lookup(RELPATH, ino, bufsize);
889 	expect_open(ino, 0, 1);
890 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
891 
892 	fd = open(FULLPATH, O_RDONLY);
893 	ASSERT_LE(0, fd) << strerror(errno);
894 
895 	ASSERT_EQ(bufsize, read(fd, buf, bufsize)) << strerror(errno);
896 	ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize));
897 
898 	leak(fd);
899 }
900 
901 /*
902  * If cacheing is enabled, the kernel should try to read an entire cache block
903  * at a time.
904  */
905 TEST_F(Read, cache_block)
906 {
907 	const char FULLPATH[] = "mountpoint/some_file.txt";
908 	const char RELPATH[] = "some_file.txt";
909 	const char *CONTENTS0 = "abcdefghijklmnop";
910 	uint64_t ino = 42;
911 	int fd;
912 	ssize_t bufsize = 8;
913 	ssize_t filesize = m_maxbcachebuf * 2;
914 	char *contents;
915 	char buf[bufsize];
916 	const char *contents1 = CONTENTS0 + bufsize;
917 
918 	contents = (char*)calloc(1, filesize);
919 	ASSERT_NE(nullptr, contents);
920 	memmove(contents, CONTENTS0, strlen(CONTENTS0));
921 
922 	expect_lookup(RELPATH, ino, filesize);
923 	expect_open(ino, 0, 1);
924 	expect_read(ino, 0, m_maxbcachebuf, m_maxbcachebuf,
925 		contents);
926 
927 	fd = open(FULLPATH, O_RDONLY);
928 	ASSERT_LE(0, fd) << strerror(errno);
929 
930 	ASSERT_EQ(bufsize, read(fd, buf, bufsize)) << strerror(errno);
931 	ASSERT_EQ(0, memcmp(buf, CONTENTS0, bufsize));
932 
933 	/* A subsequent read should be serviced by cache */
934 	ASSERT_EQ(bufsize, read(fd, buf, bufsize)) << strerror(errno);
935 	ASSERT_EQ(0, memcmp(buf, contents1, bufsize));
936 	leak(fd);
937 	free(contents);
938 }
939 
940 /* Reading with sendfile should work (though it obviously won't be 0-copy) */
941 TEST_F(Read, sendfile)
942 {
943 	const char FULLPATH[] = "mountpoint/some_file.txt";
944 	const char RELPATH[] = "some_file.txt";
945 	const char *CONTENTS = "abcdefgh";
946 	uint64_t ino = 42;
947 	int fd;
948 	size_t bufsize = strlen(CONTENTS);
949 	uint8_t buf[bufsize];
950 	int sp[2];
951 	off_t sbytes;
952 
953 	expect_lookup(RELPATH, ino, bufsize);
954 	expect_open(ino, 0, 1);
955 	EXPECT_CALL(*m_mock, process(
956 		ResultOf([=](auto in) {
957 			return (in.header.opcode == FUSE_READ &&
958 				in.header.nodeid == ino &&
959 				in.body.read.fh == Read::FH &&
960 				in.body.read.offset == 0 &&
961 				in.body.read.size == bufsize);
962 		}, Eq(true)),
963 		_)
964 	).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
965 		out.header.len = sizeof(struct fuse_out_header) + bufsize;
966 		memmove(out.body.bytes, CONTENTS, bufsize);
967 	})));
968 
969 	ASSERT_EQ(0, socketpair(PF_LOCAL, SOCK_STREAM, 0, sp))
970 		<< strerror(errno);
971 	fd = open(FULLPATH, O_RDONLY);
972 	ASSERT_LE(0, fd) << strerror(errno);
973 
974 	ASSERT_EQ(0, sendfile(fd, sp[1], 0, bufsize, NULL, &sbytes, 0))
975 		<< strerror(errno);
976 	ASSERT_EQ(static_cast<ssize_t>(bufsize), read(sp[0], buf, bufsize))
977 		<< strerror(errno);
978 	ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize));
979 
980 	close(sp[1]);
981 	close(sp[0]);
982 	leak(fd);
983 }
984 
985 /* sendfile should fail gracefully if fuse declines the read */
986 /* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236466 */
987 TEST_F(Read, sendfile_eio)
988 {
989 	const char FULLPATH[] = "mountpoint/some_file.txt";
990 	const char RELPATH[] = "some_file.txt";
991 	const char *CONTENTS = "abcdefgh";
992 	uint64_t ino = 42;
993 	int fd;
994 	ssize_t bufsize = strlen(CONTENTS);
995 	int sp[2];
996 	off_t sbytes;
997 
998 	expect_lookup(RELPATH, ino, bufsize);
999 	expect_open(ino, 0, 1);
1000 	EXPECT_CALL(*m_mock, process(
1001 		ResultOf([=](auto in) {
1002 			return (in.header.opcode == FUSE_READ);
1003 		}, Eq(true)),
1004 		_)
1005 	).WillOnce(Invoke(ReturnErrno(EIO)));
1006 
1007 	ASSERT_EQ(0, socketpair(PF_LOCAL, SOCK_STREAM, 0, sp))
1008 		<< strerror(errno);
1009 	fd = open(FULLPATH, O_RDONLY);
1010 	ASSERT_LE(0, fd) << strerror(errno);
1011 
1012 	ASSERT_NE(0, sendfile(fd, sp[1], 0, bufsize, NULL, &sbytes, 0));
1013 
1014 	close(sp[1]);
1015 	close(sp[0]);
1016 	leak(fd);
1017 }
1018 
1019 /*
1020  * Sequential reads should use readahead.  And if allowed, large reads should
1021  * be clustered.
1022  */
1023 TEST_P(ReadAhead, readahead) {
1024 	const char FULLPATH[] = "mountpoint/some_file.txt";
1025 	const char RELPATH[] = "some_file.txt";
1026 	uint64_t ino = 42;
1027 	int fd, maxcontig, clustersize;
1028 	ssize_t bufsize = 4 * m_maxbcachebuf;
1029 	ssize_t filesize = bufsize;
1030 	uint64_t len;
1031 	char *rbuf, *contents;
1032 	off_t offs;
1033 
1034 	contents = (char*)malloc(filesize);
1035 	ASSERT_NE(nullptr, contents);
1036 	memset(contents, 'X', filesize);
1037 	rbuf = (char*)calloc(1, bufsize);
1038 
1039 	expect_lookup(RELPATH, ino, filesize);
1040 	expect_open(ino, 0, 1);
1041 	maxcontig = m_noclusterr ? m_maxbcachebuf :
1042 		m_maxbcachebuf + m_maxreadahead;
1043 	clustersize = MIN(maxcontig, m_maxphys);
1044 	for (offs = 0; offs < bufsize; offs += clustersize) {
1045 		len = std::min((size_t)clustersize, (size_t)(filesize - offs));
1046 		expect_read(ino, offs, len, len, contents + offs);
1047 	}
1048 
1049 	fd = open(FULLPATH, O_RDONLY);
1050 	ASSERT_LE(0, fd) << strerror(errno);
1051 
1052 	/* Set the internal readahead counter to a "large" value */
1053 	ASSERT_EQ(0, fcntl(fd, F_READAHEAD, 1'000'000'000)) << strerror(errno);
1054 
1055 	ASSERT_EQ(bufsize, read(fd, rbuf, bufsize)) << strerror(errno);
1056 	ASSERT_EQ(0, memcmp(rbuf, contents, bufsize));
1057 
1058 	leak(fd);
1059 	free(rbuf);
1060 	free(contents);
1061 }
1062 
1063 INSTANTIATE_TEST_CASE_P(RA, ReadAhead,
1064 	Values(tuple<bool, int>(false, 0),
1065 	       tuple<bool, int>(false, 1),
1066 	       tuple<bool, int>(false, 2),
1067 	       tuple<bool, int>(false, 3),
1068 	       tuple<bool, int>(true, 0),
1069 	       tuple<bool, int>(true, 1),
1070 	       tuple<bool, int>(true, 2)));
1071