github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/fuse/linux/write_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 WriteTest : 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 WriteTestSmallMaxWrite : public WriteTest {
    77    void SetUp() override {
    78      MountFuse();
    79      SetUpFuseServer(&fuse_init_payload);
    80      test_file_path_ = JoinPath(mount_point_.path().c_str(), test_file_);
    81    }
    82  
    83   protected:
    84    const static uint32_t max_write_ = 4096;
    85    constexpr static struct fuse_init_out fuse_init_payload = {
    86        .major = 7,
    87        .max_write = max_write_,
    88    };
    89  
    90    const uint32_t size_fragment = max_write_;
    91  };
    92  
    93  TEST_F(WriteTest, WriteNormal) {
    94    auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_));
    95  
    96    // Prepare for the write.
    97    const int n_write = 10;
    98    struct fuse_out_header out_header_write = {
    99        .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_write_out),
   100    };
   101    struct fuse_write_out out_payload_write = {
   102        .size = n_write,
   103    };
   104    auto iov_out_write = FuseGenerateIovecs(out_header_write, out_payload_write);
   105    SetServerResponse(FUSE_WRITE, iov_out_write);
   106  
   107    // Issue the write.
   108    std::vector<char> buf(n_write);
   109    RandomizeBuffer(buf.data(), buf.size());
   110    EXPECT_THAT(write(fd.get(), buf.data(), n_write),
   111                SyscallSucceedsWithValue(n_write));
   112  
   113    // Check the write request.
   114    struct fuse_in_header in_header_write;
   115    struct fuse_write_in in_payload_write;
   116    std::vector<char> payload_buf(n_write);
   117    auto iov_in_write =
   118        FuseGenerateIovecs(in_header_write, in_payload_write, payload_buf);
   119    GetServerActualRequest(iov_in_write);
   120  
   121    EXPECT_EQ(in_payload_write.fh, test_fh_);
   122    EXPECT_EQ(in_header_write.len,
   123              sizeof(in_header_write) + sizeof(in_payload_write));
   124    EXPECT_EQ(in_header_write.opcode, FUSE_WRITE);
   125    EXPECT_EQ(in_payload_write.offset, 0);
   126    EXPECT_EQ(in_payload_write.size, n_write);
   127    EXPECT_EQ(buf, payload_buf);
   128  }
   129  
   130  TEST_F(WriteTest, WriteShort) {
   131    auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_));
   132  
   133    // Prepare for the write.
   134    const int n_write = 10, n_written = 5;
   135    struct fuse_out_header out_header_write = {
   136        .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_write_out),
   137    };
   138    struct fuse_write_out out_payload_write = {
   139        .size = n_written,
   140    };
   141    auto iov_out_write = FuseGenerateIovecs(out_header_write, out_payload_write);
   142    SetServerResponse(FUSE_WRITE, iov_out_write);
   143  
   144    // Issue the write.
   145    std::vector<char> buf(n_write);
   146    RandomizeBuffer(buf.data(), buf.size());
   147    EXPECT_THAT(write(fd.get(), buf.data(), n_write),
   148                SyscallSucceedsWithValue(n_written));
   149  
   150    // Check the write request.
   151    struct fuse_in_header in_header_write;
   152    struct fuse_write_in in_payload_write;
   153    std::vector<char> payload_buf(n_write);
   154    auto iov_in_write =
   155        FuseGenerateIovecs(in_header_write, in_payload_write, payload_buf);
   156    GetServerActualRequest(iov_in_write);
   157  
   158    EXPECT_EQ(in_payload_write.fh, test_fh_);
   159    EXPECT_EQ(in_header_write.len,
   160              sizeof(in_header_write) + sizeof(in_payload_write));
   161    EXPECT_EQ(in_header_write.opcode, FUSE_WRITE);
   162    EXPECT_EQ(in_payload_write.offset, 0);
   163    EXPECT_EQ(in_payload_write.size, n_write);
   164    EXPECT_EQ(buf, payload_buf);
   165  }
   166  
   167  TEST_F(WriteTest, WriteShortZero) {
   168    auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_));
   169  
   170    // Prepare for the write.
   171    const int n_write = 10;
   172    struct fuse_out_header out_header_write = {
   173        .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_write_out),
   174    };
   175    struct fuse_write_out out_payload_write = {
   176        .size = 0,
   177    };
   178    auto iov_out_write = FuseGenerateIovecs(out_header_write, out_payload_write);
   179    SetServerResponse(FUSE_WRITE, iov_out_write);
   180  
   181    // Issue the write.
   182    std::vector<char> buf(n_write);
   183    RandomizeBuffer(buf.data(), buf.size());
   184    EXPECT_THAT(write(fd.get(), buf.data(), n_write), SyscallFailsWithErrno(EIO));
   185  
   186    // Check the write request.
   187    struct fuse_in_header in_header_write;
   188    struct fuse_write_in in_payload_write;
   189    std::vector<char> payload_buf(n_write);
   190    auto iov_in_write =
   191        FuseGenerateIovecs(in_header_write, in_payload_write, payload_buf);
   192    GetServerActualRequest(iov_in_write);
   193  
   194    EXPECT_EQ(in_payload_write.fh, test_fh_);
   195    EXPECT_EQ(in_header_write.len,
   196              sizeof(in_header_write) + sizeof(in_payload_write));
   197    EXPECT_EQ(in_header_write.opcode, FUSE_WRITE);
   198    EXPECT_EQ(in_payload_write.offset, 0);
   199    EXPECT_EQ(in_payload_write.size, n_write);
   200    EXPECT_EQ(buf, payload_buf);
   201  }
   202  
   203  TEST_F(WriteTest, WriteZero) {
   204    auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_));
   205  
   206    // Issue the write.
   207    std::vector<char> buf(0);
   208    EXPECT_THAT(write(fd.get(), buf.data(), 0), SyscallSucceedsWithValue(0));
   209  }
   210  
   211  TEST_F(WriteTest, PWrite) {
   212    const int file_size = 512;
   213    auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_, file_size));
   214  
   215    // Prepare for the write.
   216    const int n_write = 10;
   217    struct fuse_out_header out_header_write = {
   218        .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_write_out),
   219    };
   220    struct fuse_write_out out_payload_write = {
   221        .size = n_write,
   222    };
   223    auto iov_out_write = FuseGenerateIovecs(out_header_write, out_payload_write);
   224    SetServerResponse(FUSE_WRITE, iov_out_write);
   225  
   226    // Issue the write.
   227    std::vector<char> buf(n_write);
   228    RandomizeBuffer(buf.data(), buf.size());
   229    const int offset_write = file_size >> 1;
   230    EXPECT_THAT(pwrite(fd.get(), buf.data(), n_write, offset_write),
   231                SyscallSucceedsWithValue(n_write));
   232  
   233    // Check the write request.
   234    struct fuse_in_header in_header_write;
   235    struct fuse_write_in in_payload_write;
   236    std::vector<char> payload_buf(n_write);
   237    auto iov_in_write =
   238        FuseGenerateIovecs(in_header_write, in_payload_write, payload_buf);
   239    GetServerActualRequest(iov_in_write);
   240  
   241    EXPECT_EQ(in_payload_write.fh, test_fh_);
   242    EXPECT_EQ(in_header_write.len,
   243              sizeof(in_header_write) + sizeof(in_payload_write));
   244    EXPECT_EQ(in_header_write.opcode, FUSE_WRITE);
   245    EXPECT_EQ(in_payload_write.offset, offset_write);
   246    EXPECT_EQ(in_payload_write.size, n_write);
   247    EXPECT_EQ(buf, payload_buf);
   248  }
   249  
   250  TEST_F(WriteTestSmallMaxWrite, WriteSmallMaxWrie) {
   251    const int n_fragment = 10;
   252    const int n_write = size_fragment * n_fragment;
   253  
   254    auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_, n_write));
   255  
   256    // Prepare for the write.
   257    struct fuse_out_header out_header_write = {
   258        .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_write_out),
   259    };
   260    struct fuse_write_out out_payload_write = {
   261        .size = size_fragment,
   262    };
   263    auto iov_out_write = FuseGenerateIovecs(out_header_write, out_payload_write);
   264  
   265    for (int i = 0; i < n_fragment; ++i) {
   266      SetServerResponse(FUSE_WRITE, iov_out_write);
   267    }
   268  
   269    // Issue the write.
   270    std::vector<char> buf(n_write);
   271    RandomizeBuffer(buf.data(), buf.size());
   272    EXPECT_THAT(write(fd.get(), buf.data(), n_write),
   273                SyscallSucceedsWithValue(n_write));
   274  
   275    ASSERT_EQ(GetServerNumUnsentResponses(), 0);
   276    ASSERT_EQ(GetServerNumUnconsumedRequests(), n_fragment);
   277  
   278    // Check the write request.
   279    struct fuse_in_header in_header_write;
   280    struct fuse_write_in in_payload_write;
   281    std::vector<char> payload_buf(size_fragment);
   282    auto iov_in_write =
   283        FuseGenerateIovecs(in_header_write, in_payload_write, payload_buf);
   284  
   285    for (int i = 0; i < n_fragment; ++i) {
   286      GetServerActualRequest(iov_in_write);
   287  
   288      EXPECT_EQ(in_payload_write.fh, test_fh_);
   289      EXPECT_EQ(in_header_write.len,
   290                sizeof(in_header_write) + sizeof(in_payload_write));
   291      EXPECT_EQ(in_header_write.opcode, FUSE_WRITE);
   292      EXPECT_EQ(in_payload_write.offset, i * size_fragment);
   293      EXPECT_EQ(in_payload_write.size, size_fragment);
   294  
   295      auto it = buf.begin() + i * size_fragment;
   296      EXPECT_EQ(std::vector<char>(it, it + size_fragment), payload_buf);
   297    }
   298  }
   299  
   300  }  // namespace
   301  
   302  }  // namespace testing
   303  }  // namespace gvisor