From: Dhairya Parmar Date: Wed, 17 Jul 2024 13:00:29 +0000 (+0530) Subject: src/test: test sync/async i/o code paths with huge (4GiB) buffers X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=28b15bd1ec58e2a1cfbcf139ea3df81079f71e3e;p=ceph.git src/test: test sync/async i/o code paths with huge (4GiB) buffers to make sure there are no crashes and max bytes written is INT_MAX (clamped in write paths). Fixes: https://tracker.ceph.com/issues/66245 Signed-off-by: Dhairya Parmar --- diff --git a/src/test/client/nonblocking.cc b/src/test/client/nonblocking.cc index 93bcfabd3fcf..5be6f4fe8d57 100644 --- a/src/test/client/nonblocking.cc +++ b/src/test/client/nonblocking.cc @@ -18,6 +18,7 @@ #include #include +#include #include "test/client/TestClient.h" @@ -716,3 +717,74 @@ TEST_F(TestClient, LlreadvContiguousLlwritevNonContiguous) { client->ll_release(fh); ASSERT_EQ(0, client->ll_unlink(root, filename, myperm)); } + +TEST_F(TestClient, LlreadvLlwritevLargeBuffers) { + /* Test that async I/O code paths handle large buffers (total len >= 4GiB)*/ + int mypid = getpid(); + char filename[256]; + + client->unmount(); + TearDown(); + SetUp(); + + sprintf(filename, "test_llreadvllwritevlargebuffers%u", mypid); + + Inode *root, *file; + root = client->get_root(); + ASSERT_NE(root, (Inode *)NULL); + + Fh *fh; + struct ceph_statx stx; + + ASSERT_EQ(0, client->ll_createx(root, filename, 0666, + O_RDWR | O_CREAT | O_TRUNC, + &file, &fh, &stx, 0, 0, myperm)); + + struct statvfs stbuf; + int64_t rc; + rc = client->ll_statfs(root, &stbuf, myperm); + ASSERT_EQ(rc, 0); + int64_t fs_available_space = stbuf.f_bfree * stbuf.f_bsize; + ASSERT_GT(fs_available_space, 0); + + const size_t BUFSIZE = (size_t)INT_MAX + 1; + int64_t bytes_written = 0, bytes_read = 0; + + C_SaferCond writefinish; + C_SaferCond readfinish; + + auto out_buf_0 = std::make_unique(BUFSIZE); + memset(out_buf_0.get(), 0xDD, BUFSIZE); + auto out_buf_1 = std::make_unique(BUFSIZE); + memset(out_buf_1.get(), 0xFF, BUFSIZE); + + struct iovec iov_out[2] = { + {out_buf_0.get(), BUFSIZE}, + {out_buf_1.get(), BUFSIZE} + }; + + bufferlist bl; + auto in_buf_0 = std::make_unique(BUFSIZE); + auto in_buf_1 = std::make_unique(BUFSIZE); + + struct iovec iov_in[2] = { + {in_buf_0.get(), BUFSIZE}, + {in_buf_1.get(), BUFSIZE} + }; + + rc = client->ll_preadv_pwritev(fh, iov_out, 2, 0, true, &writefinish, + nullptr); + ASSERT_EQ(rc, 0); + bytes_written = writefinish.wait(); + // total write length is clamped to INT_MAX in write paths + ASSERT_EQ(bytes_written, INT_MAX); + + rc = client->ll_preadv_pwritev(fh, iov_in, 2, 0, false, &readfinish, &bl); + ASSERT_EQ(rc, 0); + bytes_read = readfinish.wait(); + // total read length is clamped to INT_MAX in read paths + ASSERT_EQ(bytes_read, INT_MAX); + + client->ll_release(fh); + ASSERT_EQ(0, client->ll_unlink(root, filename, myperm)); +} \ No newline at end of file diff --git a/src/test/client/syncio.cc b/src/test/client/syncio.cc index f40503a3909f..fa5bbaf1ce4d 100644 --- a/src/test/client/syncio.cc +++ b/src/test/client/syncio.cc @@ -18,6 +18,7 @@ #include #include +#include #include "test/client/TestClient.h" @@ -77,3 +78,64 @@ TEST_F(TestClient, LlreadvLlwritevInvalidFileHandleSync) { rc = client->ll_readv(fh, iov_in, 2, 0); ASSERT_EQ(rc, -CEPHFS_EBADF); } + +TEST_F(TestClient, LlreadvLlwritevLargeBuffersSync) { + /* Test that sync I/O code paths handle large buffers (total len >= 4GiB)*/ + int mypid = getpid(); + char filename[256]; + + client->unmount(); + TearDown(); + SetUp(); + + sprintf(filename, "test_llreadvllwritevlargebufferssync%u", mypid); + + Inode *root, *file; + root = client->get_root(); + ASSERT_NE(root, (Inode *)NULL); + + Fh *fh; + struct ceph_statx stx; + + ASSERT_EQ(0, client->ll_createx(root, filename, 0666, + O_RDWR | O_CREAT | O_TRUNC, + &file, &fh, &stx, 0, 0, myperm)); + + struct statvfs stbuf; + int64_t rc; + const size_t BUFSIZE = (size_t)INT_MAX + 1; + rc = client->ll_statfs(root, &stbuf, myperm); + ASSERT_EQ(rc, 0); + int64_t fs_available_space = stbuf.f_bfree * stbuf.f_bsize; + ASSERT_GT(fs_available_space, BUFSIZE * 2); + + auto out_buf_0 = std::make_unique(BUFSIZE); + memset(out_buf_0.get(), 0xDD, BUFSIZE); + auto out_buf_1 = std::make_unique(BUFSIZE); + memset(out_buf_1.get(), 0xFF, BUFSIZE); + + struct iovec iov_out[2] = { + {out_buf_0.get(), BUFSIZE}, + {out_buf_1.get(), BUFSIZE} + }; + + bufferlist bl; + auto in_buf_0 = std::make_unique(BUFSIZE); + auto in_buf_1 = std::make_unique(BUFSIZE); + + struct iovec iov_in[2] = { + {in_buf_0.get(), BUFSIZE}, + {in_buf_1.get(), BUFSIZE} + }; + + rc = client->ll_writev(fh, iov_out, 2, 0); + // total write length is clamped to INT_MAX in write paths + ASSERT_EQ(rc, INT_MAX); + + rc = client->ll_readv(fh, iov_in, 2, 0); + // total write length is clamped to INT_MAX in write paths + ASSERT_EQ(rc, INT_MAX); + + client->ll_release(fh); + ASSERT_EQ(0, client->ll_unlink(root, filename, myperm)); +}