2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2021 Alan Somers
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/param.h>
32 #include <sys/mount.h>
33 #include <sys/resource.h>
40 #include "mntopts.h" // for build_iovec
46 using namespace testing;
48 /* Is buf all zero? */
50 is_zero(const char *buf, uint64_t size)
52 return buf[0] == 0 && !memcmp(buf, buf + 1, size - 1);
55 class Fallocate: public FuseTest {
58 * expect VOP_DEALLOCATE to be implemented by vop_stddeallocate.
60 void expect_vop_stddeallocate(uint64_t ino, uint64_t off, uint64_t length)
62 /* XXX read offset and size may depend on cache mode */
63 EXPECT_CALL(*m_mock, process(
64 ResultOf([=](auto in) {
65 return (in.header.opcode == FUSE_READ &&
66 in.header.nodeid == ino &&
67 in.body.read.offset <= off &&
68 in.body.read.offset + in.body.read.size >=
72 ).WillOnce(Invoke(ReturnImmediate([=](auto in, auto& out) {
73 assert(in.body.read.size <= sizeof(out.body.bytes));
74 out.header.len = sizeof(struct fuse_out_header) +
76 memset(out.body.bytes, 'X', in.body.read.size);
77 }))).RetiresOnSaturation();
78 EXPECT_CALL(*m_mock, process(
79 ResultOf([=](auto in) {
80 const char *buf = (const char*)in.body.bytes +
81 sizeof(struct fuse_write_in);
83 assert(length <= sizeof(in.body.bytes) -
84 sizeof(struct fuse_write_in));
85 return (in.header.opcode == FUSE_WRITE &&
86 in.header.nodeid == ino &&
87 in.body.write.offset == off &&
88 in.body.write.size == length &&
89 is_zero(buf, length));
92 ).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
93 SET_OUT_HEADER_LEN(out, write);
94 out.body.write.size = length;
99 class Fspacectl: public Fallocate {};
101 class Fspacectl_7_18: public Fspacectl {
103 virtual void SetUp() {
104 m_kernel_minor_version = 18;
109 class FspacectlCache: public Fspacectl, public WithParamInterface<cache_mode> {
113 FspacectlCache(): m_direct_io(false) {};
115 virtual void SetUp() {
116 int cache_mode = GetParam();
117 switch (cache_mode) {
125 m_init_flags |= FUSE_WRITEBACK_CACHE;
130 FAIL() << "Unknown cache mode";
139 class PosixFallocate: public Fallocate {
141 static sig_atomic_t s_sigxfsz;
151 bzero(&sa, sizeof(sa));
152 sa.sa_handler = SIG_DFL;
153 sigaction(SIGXFSZ, &sa, NULL);
155 Fallocate::TearDown();
160 sig_atomic_t PosixFallocate::s_sigxfsz = 0;
162 void sigxfsz_handler(int __unused sig) {
163 PosixFallocate::s_sigxfsz = 1;
166 class PosixFallocate_7_18: public PosixFallocate {
168 virtual void SetUp() {
169 m_kernel_minor_version = 18;
170 PosixFallocate::SetUp();
176 * If the server returns ENOSYS, it indicates that the server does not support
177 * FUSE_FALLOCATE. This and future calls should fall back to vop_stddeallocate.
179 TEST_F(Fspacectl, enosys)
181 const char FULLPATH[] = "mountpoint/some_file.txt";
182 const char RELPATH[] = "some_file.txt";
183 off_t fsize = 1 << 20;
186 struct spacectl_range rqsr = { .r_offset = off0, .r_len = len0 };
188 uint64_t off1 = fsize;
189 uint64_t len1 = 1000;
190 off_t off2 = fsize / 2;
194 expect_lookup(RELPATH, ino, S_IFREG | 0644, fsize, 1);
195 expect_open(ino, 0, 1);
196 expect_fallocate(ino, off0, len0,
197 FUSE_FALLOC_FL_KEEP_SIZE | FUSE_FALLOC_FL_PUNCH_HOLE, ENOSYS);
198 expect_vop_stddeallocate(ino, off0, len0);
199 expect_vop_stddeallocate(ino, off2, len2);
201 fd = open(FULLPATH, O_RDWR);
202 ASSERT_LE(0, fd) << strerror(errno);
203 EXPECT_EQ(0, fspacectl(fd, SPACECTL_DEALLOC, &rqsr, 0, NULL));
205 /* Subsequent calls shouldn't query the daemon either */
206 rqsr.r_offset = off2;
208 EXPECT_EQ(0, fspacectl(fd, SPACECTL_DEALLOC, &rqsr, 0, NULL));
210 /* Neither should posix_fallocate query the daemon */
211 EXPECT_EQ(EINVAL, posix_fallocate(fd, off1, len1));
217 * EOPNOTSUPP means "the file system does not support fallocate with the
218 * supplied mode on this particular file". So we should fallback, but not
219 * assume anything about whether the operation will fail on a different file or
220 * with a different mode.
222 TEST_F(Fspacectl, eopnotsupp)
224 const char FULLPATH[] = "mountpoint/some_file.txt";
225 const char RELPATH[] = "some_file.txt";
226 struct spacectl_range rqsr;
228 uint64_t fsize = 1 << 20;
231 uint64_t off1 = fsize / 2;
234 expect_lookup(RELPATH, ino, S_IFREG | 0644, fsize, 1);
235 expect_open(ino, 0, 1);
236 expect_fallocate(ino, off0, len,
237 FUSE_FALLOC_FL_KEEP_SIZE | FUSE_FALLOC_FL_PUNCH_HOLE,
239 expect_vop_stddeallocate(ino, off0, len);
240 expect_fallocate(ino, off1, len,
241 FUSE_FALLOC_FL_KEEP_SIZE | FUSE_FALLOC_FL_PUNCH_HOLE,
243 expect_vop_stddeallocate(ino, off1, len);
244 expect_fallocate(ino, fsize, len, 0, 0);
246 fd = open(FULLPATH, O_RDWR);
247 ASSERT_LE(0, fd) << strerror(errno);
250 * Though the FUSE daemon will reject the call, the kernel should fall
251 * back to a read-modify-write approach.
253 rqsr.r_offset = off0;
255 EXPECT_EQ(0, fspacectl(fd, SPACECTL_DEALLOC, &rqsr, 0, NULL));
257 /* Subsequent calls should still query the daemon */
258 rqsr.r_offset = off1;
260 EXPECT_EQ(0, fspacectl(fd, SPACECTL_DEALLOC, &rqsr, 0, NULL));
262 /* But subsequent posix_fallocate calls _should_ query the daemon */
263 EXPECT_EQ(0, posix_fallocate(fd, fsize, len));
268 TEST_F(Fspacectl, erofs)
270 const char FULLPATH[] = "mountpoint/some_file.txt";
271 const char RELPATH[] = "some_file.txt";
272 struct statfs statbuf;
273 uint64_t fsize = 2000;
274 struct spacectl_range rqsr = { .r_offset = 0, .r_len = 1 };
275 struct iovec *iov = NULL;
281 expect_lookup(RELPATH, ino, S_IFREG | 0644, fsize, 1);
282 expect_open(ino, 0, 1);
283 EXPECT_CALL(*m_mock, process(
284 ResultOf([](auto in) {
285 return (in.header.opcode == FUSE_STATFS);
288 ).WillRepeatedly(Invoke(ReturnImmediate([=](auto in __unused, auto& out)
291 * All of the fields except f_flags are don't care, and f_flags
294 SET_OUT_HEADER_LEN(out, statfs);
297 fd = open(FULLPATH, O_RDWR);
298 ASSERT_LE(0, fd) << strerror(errno);
300 /* Remount read-only */
301 ASSERT_EQ(0, statfs("mountpoint", &statbuf)) << strerror(errno);
302 newflags = statbuf.f_flags | MNT_UPDATE | MNT_RDONLY;
303 build_iovec(&iov, &iovlen, "fstype", (void*)statbuf.f_fstypename, -1);
304 build_iovec(&iov, &iovlen, "fspath", (void*)statbuf.f_mntonname, -1);
305 build_iovec(&iov, &iovlen, "from", __DECONST(void *, "/dev/fuse"), -1);
306 ASSERT_EQ(0, nmount(iov, iovlen, newflags)) << strerror(errno);
308 EXPECT_EQ(-1, fspacectl(fd, SPACECTL_DEALLOC, &rqsr, 0, NULL));
309 EXPECT_EQ(EROFS, errno);
314 TEST_F(Fspacectl, ok)
316 const char FULLPATH[] = "mountpoint/some_file.txt";
317 const char RELPATH[] = "some_file.txt";
318 struct spacectl_range rqsr, rmsr;
319 struct stat sb0, sb1;
321 uint64_t fsize = 2000;
322 uint64_t offset = 500;
323 uint64_t length = 1000;
326 expect_lookup(RELPATH, ino, S_IFREG | 0644, fsize, 1);
327 expect_open(ino, 0, 1);
328 expect_fallocate(ino, offset, length,
329 FUSE_FALLOC_FL_KEEP_SIZE | FUSE_FALLOC_FL_PUNCH_HOLE, 0);
331 fd = open(FULLPATH, O_RDWR);
332 ASSERT_LE(0, fd) << strerror(errno);
333 ASSERT_EQ(0, fstat(fd, &sb0)) << strerror(errno);
334 rqsr.r_offset = offset;
336 EXPECT_EQ(0, fspacectl(fd, SPACECTL_DEALLOC, &rqsr, 0, &rmsr));
337 EXPECT_EQ(0, rmsr.r_len);
338 EXPECT_EQ((off_t)(offset + length), rmsr.r_offset);
341 * The file's attributes should not have been invalidated, so this fstat
342 * will not requery the daemon.
344 EXPECT_EQ(0, fstat(fd, &sb1));
345 EXPECT_EQ(fsize, (uint64_t)sb1.st_size);
347 /* mtime and ctime should be updated */
348 EXPECT_EQ(sb0.st_atime, sb1.st_atime);
349 EXPECT_NE(sb0.st_mtime, sb1.st_mtime);
350 EXPECT_NE(sb0.st_ctime, sb1.st_ctime);
355 /* The returned rqsr.r_off should be clipped at EoF */
356 TEST_F(Fspacectl, past_eof)
358 const char FULLPATH[] = "mountpoint/some_file.txt";
359 const char RELPATH[] = "some_file.txt";
360 struct spacectl_range rqsr, rmsr;
362 uint64_t fsize = 1000;
363 uint64_t offset = 1500;
364 uint64_t length = 1000;
367 expect_lookup(RELPATH, ino, S_IFREG | 0644, fsize, 1);
368 expect_open(ino, 0, 1);
369 expect_fallocate(ino, offset, length,
370 FUSE_FALLOC_FL_KEEP_SIZE | FUSE_FALLOC_FL_PUNCH_HOLE, 0);
372 fd = open(FULLPATH, O_RDWR);
373 ASSERT_LE(0, fd) << strerror(errno);
374 rqsr.r_offset = offset;
376 EXPECT_EQ(0, fspacectl(fd, SPACECTL_DEALLOC, &rqsr, 0, &rmsr));
377 EXPECT_EQ(0, rmsr.r_len);
378 EXPECT_EQ((off_t)fsize, rmsr.r_offset);
383 /* The returned rqsr.r_off should be clipped at EoF */
384 TEST_F(Fspacectl, spans_eof)
386 const char FULLPATH[] = "mountpoint/some_file.txt";
387 const char RELPATH[] = "some_file.txt";
388 struct spacectl_range rqsr, rmsr;
390 uint64_t fsize = 1000;
391 uint64_t offset = 500;
392 uint64_t length = 1000;
395 expect_lookup(RELPATH, ino, S_IFREG | 0644, fsize, 1);
396 expect_open(ino, 0, 1);
397 expect_fallocate(ino, offset, length,
398 FUSE_FALLOC_FL_KEEP_SIZE | FUSE_FALLOC_FL_PUNCH_HOLE, 0);
400 fd = open(FULLPATH, O_RDWR);
401 ASSERT_LE(0, fd) << strerror(errno);
402 rqsr.r_offset = offset;
404 EXPECT_EQ(0, fspacectl(fd, SPACECTL_DEALLOC, &rqsr, 0, &rmsr));
405 EXPECT_EQ(0, rmsr.r_len);
406 EXPECT_EQ((off_t)fsize, rmsr.r_offset);
412 * With older servers, no FUSE_FALLOCATE should be attempted. The kernel
413 * should fall back to vop_stddeallocate.
415 TEST_F(Fspacectl_7_18, ok)
417 const char FULLPATH[] = "mountpoint/some_file.txt";
418 const char RELPATH[] = "some_file.txt";
419 struct spacectl_range rqsr, rmsr;
422 uint64_t fsize = 2000;
423 uint64_t offset = 500;
424 uint64_t length = 1000;
427 buf = malloc(length);
429 expect_lookup(RELPATH, ino, S_IFREG | 0644, fsize, 1);
430 expect_open(ino, 0, 1);
431 expect_vop_stddeallocate(ino, offset, length);
433 fd = open(FULLPATH, O_RDWR);
434 ASSERT_LE(0, fd) << strerror(errno);
435 rqsr.r_offset = offset;
437 EXPECT_EQ(0, fspacectl(fd, SPACECTL_DEALLOC, &rqsr, 0, &rmsr));
438 EXPECT_EQ(0, rmsr.r_len);
439 EXPECT_EQ((off_t)(offset + length), rmsr.r_offset);
446 * A successful fspacectl should clear the zeroed data from the kernel cache.
448 TEST_P(FspacectlCache, clears_cache)
450 const char FULLPATH[] = "mountpoint/some_file.txt";
451 const char RELPATH[] = "some_file.txt";
452 const char *CONTENTS = "abcdefghijklmnopqrstuvwxyz";
453 struct spacectl_range rqsr, rmsr;
455 ssize_t bufsize = strlen(CONTENTS);
456 uint64_t fsize = bufsize;
457 uint8_t buf[bufsize];
460 uint64_t length = bufsize;
463 bzero(zbuf, bufsize);
465 expect_lookup(RELPATH, ino, S_IFREG | 0644, fsize, 1);
466 expect_open(ino, 0, 1);
467 /* NB: expectations are applied in LIFO order */
468 expect_read(ino, 0, fsize, fsize, zbuf);
469 expect_read(ino, 0, fsize, fsize, CONTENTS);
470 expect_fallocate(ino, offset, length,
471 FUSE_FALLOC_FL_KEEP_SIZE | FUSE_FALLOC_FL_PUNCH_HOLE, 0);
473 fd = open(FULLPATH, O_RDWR);
474 ASSERT_LE(0, fd) << strerror(errno);
476 /* Populate the cache */
477 ASSERT_EQ(fsize, (uint64_t)pread(fd, buf, bufsize, 0))
479 ASSERT_EQ(0, memcmp(buf, CONTENTS, fsize));
482 rqsr.r_offset = offset;
484 EXPECT_EQ(0, fspacectl(fd, SPACECTL_DEALLOC, &rqsr, 0, &rmsr));
485 EXPECT_EQ(0, rmsr.r_len);
486 EXPECT_EQ((off_t)(offset + length), rmsr.r_offset);
488 /* Read again. This should query the daemon */
489 ASSERT_EQ(fsize, (uint64_t)pread(fd, buf, bufsize, 0))
491 ASSERT_EQ(0, memcmp(buf, zbuf, fsize));
496 INSTANTIATE_TEST_CASE_P(FspacectlCache, FspacectlCache,
497 Values(Uncached, Writethrough, Writeback),
501 * If the server returns ENOSYS, it indicates that the server does not support
502 * FUSE_FALLOCATE. This and future calls should return EINVAL.
504 TEST_F(PosixFallocate, enosys)
506 const char FULLPATH[] = "mountpoint/some_file.txt";
507 const char RELPATH[] = "some_file.txt";
510 uint64_t len0 = 1000;
513 uint64_t fsize = 500;
514 struct spacectl_range rqsr = { .r_offset = off1, .r_len = len1 };
517 expect_lookup(RELPATH, ino, S_IFREG | 0644, fsize, 1);
518 expect_open(ino, 0, 1);
519 expect_fallocate(ino, off0, len0, 0, ENOSYS);
520 expect_vop_stddeallocate(ino, off1, len1);
522 fd = open(FULLPATH, O_RDWR);
523 ASSERT_LE(0, fd) << strerror(errno);
524 EXPECT_EQ(EINVAL, posix_fallocate(fd, off0, len0));
526 /* Subsequent calls shouldn't query the daemon*/
527 EXPECT_EQ(EINVAL, posix_fallocate(fd, off0, len0));
529 /* Neither should VOP_DEALLOCATE query the daemon */
530 EXPECT_EQ(0, fspacectl(fd, SPACECTL_DEALLOC, &rqsr, 0, NULL));
536 * EOPNOTSUPP means "the file system does not support fallocate with the
537 * supplied mode on this particular file". So we should fallback, but not
538 * assume anything about whether the operation will fail on a different file or
539 * with a different mode.
541 TEST_F(PosixFallocate, eopnotsupp)
543 const char FULLPATH[] = "mountpoint/some_file.txt";
544 const char RELPATH[] = "some_file.txt";
545 struct spacectl_range rqsr;
547 uint64_t fsize = 2000;
549 uint64_t length = 1000;
552 expect_lookup(RELPATH, ino, S_IFREG | 0644, fsize, 1);
553 expect_open(ino, 0, 1);
554 expect_fallocate(ino, fsize, length, 0, EOPNOTSUPP);
555 expect_fallocate(ino, offset, length, 0, EOPNOTSUPP);
556 expect_fallocate(ino, offset, length,
557 FUSE_FALLOC_FL_KEEP_SIZE | FUSE_FALLOC_FL_PUNCH_HOLE, 0);
559 fd = open(FULLPATH, O_RDWR);
560 ASSERT_LE(0, fd) << strerror(errno);
561 EXPECT_EQ(EINVAL, posix_fallocate(fd, fsize, length));
563 /* Subsequent calls should still query the daemon*/
564 EXPECT_EQ(EINVAL, posix_fallocate(fd, offset, length));
566 /* And subsequent VOP_DEALLOCATE calls should also query the daemon */
568 rqsr.r_offset = offset;
569 EXPECT_EQ(0, fspacectl(fd, SPACECTL_DEALLOC, &rqsr, 0, NULL));
574 /* EIO is not a permanent error, and may be retried */
575 TEST_F(PosixFallocate, eio)
577 const char FULLPATH[] = "mountpoint/some_file.txt";
578 const char RELPATH[] = "some_file.txt";
581 uint64_t length = 1000;
584 expect_lookup(RELPATH, ino, S_IFREG | 0644, 0, 1);
585 expect_open(ino, 0, 1);
586 expect_fallocate(ino, offset, length, 0, EIO);
588 fd = open(FULLPATH, O_RDWR);
589 ASSERT_LE(0, fd) << strerror(errno);
590 EXPECT_EQ(EIO, posix_fallocate(fd, offset, length));
592 expect_fallocate(ino, offset, length, 0, 0);
594 EXPECT_EQ(0, posix_fallocate(fd, offset, length));
599 TEST_F(PosixFallocate, erofs)
601 const char FULLPATH[] = "mountpoint/some_file.txt";
602 const char RELPATH[] = "some_file.txt";
603 struct statfs statbuf;
604 struct iovec *iov = NULL;
608 uint64_t length = 1000;
612 expect_lookup(RELPATH, ino, S_IFREG | 0644, 0, 1);
613 expect_open(ino, 0, 1);
614 EXPECT_CALL(*m_mock, process(
615 ResultOf([](auto in) {
616 return (in.header.opcode == FUSE_STATFS);
619 ).WillRepeatedly(Invoke(ReturnImmediate([=](auto in __unused, auto& out)
622 * All of the fields except f_flags are don't care, and f_flags
625 SET_OUT_HEADER_LEN(out, statfs);
628 fd = open(FULLPATH, O_RDWR);
629 ASSERT_LE(0, fd) << strerror(errno);
631 /* Remount read-only */
632 ASSERT_EQ(0, statfs("mountpoint", &statbuf)) << strerror(errno);
633 newflags = statbuf.f_flags | MNT_UPDATE | MNT_RDONLY;
634 build_iovec(&iov, &iovlen, "fstype", (void*)statbuf.f_fstypename, -1);
635 build_iovec(&iov, &iovlen, "fspath", (void*)statbuf.f_mntonname, -1);
636 build_iovec(&iov, &iovlen, "from", __DECONST(void *, "/dev/fuse"), -1);
637 ASSERT_EQ(0, nmount(iov, iovlen, newflags)) << strerror(errno);
639 EXPECT_EQ(EROFS, posix_fallocate(fd, offset, length));
644 TEST_F(PosixFallocate, ok)
646 const char FULLPATH[] = "mountpoint/some_file.txt";
647 const char RELPATH[] = "some_file.txt";
648 struct stat sb0, sb1;
651 uint64_t length = 1000;
654 EXPECT_LOOKUP(FUSE_ROOT_ID, RELPATH)
655 .WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
656 SET_OUT_HEADER_LEN(out, entry);
657 out.body.entry.attr.mode = S_IFREG | 0644;
658 out.body.entry.nodeid = ino;
659 out.body.entry.entry_valid = UINT64_MAX;
660 out.body.entry.attr_valid = UINT64_MAX;
662 expect_open(ino, 0, 1);
663 expect_fallocate(ino, offset, length, 0, 0);
665 fd = open(FULLPATH, O_RDWR);
666 ASSERT_LE(0, fd) << strerror(errno);
667 ASSERT_EQ(0, fstat(fd, &sb0)) << strerror(errno);
668 EXPECT_EQ(0, posix_fallocate(fd, offset, length));
670 * Despite the originally cached file size of zero, stat should now
671 * return either the new size or requery the daemon.
673 EXPECT_EQ(0, stat(FULLPATH, &sb1));
674 EXPECT_EQ(length, (uint64_t)sb1.st_size);
676 /* mtime and ctime should be updated */
677 EXPECT_EQ(sb0.st_atime, sb1.st_atime);
678 EXPECT_NE(sb0.st_mtime, sb1.st_mtime);
679 EXPECT_NE(sb0.st_ctime, sb1.st_ctime);
684 /* fusefs should respect RLIMIT_FSIZE */
685 TEST_F(PosixFallocate, rlimit_fsize)
687 const char FULLPATH[] = "mountpoint/some_file.txt";
688 const char RELPATH[] = "some_file.txt";
692 uint64_t length = 1'000'000;
695 expect_lookup(RELPATH, ino, S_IFREG | 0644, 0, 1);
696 expect_open(ino, 0, 1);
698 rl.rlim_cur = length / 2;
699 rl.rlim_max = 10 * length;
700 ASSERT_EQ(0, setrlimit(RLIMIT_FSIZE, &rl)) << strerror(errno);
701 ASSERT_NE(SIG_ERR, signal(SIGXFSZ, sigxfsz_handler)) << strerror(errno);
703 fd = open(FULLPATH, O_RDWR);
704 ASSERT_LE(0, fd) << strerror(errno);
705 EXPECT_EQ(EFBIG, posix_fallocate(fd, offset, length));
706 EXPECT_EQ(1, s_sigxfsz);
711 /* With older servers, no FUSE_FALLOCATE should be attempted */
712 TEST_F(PosixFallocate_7_18, einval)
714 const char FULLPATH[] = "mountpoint/some_file.txt";
715 const char RELPATH[] = "some_file.txt";
718 uint64_t length = 1000;
721 expect_lookup(RELPATH, ino, S_IFREG | 0644, 0, 1);
722 expect_open(ino, 0, 1);
724 fd = open(FULLPATH, O_RDWR);
725 ASSERT_LE(0, fd) << strerror(errno);
726 EXPECT_EQ(EINVAL, posix_fallocate(fd, offset, length));