Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/fs/fusefs/fsyncdir.cc
39537 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2019 The FreeBSD Foundation
5
*
6
* This software was developed by BFF Storage Systems, LLC under sponsorship
7
* from the FreeBSD Foundation.
8
*
9
* Redistribution and use in source and binary forms, with or without
10
* modification, are permitted provided that the following conditions
11
* are met:
12
* 1. Redistributions of source code must retain the above copyright
13
* notice, this list of conditions and the following disclaimer.
14
* 2. Redistributions in binary form must reproduce the above copyright
15
* notice, this list of conditions and the following disclaimer in the
16
* documentation and/or other materials provided with the distribution.
17
*
18
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
* SUCH DAMAGE.
29
*/
30
31
extern "C" {
32
#include <aio.h>
33
#include <fcntl.h>
34
#include <unistd.h>
35
}
36
37
#include "mockfs.hh"
38
#include "utils.hh"
39
40
using namespace testing;
41
42
/*
43
* TODO: remove FUSE_FSYNC_FDATASYNC definition when upgrading to protocol 7.28.
44
* This bit was actually part of kernel protocol version 5.2, but never
45
* documented until after 7.28
46
*/
47
#ifndef FUSE_FSYNC_FDATASYNC
48
#define FUSE_FSYNC_FDATASYNC 1
49
#endif
50
51
class FsyncDir: public FuseTest {
52
public:
53
void expect_fsyncdir(uint64_t ino, uint32_t flags, int error)
54
{
55
EXPECT_CALL(*m_mock, process(
56
ResultOf([=](auto in) {
57
return (in.header.opcode == FUSE_FSYNCDIR &&
58
in.header.nodeid == ino &&
59
/*
60
* TODO: reenable pid check after fixing
61
* bug 236379
62
*/
63
//(pid_t)in.header.pid == getpid() &&
64
in.body.fsyncdir.fh == FH &&
65
in.body.fsyncdir.fsync_flags == flags);
66
}, Eq(true)),
67
_)
68
).WillOnce(Invoke(ReturnErrno(error)));
69
}
70
71
void expect_lookup(const char *relpath, uint64_t ino)
72
{
73
FuseTest::expect_lookup(relpath, ino, S_IFDIR | 0755, 0, 1);
74
}
75
76
};
77
78
class AioFsyncDir: public FsyncDir {
79
virtual void SetUp() {
80
if (!is_unsafe_aio_enabled())
81
GTEST_SKIP() <<
82
"vfs.aio.enable_unsafe must be set for this test";
83
FuseTest::SetUp();
84
}
85
};
86
87
/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236379 */
88
TEST_F(AioFsyncDir, aio_fsync)
89
{
90
const char FULLPATH[] = "mountpoint/some_file.txt";
91
const char RELPATH[] = "some_file.txt";
92
uint64_t ino = 42;
93
struct aiocb iocb, *piocb;
94
int fd;
95
96
expect_lookup(RELPATH, ino);
97
expect_opendir(ino);
98
expect_fsyncdir(ino, 0, 0);
99
100
fd = open(FULLPATH, O_DIRECTORY);
101
ASSERT_LE(0, fd) << strerror(errno);
102
103
bzero(&iocb, sizeof(iocb));
104
iocb.aio_fildes = fd;
105
106
ASSERT_EQ(0, aio_fsync(O_SYNC, &iocb)) << strerror(errno);
107
ASSERT_EQ(0, aio_waitcomplete(&piocb, NULL)) << strerror(errno);
108
109
leak(fd);
110
}
111
112
TEST_F(FsyncDir, eio)
113
{
114
const char FULLPATH[] = "mountpoint/some_dir";
115
const char RELPATH[] = "some_dir";
116
uint64_t ino = 42;
117
int fd;
118
119
expect_lookup(RELPATH, ino);
120
expect_opendir(ino);
121
expect_fsyncdir(ino, 0, EIO);
122
123
fd = open(FULLPATH, O_DIRECTORY);
124
ASSERT_LE(0, fd) << strerror(errno);
125
ASSERT_NE(0, fsync(fd));
126
ASSERT_EQ(EIO, errno);
127
128
leak(fd);
129
}
130
131
/*
132
* If the filesystem returns ENOSYS, it will be treated as success and
133
* subsequent calls to VOP_FSYNC will succeed automatically without being sent
134
* to the filesystem daemon
135
*/
136
TEST_F(FsyncDir, enosys)
137
{
138
const char FULLPATH[] = "mountpoint/some_dir";
139
const char RELPATH[] = "some_dir";
140
uint64_t ino = 42;
141
int fd;
142
143
expect_lookup(RELPATH, ino);
144
expect_opendir(ino);
145
expect_fsyncdir(ino, 0, ENOSYS);
146
147
fd = open(FULLPATH, O_DIRECTORY);
148
ASSERT_LE(0, fd) << strerror(errno);
149
EXPECT_EQ(0, fsync(fd)) << strerror(errno);
150
151
/* Subsequent calls shouldn't query the daemon*/
152
EXPECT_EQ(0, fsync(fd)) << strerror(errno);
153
154
leak(fd);
155
}
156
157
TEST_F(FsyncDir, fsyncdata)
158
{
159
const char FULLPATH[] = "mountpoint/some_dir";
160
const char RELPATH[] = "some_dir";
161
uint64_t ino = 42;
162
int fd;
163
164
expect_lookup(RELPATH, ino);
165
expect_opendir(ino);
166
expect_fsyncdir(ino, FUSE_FSYNC_FDATASYNC, 0);
167
168
fd = open(FULLPATH, O_DIRECTORY);
169
ASSERT_LE(0, fd) << strerror(errno);
170
ASSERT_EQ(0, fdatasync(fd)) << strerror(errno);
171
172
leak(fd);
173
}
174
175
/*
176
* Unlike regular files, the kernel doesn't know whether a directory is or
177
* isn't dirty, so fuse(4) should always send FUSE_FSYNCDIR on fsync(2)
178
*/
179
TEST_F(FsyncDir, fsync)
180
{
181
const char FULLPATH[] = "mountpoint/some_dir";
182
const char RELPATH[] = "some_dir";
183
uint64_t ino = 42;
184
int fd;
185
186
expect_lookup(RELPATH, ino);
187
expect_opendir(ino);
188
expect_fsyncdir(ino, 0, 0);
189
190
fd = open(FULLPATH, O_DIRECTORY);
191
ASSERT_LE(0, fd) << strerror(errno);
192
ASSERT_EQ(0, fsync(fd)) << strerror(errno);
193
194
leak(fd);
195
}
196
197