xref: /freebsd/tests/sys/fs/fusefs/read.cc (revision 7fc0921d7e3c52f66ca8e47c0413ee46f6d73328)
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 
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 <unistd.h>
42 }
43 
44 #include "mockfs.hh"
45 #include "utils.hh"
46 
47 using namespace testing;
48 
49 class Read: public FuseTest {
50 
51 public:
52 void expect_lookup(const char *relpath, uint64_t ino, uint64_t size)
53 {
54 	FuseTest::expect_lookup(relpath, ino, S_IFREG | 0644, size, 1);
55 }
56 };
57 
58 class Read_7_8: public FuseTest {
59 public:
60 virtual void SetUp() {
61 	m_kernel_minor_version = 8;
62 	FuseTest::SetUp();
63 }
64 
65 void expect_lookup(const char *relpath, uint64_t ino, uint64_t size)
66 {
67 	FuseTest::expect_lookup_7_8(relpath, ino, S_IFREG | 0644, size, 1);
68 }
69 };
70 
71 class AioRead: public Read {
72 public:
73 virtual void SetUp() {
74 	const char *node = "vfs.aio.enable_unsafe";
75 	int val = 0;
76 	size_t size = sizeof(val);
77 
78 	FuseTest::SetUp();
79 
80 	ASSERT_EQ(0, sysctlbyname(node, &val, &size, NULL, 0))
81 		<< strerror(errno);
82 	if (!val)
83 		GTEST_SKIP() <<
84 			"vfs.aio.enable_unsafe must be set for this test";
85 }
86 };
87 
88 class AsyncRead: public AioRead {
89 	virtual void SetUp() {
90 		m_init_flags = FUSE_ASYNC_READ;
91 		AioRead::SetUp();
92 	}
93 };
94 
95 class ReadAhead: public Read,
96 		 public WithParamInterface<tuple<bool, int>>
97 {
98 	virtual void SetUp() {
99 		int val;
100 		const char *node = "vfs.maxbcachebuf";
101 		size_t size = sizeof(val);
102 		ASSERT_EQ(0, sysctlbyname(node, &val, &size, NULL, 0))
103 			<< strerror(errno);
104 
105 		m_maxreadahead = val * get<1>(GetParam());
106 		m_noclusterr = get<0>(GetParam());
107 		Read::SetUp();
108 	}
109 };
110 
111 /* AIO reads need to set the header's pid field correctly */
112 /* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236379 */
113 TEST_F(AioRead, aio_read)
114 {
115 	const char FULLPATH[] = "mountpoint/some_file.txt";
116 	const char RELPATH[] = "some_file.txt";
117 	const char *CONTENTS = "abcdefgh";
118 	uint64_t ino = 42;
119 	int fd;
120 	ssize_t bufsize = strlen(CONTENTS);
121 	char buf[bufsize];
122 	struct aiocb iocb, *piocb;
123 
124 	expect_lookup(RELPATH, ino, bufsize);
125 	expect_open(ino, 0, 1);
126 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
127 
128 	fd = open(FULLPATH, O_RDONLY);
129 	ASSERT_LE(0, fd) << strerror(errno);
130 
131 	iocb.aio_nbytes = bufsize;
132 	iocb.aio_fildes = fd;
133 	iocb.aio_buf = buf;
134 	iocb.aio_offset = 0;
135 	iocb.aio_sigevent.sigev_notify = SIGEV_NONE;
136 	ASSERT_EQ(0, aio_read(&iocb)) << strerror(errno);
137 	ASSERT_EQ(bufsize, aio_waitcomplete(&piocb, NULL)) << strerror(errno);
138 	ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize));
139 
140 	leak(fd);
141 }
142 
143 /*
144  * Without the FUSE_ASYNC_READ mount option, fuse(4) should ensure that there
145  * is at most one outstanding read operation per file handle
146  */
147 TEST_F(AioRead, async_read_disabled)
148 {
149 	const char FULLPATH[] = "mountpoint/some_file.txt";
150 	const char RELPATH[] = "some_file.txt";
151 	uint64_t ino = 42;
152 	int fd;
153 	ssize_t bufsize = 50;
154 	char buf0[bufsize], buf1[bufsize];
155 	off_t off0 = 0;
156 	off_t off1 = m_maxbcachebuf;
157 	struct aiocb iocb0, iocb1;
158 	volatile sig_atomic_t read_count = 0;
159 
160 	expect_lookup(RELPATH, ino, 131072);
161 	expect_open(ino, 0, 1);
162 	EXPECT_CALL(*m_mock, process(
163 		ResultOf([=](auto in) {
164 			return (in.header.opcode == FUSE_READ &&
165 				in.header.nodeid == ino &&
166 				in.body.read.fh == FH &&
167 				in.body.read.offset == (uint64_t)off0);
168 		}, Eq(true)),
169 		_)
170 	).WillRepeatedly(Invoke([&](auto in __unused, auto &out __unused) {
171 		read_count++;
172 		/* Filesystem is slow to respond */
173 	}));
174 	EXPECT_CALL(*m_mock, process(
175 		ResultOf([=](auto in) {
176 			return (in.header.opcode == FUSE_READ &&
177 				in.header.nodeid == ino &&
178 				in.body.read.fh == FH &&
179 				in.body.read.offset == (uint64_t)off1);
180 		}, Eq(true)),
181 		_)
182 	).WillRepeatedly(Invoke([&](auto in __unused, auto &out __unused) {
183 		read_count++;
184 		/* Filesystem is slow to respond */
185 	}));
186 
187 	fd = open(FULLPATH, O_RDONLY);
188 	ASSERT_LE(0, fd) << strerror(errno);
189 
190 	/*
191 	 * Submit two AIO read requests, and respond to neither.  If the
192 	 * filesystem ever gets the second read request, then we failed to
193 	 * limit outstanding reads.
194 	 */
195 	iocb0.aio_nbytes = bufsize;
196 	iocb0.aio_fildes = fd;
197 	iocb0.aio_buf = buf0;
198 	iocb0.aio_offset = off0;
199 	iocb0.aio_sigevent.sigev_notify = SIGEV_NONE;
200 	ASSERT_EQ(0, aio_read(&iocb0)) << strerror(errno);
201 
202 	iocb1.aio_nbytes = bufsize;
203 	iocb1.aio_fildes = fd;
204 	iocb1.aio_buf = buf1;
205 	iocb1.aio_offset = off1;
206 	iocb1.aio_sigevent.sigev_notify = SIGEV_NONE;
207 	ASSERT_EQ(0, aio_read(&iocb1)) << strerror(errno);
208 
209 	/*
210 	 * Sleep for awhile to make sure the kernel has had a chance to issue
211 	 * the second read, even though the first has not yet returned
212 	 */
213 	nap();
214 	EXPECT_EQ(read_count, 1);
215 
216 	m_mock->kill_daemon();
217 	/* Wait for AIO activity to complete, but ignore errors */
218 	(void)aio_waitcomplete(NULL, NULL);
219 
220 	leak(fd);
221 }
222 
223 /*
224  * With the FUSE_ASYNC_READ mount option, fuse(4) may issue multiple
225  * simultaneous read requests on the same file handle.
226  */
227 TEST_F(AsyncRead, async_read)
228 {
229 	const char FULLPATH[] = "mountpoint/some_file.txt";
230 	const char RELPATH[] = "some_file.txt";
231 	uint64_t ino = 42;
232 	int fd;
233 	ssize_t bufsize = 50;
234 	char buf0[bufsize], buf1[bufsize];
235 	off_t off0 = 0;
236 	off_t off1 = m_maxbcachebuf;
237 	off_t fsize = 2 * m_maxbcachebuf;
238 	struct aiocb iocb0, iocb1;
239 	sem_t sem;
240 
241 	ASSERT_EQ(0, sem_init(&sem, 0, 0)) << strerror(errno);
242 
243 	expect_lookup(RELPATH, ino, fsize);
244 	expect_open(ino, 0, 1);
245 	EXPECT_CALL(*m_mock, process(
246 		ResultOf([=](auto in) {
247 			return (in.header.opcode == FUSE_READ &&
248 				in.header.nodeid == ino &&
249 				in.body.read.fh == FH &&
250 				in.body.read.offset == (uint64_t)off0);
251 		}, Eq(true)),
252 		_)
253 	).WillOnce(Invoke([&](auto in __unused, auto &out __unused) {
254 		sem_post(&sem);
255 		/* Filesystem is slow to respond */
256 	}));
257 	EXPECT_CALL(*m_mock, process(
258 		ResultOf([=](auto in) {
259 			return (in.header.opcode == FUSE_READ &&
260 				in.header.nodeid == ino &&
261 				in.body.read.fh == FH &&
262 				in.body.read.offset == (uint64_t)off1);
263 		}, Eq(true)),
264 		_)
265 	).WillOnce(Invoke([&](auto in __unused, auto &out __unused) {
266 		sem_post(&sem);
267 		/* Filesystem is slow to respond */
268 	}));
269 
270 	fd = open(FULLPATH, O_RDONLY);
271 	ASSERT_LE(0, fd) << strerror(errno);
272 
273 	/*
274 	 * Submit two AIO read requests, but respond to neither.  Ensure that
275 	 * we received both.
276 	 */
277 	iocb0.aio_nbytes = bufsize;
278 	iocb0.aio_fildes = fd;
279 	iocb0.aio_buf = buf0;
280 	iocb0.aio_offset = off0;
281 	iocb0.aio_sigevent.sigev_notify = SIGEV_NONE;
282 	ASSERT_EQ(0, aio_read(&iocb0)) << strerror(errno);
283 
284 	iocb1.aio_nbytes = bufsize;
285 	iocb1.aio_fildes = fd;
286 	iocb1.aio_buf = buf1;
287 	iocb1.aio_offset = off1;
288 	iocb1.aio_sigevent.sigev_notify = SIGEV_NONE;
289 	ASSERT_EQ(0, aio_read(&iocb1)) << strerror(errno);
290 
291 	/* Wait until both reads have reached the daemon */
292 	ASSERT_EQ(0, sem_wait(&sem)) << strerror(errno);
293 	ASSERT_EQ(0, sem_wait(&sem)) << strerror(errno);
294 
295 	m_mock->kill_daemon();
296 	/* Wait for AIO activity to complete, but ignore errors */
297 	(void)aio_waitcomplete(NULL, NULL);
298 
299 	leak(fd);
300 }
301 
302 /* 0-length reads shouldn't cause any confusion */
303 TEST_F(Read, direct_io_read_nothing)
304 {
305 	const char FULLPATH[] = "mountpoint/some_file.txt";
306 	const char RELPATH[] = "some_file.txt";
307 	uint64_t ino = 42;
308 	int fd;
309 	uint64_t offset = 100;
310 	char buf[80];
311 
312 	expect_lookup(RELPATH, ino, offset + 1000);
313 	expect_open(ino, FOPEN_DIRECT_IO, 1);
314 
315 	fd = open(FULLPATH, O_RDONLY);
316 	ASSERT_LE(0, fd) << strerror(errno);
317 
318 	ASSERT_EQ(0, pread(fd, buf, 0, offset)) << strerror(errno);
319 	leak(fd);
320 }
321 
322 /*
323  * With direct_io, reads should not fill the cache.  They should go straight to
324  * the daemon
325  */
326 TEST_F(Read, direct_io_pread)
327 {
328 	const char FULLPATH[] = "mountpoint/some_file.txt";
329 	const char RELPATH[] = "some_file.txt";
330 	const char *CONTENTS = "abcdefgh";
331 	uint64_t ino = 42;
332 	int fd;
333 	uint64_t offset = 100;
334 	ssize_t bufsize = strlen(CONTENTS);
335 	char buf[bufsize];
336 
337 	expect_lookup(RELPATH, ino, offset + bufsize);
338 	expect_open(ino, FOPEN_DIRECT_IO, 1);
339 	expect_read(ino, offset, bufsize, bufsize, CONTENTS);
340 
341 	fd = open(FULLPATH, O_RDONLY);
342 	ASSERT_LE(0, fd) << strerror(errno);
343 
344 	ASSERT_EQ(bufsize, pread(fd, buf, bufsize, offset)) << strerror(errno);
345 	ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize));
346 
347 	// With FOPEN_DIRECT_IO, the cache should be bypassed.  The server will
348 	// get a 2nd read request.
349 	expect_read(ino, offset, bufsize, bufsize, CONTENTS);
350 	ASSERT_EQ(bufsize, pread(fd, buf, bufsize, offset)) << strerror(errno);
351 	ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize));
352 	leak(fd);
353 }
354 
355 /*
356  * With direct_io, filesystems are allowed to return less data than is
357  * requested.  fuse(4) should return a short read to userland.
358  */
359 TEST_F(Read, direct_io_short_read)
360 {
361 	const char FULLPATH[] = "mountpoint/some_file.txt";
362 	const char RELPATH[] = "some_file.txt";
363 	const char *CONTENTS = "abcdefghijklmnop";
364 	uint64_t ino = 42;
365 	int fd;
366 	uint64_t offset = 100;
367 	ssize_t bufsize = strlen(CONTENTS);
368 	ssize_t halfbufsize = bufsize / 2;
369 	char buf[bufsize];
370 
371 	expect_lookup(RELPATH, ino, offset + bufsize);
372 	expect_open(ino, FOPEN_DIRECT_IO, 1);
373 	expect_read(ino, offset, bufsize, halfbufsize, CONTENTS);
374 
375 	fd = open(FULLPATH, O_RDONLY);
376 	ASSERT_LE(0, fd) << strerror(errno);
377 
378 	ASSERT_EQ(halfbufsize, pread(fd, buf, bufsize, offset))
379 		<< strerror(errno);
380 	ASSERT_EQ(0, memcmp(buf, CONTENTS, halfbufsize));
381 	leak(fd);
382 }
383 
384 TEST_F(Read, eio)
385 {
386 	const char FULLPATH[] = "mountpoint/some_file.txt";
387 	const char RELPATH[] = "some_file.txt";
388 	const char *CONTENTS = "abcdefgh";
389 	uint64_t ino = 42;
390 	int fd;
391 	ssize_t bufsize = strlen(CONTENTS);
392 	char buf[bufsize];
393 
394 	expect_lookup(RELPATH, ino, bufsize);
395 	expect_open(ino, 0, 1);
396 	EXPECT_CALL(*m_mock, process(
397 		ResultOf([=](auto in) {
398 			return (in.header.opcode == FUSE_READ);
399 		}, Eq(true)),
400 		_)
401 	).WillOnce(Invoke(ReturnErrno(EIO)));
402 
403 	fd = open(FULLPATH, O_RDONLY);
404 	ASSERT_LE(0, fd) << strerror(errno);
405 
406 	ASSERT_EQ(-1, read(fd, buf, bufsize)) << strerror(errno);
407 	ASSERT_EQ(EIO, errno);
408 	leak(fd);
409 }
410 
411 /*
412  * If the server returns a short read when direct io is not in use, that
413  * indicates EOF, because of a server-side truncation.  We should invalidate
414  * all cached attributes.  We may update the file size,
415  */
416 TEST_F(Read, eof)
417 {
418 	const char FULLPATH[] = "mountpoint/some_file.txt";
419 	const char RELPATH[] = "some_file.txt";
420 	const char *CONTENTS = "abcdefghijklmnop";
421 	uint64_t ino = 42;
422 	int fd;
423 	uint64_t offset = 100;
424 	ssize_t bufsize = strlen(CONTENTS);
425 	ssize_t partbufsize = 3 * bufsize / 4;
426 	ssize_t r;
427 	char buf[bufsize];
428 	struct stat sb;
429 
430 	expect_lookup(RELPATH, ino, offset + bufsize);
431 	expect_open(ino, 0, 1);
432 	expect_read(ino, 0, offset + bufsize, offset + partbufsize, CONTENTS);
433 	expect_getattr(ino, offset + partbufsize);
434 
435 	fd = open(FULLPATH, O_RDONLY);
436 	ASSERT_LE(0, fd) << strerror(errno);
437 
438 	r = pread(fd, buf, bufsize, offset);
439 	ASSERT_LE(0, r) << strerror(errno);
440 	EXPECT_EQ(partbufsize, r) << strerror(errno);
441 	ASSERT_EQ(0, fstat(fd, &sb));
442 	EXPECT_EQ((off_t)(offset + partbufsize), sb.st_size);
443 	leak(fd);
444 }
445 
446 /* Like Read.eof, but causes an entire buffer to be invalidated */
447 TEST_F(Read, eof_of_whole_buffer)
448 {
449 	const char FULLPATH[] = "mountpoint/some_file.txt";
450 	const char RELPATH[] = "some_file.txt";
451 	const char *CONTENTS = "abcdefghijklmnop";
452 	uint64_t ino = 42;
453 	int fd;
454 	ssize_t bufsize = strlen(CONTENTS);
455 	off_t old_filesize = m_maxbcachebuf * 2 + bufsize;
456 	char buf[bufsize];
457 	struct stat sb;
458 
459 	expect_lookup(RELPATH, ino, old_filesize);
460 	expect_open(ino, 0, 1);
461 	expect_read(ino, 2 * m_maxbcachebuf, bufsize, bufsize, CONTENTS);
462 	expect_read(ino, m_maxbcachebuf, m_maxbcachebuf, 0, CONTENTS);
463 	expect_getattr(ino, m_maxbcachebuf);
464 
465 	fd = open(FULLPATH, O_RDONLY);
466 	ASSERT_LE(0, fd) << strerror(errno);
467 
468 	/* Cache the third block */
469 	ASSERT_EQ(bufsize, pread(fd, buf, bufsize, m_maxbcachebuf * 2))
470 		<< strerror(errno);
471 	/* Try to read the 2nd block, but it's past EOF */
472 	ASSERT_EQ(0, pread(fd, buf, bufsize, m_maxbcachebuf))
473 		<< strerror(errno);
474 	ASSERT_EQ(0, fstat(fd, &sb));
475 	EXPECT_EQ((off_t)(m_maxbcachebuf), sb.st_size);
476 	leak(fd);
477 }
478 
479 /*
480  * With the keep_cache option, the kernel may keep its read cache across
481  * multiple open(2)s.
482  */
483 TEST_F(Read, keep_cache)
484 {
485 	const char FULLPATH[] = "mountpoint/some_file.txt";
486 	const char RELPATH[] = "some_file.txt";
487 	const char *CONTENTS = "abcdefgh";
488 	uint64_t ino = 42;
489 	int fd0, fd1;
490 	ssize_t bufsize = strlen(CONTENTS);
491 	char buf[bufsize];
492 
493 	FuseTest::expect_lookup(RELPATH, ino, S_IFREG | 0644, bufsize, 2);
494 	expect_open(ino, FOPEN_KEEP_CACHE, 2);
495 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
496 
497 	fd0 = open(FULLPATH, O_RDONLY);
498 	ASSERT_LE(0, fd0) << strerror(errno);
499 	ASSERT_EQ(bufsize, read(fd0, buf, bufsize)) << strerror(errno);
500 
501 	fd1 = open(FULLPATH, O_RDWR);
502 	ASSERT_LE(0, fd1) << strerror(errno);
503 
504 	/*
505 	 * This read should be serviced by cache, even though it's on the other
506 	 * file descriptor
507 	 */
508 	ASSERT_EQ(bufsize, read(fd1, buf, bufsize)) << strerror(errno);
509 
510 	leak(fd0);
511 	leak(fd1);
512 }
513 
514 /*
515  * Without the keep_cache option, the kernel should drop its read caches on
516  * every open
517  */
518 TEST_F(Read, keep_cache_disabled)
519 {
520 	const char FULLPATH[] = "mountpoint/some_file.txt";
521 	const char RELPATH[] = "some_file.txt";
522 	const char *CONTENTS = "abcdefgh";
523 	uint64_t ino = 42;
524 	int fd0, fd1;
525 	ssize_t bufsize = strlen(CONTENTS);
526 	char buf[bufsize];
527 
528 	FuseTest::expect_lookup(RELPATH, ino, S_IFREG | 0644, bufsize, 2);
529 	expect_open(ino, 0, 2);
530 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
531 
532 	fd0 = open(FULLPATH, O_RDONLY);
533 	ASSERT_LE(0, fd0) << strerror(errno);
534 	ASSERT_EQ(bufsize, read(fd0, buf, bufsize)) << strerror(errno);
535 
536 	fd1 = open(FULLPATH, O_RDWR);
537 	ASSERT_LE(0, fd1) << strerror(errno);
538 
539 	/*
540 	 * This read should not be serviced by cache, even though it's on the
541 	 * original file descriptor
542 	 */
543 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
544 	ASSERT_EQ(0, lseek(fd0, 0, SEEK_SET)) << strerror(errno);
545 	ASSERT_EQ(bufsize, read(fd0, buf, bufsize)) << strerror(errno);
546 
547 	leak(fd0);
548 	leak(fd1);
549 }
550 
551 TEST_F(Read, mmap)
552 {
553 	const char FULLPATH[] = "mountpoint/some_file.txt";
554 	const char RELPATH[] = "some_file.txt";
555 	const char *CONTENTS = "abcdefgh";
556 	uint64_t ino = 42;
557 	int fd;
558 	ssize_t len;
559 	size_t bufsize = strlen(CONTENTS);
560 	void *p;
561 
562 	len = getpagesize();
563 
564 	expect_lookup(RELPATH, ino, bufsize);
565 	expect_open(ino, 0, 1);
566 	/* mmap may legitimately try to read more data than is available */
567 	EXPECT_CALL(*m_mock, process(
568 		ResultOf([=](auto in) {
569 			return (in.header.opcode == FUSE_READ &&
570 				in.header.nodeid == ino &&
571 				in.body.read.fh == Read::FH &&
572 				in.body.read.offset == 0 &&
573 				in.body.read.size >= bufsize);
574 		}, Eq(true)),
575 		_)
576 	).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
577 		out.header.len = sizeof(struct fuse_out_header) + bufsize;
578 		memmove(out.body.bytes, CONTENTS, bufsize);
579 	})));
580 
581 	fd = open(FULLPATH, O_RDONLY);
582 	ASSERT_LE(0, fd) << strerror(errno);
583 
584 	p = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
585 	ASSERT_NE(MAP_FAILED, p) << strerror(errno);
586 
587 	ASSERT_EQ(0, memcmp(p, CONTENTS, bufsize));
588 
589 	ASSERT_EQ(0, munmap(p, len)) << strerror(errno);
590 	leak(fd);
591 }
592 
593 /*
594  * A read via mmap comes up short, indicating that the file was truncated
595  * server-side.
596  */
597 TEST_F(Read, mmap_eof)
598 {
599 	const char FULLPATH[] = "mountpoint/some_file.txt";
600 	const char RELPATH[] = "some_file.txt";
601 	const char *CONTENTS = "abcdefgh";
602 	uint64_t ino = 42;
603 	int fd;
604 	ssize_t len;
605 	size_t bufsize = strlen(CONTENTS);
606 	struct stat sb;
607 	void *p;
608 
609 	len = getpagesize();
610 
611 	expect_lookup(RELPATH, ino, 100000);
612 	expect_open(ino, 0, 1);
613 	/* mmap may legitimately try to read more data than is available */
614 	EXPECT_CALL(*m_mock, process(
615 		ResultOf([=](auto in) {
616 			return (in.header.opcode == FUSE_READ &&
617 				in.header.nodeid == ino &&
618 				in.body.read.fh == Read::FH &&
619 				in.body.read.offset == 0 &&
620 				in.body.read.size >= bufsize);
621 		}, Eq(true)),
622 		_)
623 	).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
624 		out.header.len = sizeof(struct fuse_out_header) + bufsize;
625 		memmove(out.body.bytes, CONTENTS, bufsize);
626 	})));
627 	expect_getattr(ino, bufsize);
628 
629 	fd = open(FULLPATH, O_RDONLY);
630 	ASSERT_LE(0, fd) << strerror(errno);
631 
632 	p = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
633 	ASSERT_NE(MAP_FAILED, p) << strerror(errno);
634 
635 	/* The file size should be automatically truncated */
636 	ASSERT_EQ(0, memcmp(p, CONTENTS, bufsize));
637 	ASSERT_EQ(0, fstat(fd, &sb)) << strerror(errno);
638 	EXPECT_EQ((off_t)bufsize, sb.st_size);
639 
640 	ASSERT_EQ(0, munmap(p, len)) << strerror(errno);
641 	leak(fd);
642 }
643 
644 /*
645  * Just as when FOPEN_DIRECT_IO is used, reads with O_DIRECT should bypass
646  * cache and to straight to the daemon
647  */
648 TEST_F(Read, o_direct)
649 {
650 	const char FULLPATH[] = "mountpoint/some_file.txt";
651 	const char RELPATH[] = "some_file.txt";
652 	const char *CONTENTS = "abcdefgh";
653 	uint64_t ino = 42;
654 	int fd;
655 	ssize_t bufsize = strlen(CONTENTS);
656 	char buf[bufsize];
657 
658 	expect_lookup(RELPATH, ino, bufsize);
659 	expect_open(ino, 0, 1);
660 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
661 
662 	fd = open(FULLPATH, O_RDONLY);
663 	ASSERT_LE(0, fd) << strerror(errno);
664 
665 	// Fill the cache
666 	ASSERT_EQ(bufsize, read(fd, buf, bufsize)) << strerror(errno);
667 	ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize));
668 
669 	// Reads with o_direct should bypass the cache
670 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
671 	ASSERT_EQ(0, fcntl(fd, F_SETFL, O_DIRECT)) << strerror(errno);
672 	ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)) << strerror(errno);
673 	ASSERT_EQ(bufsize, read(fd, buf, bufsize)) << strerror(errno);
674 	ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize));
675 
676 	leak(fd);
677 }
678 
679 TEST_F(Read, pread)
680 {
681 	const char FULLPATH[] = "mountpoint/some_file.txt";
682 	const char RELPATH[] = "some_file.txt";
683 	const char *CONTENTS = "abcdefgh";
684 	uint64_t ino = 42;
685 	int fd;
686 	/*
687 	 * Set offset to a maxbcachebuf boundary so we'll be sure what offset
688 	 * to read from.  Without this, the read might start at a lower offset.
689 	 */
690 	uint64_t offset = m_maxbcachebuf;
691 	ssize_t bufsize = strlen(CONTENTS);
692 	char buf[bufsize];
693 
694 	expect_lookup(RELPATH, ino, offset + bufsize);
695 	expect_open(ino, 0, 1);
696 	expect_read(ino, offset, bufsize, bufsize, CONTENTS);
697 
698 	fd = open(FULLPATH, O_RDONLY);
699 	ASSERT_LE(0, fd) << strerror(errno);
700 
701 	ASSERT_EQ(bufsize, pread(fd, buf, bufsize, offset)) << strerror(errno);
702 	ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize));
703 	leak(fd);
704 }
705 
706 TEST_F(Read, read)
707 {
708 	const char FULLPATH[] = "mountpoint/some_file.txt";
709 	const char RELPATH[] = "some_file.txt";
710 	const char *CONTENTS = "abcdefgh";
711 	uint64_t ino = 42;
712 	int fd;
713 	ssize_t bufsize = strlen(CONTENTS);
714 	char buf[bufsize];
715 
716 	expect_lookup(RELPATH, ino, bufsize);
717 	expect_open(ino, 0, 1);
718 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
719 
720 	fd = open(FULLPATH, O_RDONLY);
721 	ASSERT_LE(0, fd) << strerror(errno);
722 
723 	ASSERT_EQ(bufsize, read(fd, buf, bufsize)) << strerror(errno);
724 	ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize));
725 
726 	leak(fd);
727 }
728 
729 TEST_F(Read_7_8, read)
730 {
731 	const char FULLPATH[] = "mountpoint/some_file.txt";
732 	const char RELPATH[] = "some_file.txt";
733 	const char *CONTENTS = "abcdefgh";
734 	uint64_t ino = 42;
735 	int fd;
736 	ssize_t bufsize = strlen(CONTENTS);
737 	char buf[bufsize];
738 
739 	expect_lookup(RELPATH, ino, bufsize);
740 	expect_open(ino, 0, 1);
741 	expect_read(ino, 0, bufsize, bufsize, CONTENTS);
742 
743 	fd = open(FULLPATH, O_RDONLY);
744 	ASSERT_LE(0, fd) << strerror(errno);
745 
746 	ASSERT_EQ(bufsize, read(fd, buf, bufsize)) << strerror(errno);
747 	ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize));
748 
749 	leak(fd);
750 }
751 
752 /*
753  * If cacheing is enabled, the kernel should try to read an entire cache block
754  * at a time.
755  */
756 TEST_F(Read, cache_block)
757 {
758 	const char FULLPATH[] = "mountpoint/some_file.txt";
759 	const char RELPATH[] = "some_file.txt";
760 	const char *CONTENTS0 = "abcdefghijklmnop";
761 	uint64_t ino = 42;
762 	int fd;
763 	ssize_t bufsize = 8;
764 	ssize_t filesize = m_maxbcachebuf * 2;
765 	char *contents;
766 	char buf[bufsize];
767 	const char *contents1 = CONTENTS0 + bufsize;
768 
769 	contents = (char*)calloc(1, filesize);
770 	ASSERT_NE(NULL, contents);
771 	memmove(contents, CONTENTS0, strlen(CONTENTS0));
772 
773 	expect_lookup(RELPATH, ino, filesize);
774 	expect_open(ino, 0, 1);
775 	expect_read(ino, 0, m_maxbcachebuf, m_maxbcachebuf,
776 		contents);
777 
778 	fd = open(FULLPATH, O_RDONLY);
779 	ASSERT_LE(0, fd) << strerror(errno);
780 
781 	ASSERT_EQ(bufsize, read(fd, buf, bufsize)) << strerror(errno);
782 	ASSERT_EQ(0, memcmp(buf, CONTENTS0, bufsize));
783 
784 	/* A subsequent read should be serviced by cache */
785 	ASSERT_EQ(bufsize, read(fd, buf, bufsize)) << strerror(errno);
786 	ASSERT_EQ(0, memcmp(buf, contents1, bufsize));
787 	leak(fd);
788 }
789 
790 /* Reading with sendfile should work (though it obviously won't be 0-copy) */
791 TEST_F(Read, sendfile)
792 {
793 	const char FULLPATH[] = "mountpoint/some_file.txt";
794 	const char RELPATH[] = "some_file.txt";
795 	const char *CONTENTS = "abcdefgh";
796 	uint64_t ino = 42;
797 	int fd;
798 	size_t bufsize = strlen(CONTENTS);
799 	char buf[bufsize];
800 	int sp[2];
801 	off_t sbytes;
802 
803 	expect_lookup(RELPATH, ino, bufsize);
804 	expect_open(ino, 0, 1);
805 	/* Like mmap, sendfile may request more data than is available */
806 	EXPECT_CALL(*m_mock, process(
807 		ResultOf([=](auto in) {
808 			return (in.header.opcode == FUSE_READ &&
809 				in.header.nodeid == ino &&
810 				in.body.read.fh == Read::FH &&
811 				in.body.read.offset == 0 &&
812 				in.body.read.size >= bufsize);
813 		}, Eq(true)),
814 		_)
815 	).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
816 		out.header.len = sizeof(struct fuse_out_header) + bufsize;
817 		memmove(out.body.bytes, CONTENTS, bufsize);
818 	})));
819 
820 	ASSERT_EQ(0, socketpair(PF_LOCAL, SOCK_STREAM, 0, sp))
821 		<< strerror(errno);
822 	fd = open(FULLPATH, O_RDONLY);
823 	ASSERT_LE(0, fd) << strerror(errno);
824 
825 	ASSERT_EQ(0, sendfile(fd, sp[1], 0, bufsize, NULL, &sbytes, 0))
826 		<< strerror(errno);
827 	ASSERT_EQ(static_cast<ssize_t>(bufsize), read(sp[0], buf, bufsize))
828 		<< strerror(errno);
829 	ASSERT_EQ(0, memcmp(buf, CONTENTS, bufsize));
830 
831 	close(sp[1]);
832 	close(sp[0]);
833 	leak(fd);
834 }
835 
836 /* sendfile should fail gracefully if fuse declines the read */
837 /* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236466 */
838 TEST_F(Read, DISABLED_sendfile_eio)
839 {
840 	const char FULLPATH[] = "mountpoint/some_file.txt";
841 	const char RELPATH[] = "some_file.txt";
842 	const char *CONTENTS = "abcdefgh";
843 	uint64_t ino = 42;
844 	int fd;
845 	ssize_t bufsize = strlen(CONTENTS);
846 	int sp[2];
847 	off_t sbytes;
848 
849 	expect_lookup(RELPATH, ino, bufsize);
850 	expect_open(ino, 0, 1);
851 	EXPECT_CALL(*m_mock, process(
852 		ResultOf([=](auto in) {
853 			return (in.header.opcode == FUSE_READ);
854 		}, Eq(true)),
855 		_)
856 	).WillOnce(Invoke(ReturnErrno(EIO)));
857 
858 	ASSERT_EQ(0, socketpair(PF_LOCAL, SOCK_STREAM, 0, sp))
859 		<< strerror(errno);
860 	fd = open(FULLPATH, O_RDONLY);
861 	ASSERT_LE(0, fd) << strerror(errno);
862 
863 	ASSERT_NE(0, sendfile(fd, sp[1], 0, bufsize, NULL, &sbytes, 0));
864 
865 	close(sp[1]);
866 	close(sp[0]);
867 	leak(fd);
868 }
869 
870 /*
871  * Sequential reads should use readahead.  And if allowed, large reads should
872  * be clustered.
873  */
874 TEST_P(ReadAhead, readahead) {
875 	const char FULLPATH[] = "mountpoint/some_file.txt";
876 	const char RELPATH[] = "some_file.txt";
877 	uint64_t ino = 42;
878 	int fd, maxcontig, clustersize;
879 	ssize_t bufsize = 4 * m_maxbcachebuf;
880 	ssize_t filesize = bufsize;
881 	uint64_t len;
882 	char *rbuf, *contents;
883 	off_t offs;
884 
885 	contents = (char*)malloc(filesize);
886 	ASSERT_NE(NULL, contents);
887 	memset(contents, 'X', filesize);
888 	rbuf = (char*)calloc(1, bufsize);
889 
890 	expect_lookup(RELPATH, ino, filesize);
891 	expect_open(ino, 0, 1);
892 	maxcontig = m_noclusterr ? m_maxbcachebuf :
893 		m_maxbcachebuf + m_maxreadahead;
894 	clustersize = MIN(maxcontig, m_maxphys);
895 	for (offs = 0; offs < bufsize; offs += clustersize) {
896 		len = std::min((size_t)clustersize, (size_t)(filesize - offs));
897 		expect_read(ino, offs, len, len, contents + offs);
898 	}
899 
900 	fd = open(FULLPATH, O_RDONLY);
901 	ASSERT_LE(0, fd) << strerror(errno);
902 
903 	/* Set the internal readahead counter to a "large" value */
904 	ASSERT_EQ(0, fcntl(fd, F_READAHEAD, 1'000'000'000)) << strerror(errno);
905 
906 	ASSERT_EQ(bufsize, read(fd, rbuf, bufsize)) << strerror(errno);
907 	ASSERT_EQ(0, memcmp(rbuf, contents, bufsize));
908 
909 	leak(fd);
910 }
911 
912 INSTANTIATE_TEST_CASE_P(RA, ReadAhead,
913 	Values(tuple<bool, int>(false, 0),
914 	       tuple<bool, int>(false, 1),
915 	       tuple<bool, int>(false, 2),
916 	       tuple<bool, int>(false, 3),
917 	       tuple<bool, int>(true, 0),
918 	       tuple<bool, int>(true, 1),
919 	       tuple<bool, int>(true, 2)));
920