Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/fs/fusefs/forget.cc
39536 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 <sys/types.h>
33
#include <sys/mount.h>
34
35
#include <fcntl.h>
36
#include <semaphore.h>
37
#include <unistd.h>
38
}
39
40
#include "mockfs.hh"
41
#include "utils.hh"
42
43
using namespace testing;
44
45
class Forget: public FuseTest {
46
public:
47
void SetUp() {
48
if (geteuid() != 0)
49
GTEST_SKIP() << "Only root may use " << reclaim_mib;
50
51
FuseTest::SetUp();
52
}
53
54
};
55
56
/*
57
* When a fusefs vnode is reclaimed, it should send a FUSE_FORGET operation.
58
*/
59
TEST_F(Forget, ok)
60
{
61
const char FULLPATH[] = "mountpoint/some_file.txt";
62
const char RELPATH[] = "some_file.txt";
63
uint64_t ino = 42;
64
mode_t mode = S_IFREG | 0755;
65
sem_t sem;
66
67
ASSERT_EQ(0, sem_init(&sem, 0, 0)) << strerror(errno);
68
69
EXPECT_LOOKUP(FUSE_ROOT_ID, RELPATH)
70
.Times(3)
71
.WillRepeatedly(Invoke(
72
ReturnImmediate([=](auto in __unused, auto& out) {
73
SET_OUT_HEADER_LEN(out, entry);
74
out.body.entry.attr.mode = mode;
75
out.body.entry.nodeid = ino;
76
out.body.entry.attr.nlink = 1;
77
out.body.entry.attr_valid = UINT64_MAX;
78
})));
79
expect_forget(ino, 3, &sem);
80
81
/*
82
* access(2) the file to force a lookup. Access it twice to double its
83
* lookup count.
84
*/
85
ASSERT_EQ(0, access(FULLPATH, F_OK)) << strerror(errno);
86
ASSERT_EQ(0, access(FULLPATH, F_OK)) << strerror(errno);
87
88
reclaim_vnode(FULLPATH);
89
90
sem_wait(&sem);
91
sem_destroy(&sem);
92
}
93
94
/*
95
* When a directory is reclaimed, the names of its entries vanish from the
96
* namecache
97
*/
98
TEST_F(Forget, invalidate_names)
99
{
100
const char FULLFPATH[] = "mountpoint/some_dir/some_file.txt";
101
const char FULLDPATH[] = "mountpoint/some_dir";
102
const char DNAME[] = "some_dir";
103
const char FNAME[] = "some_file.txt";
104
uint64_t dir_ino = 42;
105
uint64_t file_ino = 43;
106
107
EXPECT_LOOKUP(FUSE_ROOT_ID, DNAME)
108
.Times(2)
109
.WillRepeatedly(Invoke(
110
ReturnImmediate([=](auto in __unused, auto& out) {
111
SET_OUT_HEADER_LEN(out, entry);
112
out.body.entry.attr.mode = S_IFDIR | 0755;
113
out.body.entry.nodeid = dir_ino;
114
out.body.entry.attr.nlink = 2;
115
out.body.entry.attr_valid = UINT64_MAX;
116
out.body.entry.entry_valid = UINT64_MAX;
117
})));
118
119
/*
120
* Even though we don't reclaim FNAME and its entry is cacheable, we
121
* should get two lookups because the reclaim of DNAME will invalidate
122
* the cached FNAME entry.
123
*/
124
EXPECT_LOOKUP(dir_ino, FNAME)
125
.Times(2)
126
.WillRepeatedly(Invoke(
127
ReturnImmediate([=](auto in __unused, auto& out) {
128
SET_OUT_HEADER_LEN(out, entry);
129
out.body.entry.attr.mode = S_IFREG | 0644;
130
out.body.entry.nodeid = file_ino;
131
out.body.entry.attr.nlink = 1;
132
out.body.entry.attr_valid = UINT64_MAX;
133
out.body.entry.entry_valid = UINT64_MAX;
134
})));
135
expect_forget(dir_ino, 1);
136
137
/* Access the file to cache its name */
138
ASSERT_EQ(0, access(FULLFPATH, F_OK)) << strerror(errno);
139
140
/* Reclaim the directory, invalidating its children from namecache */
141
reclaim_vnode(FULLDPATH);
142
143
/* Access the file again, causing another lookup */
144
ASSERT_EQ(0, access(FULLFPATH, F_OK)) << strerror(errno);
145
}
146
147
/*
148
* Reclaiming the root inode should not send a FUSE_FORGET request, nor should
149
* it interfere with further lookup operations.
150
*/
151
TEST_F(Forget, root)
152
{
153
const char FULLPATH[] = "mountpoint/some_file.txt";
154
const char RELPATH[] = "some_file.txt";
155
uint64_t ino = 42;
156
mode_t mode = S_IFREG | 0755;
157
158
EXPECT_LOOKUP(FUSE_ROOT_ID, RELPATH)
159
.WillRepeatedly(Invoke(
160
ReturnImmediate([=](auto in __unused, auto& out) {
161
SET_OUT_HEADER_LEN(out, entry);
162
out.body.entry.attr.mode = mode;
163
out.body.entry.nodeid = ino;
164
out.body.entry.attr.nlink = 1;
165
out.body.entry.attr_valid = UINT64_MAX;
166
out.body.entry.entry_valid = UINT64_MAX;
167
})));
168
169
/* access(2) the file to force a lookup. */
170
ASSERT_EQ(0, access(FULLPATH, F_OK)) << strerror(errno);
171
172
reclaim_vnode("mountpoint");
173
nap();
174
175
/* Access it again, to make sure it's still possible. */
176
ASSERT_EQ(0, access(FULLPATH, F_OK)) << strerror(errno);
177
}
178
179