]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tests/sys/fs/fusefs/getattr.cc
MFHead @345353
[FreeBSD/FreeBSD.git] / tests / sys / fs / fusefs / getattr.cc
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 #include "mockfs.hh"
32 #include "utils.hh"
33
34 using namespace testing;
35
36 class Getattr : public FuseTest {};
37
38 /*
39  * If getattr returns a non-zero cache timeout, then subsequent VOP_GETATTRs
40  * should use the cached attributes, rather than query the daemon
41  */
42 /* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=235775 */
43 TEST_F(Getattr, DISABLED_attr_cache)
44 {
45         const char FULLPATH[] = "mountpoint/some_file.txt";
46         const char RELPATH[] = "some_file.txt";
47         const uint64_t ino = 42;
48         struct stat sb;
49
50         EXPECT_LOOKUP(1, RELPATH)
51         .WillRepeatedly(Invoke(ReturnImmediate([=](auto i __unused, auto out) {
52                 SET_OUT_HEADER_LEN(out, entry);
53                 out->body.entry.attr.mode = S_IFREG | 0644;
54                 out->body.entry.nodeid = ino;
55         })));
56         EXPECT_CALL(*m_mock, process(
57                 ResultOf([](auto in) {
58                         return (in->header.opcode == FUSE_GETATTR &&
59                                 in->header.nodeid == ino);
60                 }, Eq(true)),
61                 _)
62         ).WillOnce(Invoke(ReturnImmediate([](auto i __unused, auto out) {
63                 SET_OUT_HEADER_LEN(out, attr);
64                 out->body.attr.attr_valid = UINT64_MAX;
65                 out->body.attr.attr.ino = ino;  // Must match nodeid
66                 out->body.attr.attr.mode = S_IFREG | 0644;
67         })));
68         EXPECT_EQ(0, stat(FULLPATH, &sb));
69         /* The second stat(2) should use cached attributes */
70         EXPECT_EQ(0, stat(FULLPATH, &sb));
71 }
72
73 /*
74  * If getattr returns a finite but non-zero cache timeout, then we should
75  * discard the cached attributes and requery the daemon after the timeout
76  * period passes.
77  */
78 /* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=235773 */
79 TEST_F(Getattr, attr_cache_timeout)
80 {
81         const char FULLPATH[] = "mountpoint/some_file.txt";
82         const char RELPATH[] = "some_file.txt";
83         const uint64_t ino = 42;
84         struct stat sb;
85         /* 
86          * The timeout should be longer than the longest plausible time the
87          * daemon would take to complete a write(2) to /dev/fuse, but no longer.
88          */
89         long timeout_ns = 250'000'000;
90
91         expect_lookup(RELPATH, ino, S_IFREG | 0644, 0, 2);
92         EXPECT_CALL(*m_mock, process(
93                 ResultOf([](auto in) {
94                         return (in->header.opcode == FUSE_GETATTR &&
95                                 in->header.nodeid == ino);
96                 }, Eq(true)),
97                 _)
98         ).Times(2)
99         .WillRepeatedly(Invoke(ReturnImmediate([=](auto i __unused, auto out) {
100                 SET_OUT_HEADER_LEN(out, attr);
101                 out->body.attr.attr_valid_nsec = timeout_ns;
102                 out->body.attr.attr_valid = UINT64_MAX;
103                 out->body.attr.attr.ino = ino;  // Must match nodeid
104                 out->body.attr.attr.mode = S_IFREG | 0644;
105         })));
106         EXPECT_EQ(0, stat(FULLPATH, &sb));
107         usleep(2 * timeout_ns / 1000);
108         /* Timeout has expire. stat(2) should requery the daemon */
109         EXPECT_EQ(0, stat(FULLPATH, &sb));
110 }
111
112 TEST_F(Getattr, enoent)
113 {
114         const char FULLPATH[] = "mountpoint/some_file.txt";
115         const char RELPATH[] = "some_file.txt";
116         struct stat sb;
117         const uint64_t ino = 42;
118
119         expect_lookup(RELPATH, ino, S_IFREG | 0644, 0, 1);
120         EXPECT_CALL(*m_mock, process(
121                 ResultOf([](auto in) {
122                         return (in->header.opcode == FUSE_GETATTR &&
123                                 in->header.nodeid == ino);
124                 }, Eq(true)),
125                 _)
126         ).WillOnce(Invoke(ReturnErrno(ENOENT)));
127         EXPECT_NE(0, stat(FULLPATH, &sb));
128         EXPECT_EQ(ENOENT, errno);
129 }
130
131 TEST_F(Getattr, ok)
132 {
133         const char FULLPATH[] = "mountpoint/some_file.txt";
134         const char RELPATH[] = "some_file.txt";
135         const uint64_t ino = 42;
136         struct stat sb;
137
138         expect_lookup(RELPATH, ino, S_IFREG | 0644, 1, 1);
139         EXPECT_CALL(*m_mock, process(
140                 ResultOf([](auto in) {
141                         return (in->header.opcode == FUSE_GETATTR &&
142                                 in->header.nodeid == ino);
143                 }, Eq(true)),
144                 _)
145         ).WillOnce(Invoke(ReturnImmediate([](auto i __unused, auto out) {
146                 SET_OUT_HEADER_LEN(out, attr);
147                 out->body.attr.attr.ino = ino;  // Must match nodeid
148                 out->body.attr.attr.mode = S_IFREG | 0644;
149                 out->body.attr.attr.size = 1;
150                 out->body.attr.attr.blocks = 2;
151                 out->body.attr.attr.atime = 3;
152                 out->body.attr.attr.mtime = 4;
153                 out->body.attr.attr.ctime = 5;
154                 out->body.attr.attr.atimensec = 6;
155                 out->body.attr.attr.mtimensec = 7;
156                 out->body.attr.attr.ctimensec = 8;
157                 out->body.attr.attr.nlink = 9;
158                 out->body.attr.attr.uid = 10;
159                 out->body.attr.attr.gid = 11;
160                 out->body.attr.attr.rdev = 12;
161         })));
162
163         ASSERT_EQ(0, stat(FULLPATH, &sb)) << strerror(errno);
164         EXPECT_EQ(1, sb.st_size);
165         EXPECT_EQ(2, sb.st_blocks);
166         EXPECT_EQ(3, sb.st_atim.tv_sec);
167         EXPECT_EQ(6, sb.st_atim.tv_nsec);
168         EXPECT_EQ(4, sb.st_mtim.tv_sec);
169         EXPECT_EQ(7, sb.st_mtim.tv_nsec);
170         EXPECT_EQ(5, sb.st_ctim.tv_sec);
171         EXPECT_EQ(8, sb.st_ctim.tv_nsec);
172         EXPECT_EQ(9ull, sb.st_nlink);
173         EXPECT_EQ(10ul, sb.st_uid);
174         EXPECT_EQ(11ul, sb.st_gid);
175         EXPECT_EQ(12ul, sb.st_rdev);
176         EXPECT_EQ(ino, sb.st_ino);
177         EXPECT_EQ(S_IFREG | 0644, sb.st_mode);
178
179         //st_birthtim and st_flags are not supported by protocol 7.8.  They're
180         //only supported as OS-specific extensions to OSX.
181         //EXPECT_EQ(, sb.st_birthtim);
182         //EXPECT_EQ(, sb.st_flags);
183         
184         //FUSE can't set st_blksize until protocol 7.9
185 }