github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/fuse/linux/read_test.cc (about) 1 // Copyright 2020 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <errno.h> 16 #include <fcntl.h> 17 #include <linux/fuse.h> 18 #include <sys/stat.h> 19 #include <sys/statfs.h> 20 #include <sys/types.h> 21 #include <unistd.h> 22 23 #include <string> 24 #include <vector> 25 26 #include "gtest/gtest.h" 27 #include "test/fuse/linux/fuse_base.h" 28 #include "test/util/fuse_util.h" 29 #include "test/util/test_util.h" 30 31 namespace gvisor { 32 namespace testing { 33 34 namespace { 35 36 class ReadTest : public FuseTest { 37 void SetUp() override { 38 FuseTest::SetUp(); 39 test_file_path_ = JoinPath(mount_point_.path().c_str(), test_file_); 40 } 41 42 // TearDown overrides the parent's function 43 // to skip checking the unconsumed release request at the end. 44 void TearDown() override { UnmountFuse(); } 45 46 protected: 47 const std::string test_file_ = "test_file"; 48 const mode_t test_file_mode_ = S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO; 49 const uint64_t test_fh_ = 1; 50 const uint32_t open_flag_ = O_RDWR; 51 52 std::string test_file_path_; 53 54 PosixErrorOr<FileDescriptor> OpenTestFile(const std::string &path, 55 uint64_t size = 512) { 56 SetServerInodeLookup(test_file_, test_file_mode_, size); 57 58 struct fuse_out_header out_header_open = { 59 .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_open_out), 60 }; 61 struct fuse_open_out out_payload_open = { 62 .fh = test_fh_, 63 .open_flags = open_flag_, 64 }; 65 auto iov_out_open = FuseGenerateIovecs(out_header_open, out_payload_open); 66 SetServerResponse(FUSE_OPEN, iov_out_open); 67 68 auto res = Open(path.c_str(), open_flag_); 69 if (res.ok()) { 70 SkipServerActualRequest(); 71 } 72 return res; 73 } 74 }; 75 76 class ReadTestSmallMaxRead : public ReadTest { 77 void SetUp() override { 78 MountFuse(mountOpts); 79 SetUpFuseServer(); 80 test_file_path_ = JoinPath(mount_point_.path().c_str(), test_file_); 81 } 82 83 protected: 84 constexpr static char mountOpts[] = 85 "rootmode=755,user_id=0,group_id=0,max_read=4096"; 86 // 4096 is hard-coded as the max_read in mount options. 87 const int size_fragment = 4096; 88 }; 89 90 TEST_F(ReadTest, ReadWhole) { 91 auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_)); 92 93 // Prepare for the read. 94 const int n_read = 5; 95 std::vector<char> data(n_read); 96 RandomizeBuffer(data.data(), data.size()); 97 struct fuse_out_header out_header_read = { 98 .len = 99 static_cast<uint32_t>(sizeof(struct fuse_out_header) + data.size()), 100 }; 101 auto iov_out_read = FuseGenerateIovecs(out_header_read, data); 102 SetServerResponse(FUSE_READ, iov_out_read); 103 104 // Read the whole "file". 105 std::vector<char> buf(n_read); 106 EXPECT_THAT(read(fd.get(), buf.data(), n_read), 107 SyscallSucceedsWithValue(n_read)); 108 109 // Check the read request. 110 struct fuse_in_header in_header_read; 111 struct fuse_read_in in_payload_read; 112 auto iov_in = FuseGenerateIovecs(in_header_read, in_payload_read); 113 GetServerActualRequest(iov_in); 114 115 EXPECT_EQ(in_payload_read.fh, test_fh_); 116 EXPECT_EQ(in_header_read.len, 117 sizeof(in_header_read) + sizeof(in_payload_read)); 118 EXPECT_EQ(in_header_read.opcode, FUSE_READ); 119 EXPECT_EQ(in_payload_read.offset, 0); 120 EXPECT_EQ(buf, data); 121 } 122 123 TEST_F(ReadTest, ReadPartial) { 124 auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_)); 125 126 // Prepare for the read. 127 const int n_data = 10; 128 std::vector<char> data(n_data); 129 RandomizeBuffer(data.data(), data.size()); 130 // Note: due to read ahead, current read implementation will treat any 131 // response that is longer than requested as correct (i.e. not reach the EOF). 132 // Therefore, the test below should make sure the size to read does not exceed 133 // n_data. 134 struct fuse_out_header out_header_read = { 135 .len = 136 static_cast<uint32_t>(sizeof(struct fuse_out_header) + data.size()), 137 }; 138 auto iov_out_read = FuseGenerateIovecs(out_header_read, data); 139 struct fuse_in_header in_header_read; 140 struct fuse_read_in in_payload_read; 141 auto iov_in = FuseGenerateIovecs(in_header_read, in_payload_read); 142 143 std::vector<char> buf(n_data); 144 145 // Read 1 bytes. 146 SetServerResponse(FUSE_READ, iov_out_read); 147 EXPECT_THAT(read(fd.get(), buf.data(), 1), SyscallSucceedsWithValue(1)); 148 149 // Check the 1-byte read request. 150 GetServerActualRequest(iov_in); 151 EXPECT_EQ(in_payload_read.fh, test_fh_); 152 EXPECT_EQ(in_header_read.len, 153 sizeof(in_header_read) + sizeof(in_payload_read)); 154 EXPECT_EQ(in_header_read.opcode, FUSE_READ); 155 EXPECT_EQ(in_payload_read.offset, 0); 156 157 // Read 3 bytes. 158 SetServerResponse(FUSE_READ, iov_out_read); 159 EXPECT_THAT(read(fd.get(), buf.data(), 3), SyscallSucceedsWithValue(3)); 160 161 // Check the 3-byte read request. 162 GetServerActualRequest(iov_in); 163 EXPECT_EQ(in_payload_read.fh, test_fh_); 164 EXPECT_EQ(in_payload_read.offset, 1); 165 166 // Read 5 bytes. 167 SetServerResponse(FUSE_READ, iov_out_read); 168 EXPECT_THAT(read(fd.get(), buf.data(), 5), SyscallSucceedsWithValue(5)); 169 170 // Check the 5-byte read request. 171 GetServerActualRequest(iov_in); 172 EXPECT_EQ(in_payload_read.fh, test_fh_); 173 EXPECT_EQ(in_payload_read.offset, 4); 174 } 175 176 TEST_F(ReadTest, PRead) { 177 const int file_size = 512; 178 auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_, file_size)); 179 180 // Prepare for the read. 181 const int n_read = 5; 182 std::vector<char> data(n_read); 183 RandomizeBuffer(data.data(), data.size()); 184 struct fuse_out_header out_header_read = { 185 .len = 186 static_cast<uint32_t>(sizeof(struct fuse_out_header) + data.size()), 187 }; 188 auto iov_out_read = FuseGenerateIovecs(out_header_read, data); 189 SetServerResponse(FUSE_READ, iov_out_read); 190 191 // Read some bytes. 192 std::vector<char> buf(n_read); 193 const int offset_read = file_size >> 1; 194 EXPECT_THAT(pread(fd.get(), buf.data(), n_read, offset_read), 195 SyscallSucceedsWithValue(n_read)); 196 197 // Check the read request. 198 struct fuse_in_header in_header_read; 199 struct fuse_read_in in_payload_read; 200 auto iov_in = FuseGenerateIovecs(in_header_read, in_payload_read); 201 GetServerActualRequest(iov_in); 202 203 EXPECT_EQ(in_payload_read.fh, test_fh_); 204 EXPECT_EQ(in_header_read.len, 205 sizeof(in_header_read) + sizeof(in_payload_read)); 206 EXPECT_EQ(in_header_read.opcode, FUSE_READ); 207 EXPECT_EQ(in_payload_read.offset, offset_read); 208 EXPECT_EQ(buf, data); 209 } 210 211 TEST_F(ReadTest, ReadZero) { 212 auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_)); 213 214 // Issue the read. 215 std::vector<char> buf; 216 EXPECT_THAT(read(fd.get(), buf.data(), 0), SyscallSucceedsWithValue(0)); 217 } 218 219 TEST_F(ReadTest, ReadShort) { 220 auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_)); 221 222 // Prepare for the short read. 223 const int n_read = 5; 224 std::vector<char> data(n_read >> 1); 225 RandomizeBuffer(data.data(), data.size()); 226 struct fuse_out_header out_header_read = { 227 .len = 228 static_cast<uint32_t>(sizeof(struct fuse_out_header) + data.size()), 229 }; 230 auto iov_out_read = FuseGenerateIovecs(out_header_read, data); 231 SetServerResponse(FUSE_READ, iov_out_read); 232 233 // Read the whole "file". 234 std::vector<char> buf(n_read); 235 EXPECT_THAT(read(fd.get(), buf.data(), n_read), 236 SyscallSucceedsWithValue(data.size())); 237 238 // Check the read request. 239 struct fuse_in_header in_header_read; 240 struct fuse_read_in in_payload_read; 241 auto iov_in = FuseGenerateIovecs(in_header_read, in_payload_read); 242 GetServerActualRequest(iov_in); 243 244 EXPECT_EQ(in_payload_read.fh, test_fh_); 245 EXPECT_EQ(in_header_read.len, 246 sizeof(in_header_read) + sizeof(in_payload_read)); 247 EXPECT_EQ(in_header_read.opcode, FUSE_READ); 248 EXPECT_EQ(in_payload_read.offset, 0); 249 std::vector<char> short_buf(buf.begin(), buf.begin() + data.size()); 250 EXPECT_EQ(short_buf, data); 251 } 252 253 TEST_F(ReadTest, ReadShortEOF) { 254 auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_)); 255 256 // Prepare for the short read. 257 struct fuse_out_header out_header_read = { 258 .len = static_cast<uint32_t>(sizeof(struct fuse_out_header)), 259 }; 260 auto iov_out_read = FuseGenerateIovecs(out_header_read); 261 SetServerResponse(FUSE_READ, iov_out_read); 262 263 // Read the whole "file". 264 const int n_read = 10; 265 std::vector<char> buf(n_read); 266 EXPECT_THAT(read(fd.get(), buf.data(), n_read), SyscallSucceedsWithValue(0)); 267 268 // Check the read request. 269 struct fuse_in_header in_header_read; 270 struct fuse_read_in in_payload_read; 271 auto iov_in = FuseGenerateIovecs(in_header_read, in_payload_read); 272 GetServerActualRequest(iov_in); 273 274 EXPECT_EQ(in_payload_read.fh, test_fh_); 275 EXPECT_EQ(in_header_read.len, 276 sizeof(in_header_read) + sizeof(in_payload_read)); 277 EXPECT_EQ(in_header_read.opcode, FUSE_READ); 278 EXPECT_EQ(in_payload_read.offset, 0); 279 } 280 281 TEST_F(ReadTestSmallMaxRead, ReadSmallMaxRead) { 282 const int n_fragment = 10; 283 const int n_read = size_fragment * n_fragment; 284 285 auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_, n_read)); 286 287 // Prepare for the read. 288 std::vector<char> data(size_fragment); 289 RandomizeBuffer(data.data(), data.size()); 290 struct fuse_out_header out_header_read = { 291 .len = 292 static_cast<uint32_t>(sizeof(struct fuse_out_header) + data.size()), 293 }; 294 auto iov_out_read = FuseGenerateIovecs(out_header_read, data); 295 296 for (int i = 0; i < n_fragment; ++i) { 297 SetServerResponse(FUSE_READ, iov_out_read); 298 } 299 300 // Read the whole "file". 301 std::vector<char> buf(n_read); 302 EXPECT_THAT(read(fd.get(), buf.data(), n_read), 303 SyscallSucceedsWithValue(n_read)); 304 305 ASSERT_EQ(GetServerNumUnsentResponses(), 0); 306 ASSERT_EQ(GetServerNumUnconsumedRequests(), n_fragment); 307 308 // Check each read segment. 309 struct fuse_in_header in_header_read; 310 struct fuse_read_in in_payload_read; 311 auto iov_in = FuseGenerateIovecs(in_header_read, in_payload_read); 312 313 for (int i = 0; i < n_fragment; ++i) { 314 GetServerActualRequest(iov_in); 315 EXPECT_EQ(in_payload_read.fh, test_fh_); 316 EXPECT_EQ(in_header_read.len, 317 sizeof(in_header_read) + sizeof(in_payload_read)); 318 EXPECT_EQ(in_header_read.opcode, FUSE_READ); 319 EXPECT_EQ(in_payload_read.offset, i * size_fragment); 320 EXPECT_EQ(in_payload_read.size, size_fragment); 321 322 auto it = buf.begin() + i * size_fragment; 323 EXPECT_EQ(std::vector<char>(it, it + size_fragment), data); 324 } 325 } 326 327 TEST_F(ReadTestSmallMaxRead, ReadSmallMaxReadShort) { 328 const int n_fragment = 10; 329 const int n_read = size_fragment * n_fragment; 330 331 auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_, n_read)); 332 333 // Prepare for the read. 334 std::vector<char> data(size_fragment); 335 RandomizeBuffer(data.data(), data.size()); 336 struct fuse_out_header out_header_read = { 337 .len = 338 static_cast<uint32_t>(sizeof(struct fuse_out_header) + data.size()), 339 }; 340 auto iov_out_read = FuseGenerateIovecs(out_header_read, data); 341 342 for (int i = 0; i < n_fragment - 1; ++i) { 343 SetServerResponse(FUSE_READ, iov_out_read); 344 } 345 346 // The last fragment is a short read. 347 std::vector<char> half_data(data.begin(), data.begin() + (data.size() >> 1)); 348 struct fuse_out_header out_header_read_short = { 349 .len = static_cast<uint32_t>(sizeof(struct fuse_out_header) + 350 half_data.size()), 351 }; 352 auto iov_out_read_short = 353 FuseGenerateIovecs(out_header_read_short, half_data); 354 SetServerResponse(FUSE_READ, iov_out_read_short); 355 356 // Read the whole "file". 357 std::vector<char> buf(n_read); 358 EXPECT_THAT(read(fd.get(), buf.data(), n_read), 359 SyscallSucceedsWithValue(n_read - (data.size() >> 1))); 360 361 ASSERT_EQ(GetServerNumUnsentResponses(), 0); 362 ASSERT_EQ(GetServerNumUnconsumedRequests(), n_fragment); 363 364 // Check each read segment. 365 struct fuse_in_header in_header_read; 366 struct fuse_read_in in_payload_read; 367 auto iov_in = FuseGenerateIovecs(in_header_read, in_payload_read); 368 369 for (int i = 0; i < n_fragment; ++i) { 370 GetServerActualRequest(iov_in); 371 EXPECT_EQ(in_payload_read.fh, test_fh_); 372 EXPECT_EQ(in_header_read.len, 373 sizeof(in_header_read) + sizeof(in_payload_read)); 374 EXPECT_EQ(in_header_read.opcode, FUSE_READ); 375 EXPECT_EQ(in_payload_read.offset, i * size_fragment); 376 EXPECT_EQ(in_payload_read.size, size_fragment); 377 378 auto it = buf.begin() + i * size_fragment; 379 if (i != n_fragment - 1) { 380 EXPECT_EQ(std::vector<char>(it, it + data.size()), data); 381 } else { 382 EXPECT_EQ(std::vector<char>(it, it + half_data.size()), half_data); 383 } 384 } 385 } 386 387 } // namespace 388 389 } // namespace testing 390 } // namespace gvisor