Skip to content

Commit 9fd7ad5

Browse files
committed
Merge PR ceph#55457 into main
* refs/pull/55457/head: client: check for bad file handle in low level I/O APIs client: check for bad file handle in ll_preadv_pwritev client: add function to check if file handle exists src/test: test async I/O with invalid/closed file handle Reviewed-by: Venky Shankar <[email protected]>
2 parents 55ac8d6 + 6614933 commit 9fd7ad5

File tree

3 files changed

+137
-15
lines changed

3 files changed

+137
-15
lines changed

src/client/Client.cc

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15779,8 +15779,14 @@ loff_t Client::ll_lseek(Fh *fh, loff_t offset, int whence)
1577915779
int Client::ll_read(Fh *fh, loff_t off, loff_t len, bufferlist *bl)
1578015780
{
1578115781
RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
15782-
if (!mref_reader.is_state_satisfied())
15782+
if (!mref_reader.is_state_satisfied()) {
1578315783
return -CEPHFS_ENOTCONN;
15784+
}
15785+
15786+
if (fh == NULL || !_ll_fh_exists(fh)) {
15787+
ldout(cct, 3) << "(fh)" << fh << " is invalid" << dendl;
15788+
return -CEPHFS_EBADF;
15789+
}
1578415790

1578515791
ldout(cct, 3) << "ll_read " << fh << " " << fh->inode->ino << " " << " " << off << "~" << len << dendl;
1578615792
tout(cct) << "ll_read" << std::endl;
@@ -15917,17 +15923,23 @@ int Client::ll_commit_blocks(Inode *in,
1591715923

1591815924
int Client::ll_write(Fh *fh, loff_t off, loff_t len, const char *data)
1591915925
{
15926+
RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
15927+
if (!mref_reader.is_state_satisfied()) {
15928+
return -CEPHFS_ENOTCONN;
15929+
}
15930+
15931+
if (fh == NULL || !_ll_fh_exists(fh)) {
15932+
ldout(cct, 3) << "(fh)" << fh << " is invalid" << dendl;
15933+
return -CEPHFS_EBADF;
15934+
}
15935+
1592015936
ldout(cct, 3) << "ll_write " << fh << " " << fh->inode->ino << " " << off <<
1592115937
"~" << len << dendl;
1592215938
tout(cct) << "ll_write" << std::endl;
1592315939
tout(cct) << (uintptr_t)fh << std::endl;
1592415940
tout(cct) << off << std::endl;
1592515941
tout(cct) << len << std::endl;
1592615942

15927-
RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
15928-
if (!mref_reader.is_state_satisfied())
15929-
return -CEPHFS_ENOTCONN;
15930-
1593115943
/* We can't return bytes written larger than INT_MAX, clamp len to that */
1593215944
len = std::min(len, (loff_t)INT_MAX);
1593315945
std::scoped_lock lock(client_lock);
@@ -15941,8 +15953,14 @@ int Client::ll_write(Fh *fh, loff_t off, loff_t len, const char *data)
1594115953
int64_t Client::ll_writev(struct Fh *fh, const struct iovec *iov, int iovcnt, int64_t off)
1594215954
{
1594315955
RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
15944-
if (!mref_reader.is_state_satisfied())
15956+
if (!mref_reader.is_state_satisfied()) {
1594515957
return -CEPHFS_ENOTCONN;
15958+
}
15959+
15960+
if (fh == NULL || !_ll_fh_exists(fh)) {
15961+
ldout(cct, 3) << "(fh)" << fh << " is invalid" << dendl;
15962+
return -CEPHFS_EBADF;
15963+
}
1594615964

1594715965
std::scoped_lock cl(client_lock);
1594815966
return _preadv_pwritev_locked(fh, iov, iovcnt, off, true, false);
@@ -15951,8 +15969,14 @@ int64_t Client::ll_writev(struct Fh *fh, const struct iovec *iov, int iovcnt, in
1595115969
int64_t Client::ll_readv(struct Fh *fh, const struct iovec *iov, int iovcnt, int64_t off)
1595215970
{
1595315971
RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
15954-
if (!mref_reader.is_state_satisfied())
15972+
if (!mref_reader.is_state_satisfied()) {
1595515973
return -CEPHFS_ENOTCONN;
15974+
}
15975+
15976+
if (fh == NULL || !_ll_fh_exists(fh)) {
15977+
ldout(cct, 3) << "(fh)" << fh << " is invalid" << dendl;
15978+
return -CEPHFS_EBADF;
15979+
}
1595615980

1595715981
std::scoped_lock cl(client_lock);
1595815982
return _preadv_pwritev_locked(fh, iov, iovcnt, off, false, false);
@@ -15963,23 +15987,34 @@ int64_t Client::ll_preadv_pwritev(struct Fh *fh, const struct iovec *iov,
1596315987
Context *onfinish, bufferlist *bl,
1596415988
bool do_fsync, bool syncdataonly)
1596515989
{
15990+
int64_t retval = -1;
15991+
1596615992
RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
1596715993
if (!mref_reader.is_state_satisfied()) {
15968-
int64_t rc = -CEPHFS_ENOTCONN;
15994+
retval = -CEPHFS_ENOTCONN;
1596915995
if (onfinish != nullptr) {
15970-
onfinish->complete(rc);
15996+
onfinish->complete(retval);
1597115997
/* async call should always return zero to caller and allow the
1597215998
caller to wait on callback for the actual errno. */
15973-
rc = 0;
15999+
retval = 0;
16000+
}
16001+
return retval;
16002+
}
16003+
16004+
if(fh == NULL || !_ll_fh_exists(fh)) {
16005+
ldout(cct, 3) << "(fh)" << fh << " is invalid" << dendl;
16006+
retval = -CEPHFS_EBADF;
16007+
if (onfinish != nullptr) {
16008+
onfinish->complete(retval);
16009+
retval = 0;
1597416010
}
15975-
return rc;
16011+
return retval;
1597616012
}
1597716013

1597816014
std::scoped_lock cl(client_lock);
1597916015

15980-
int64_t retval = _preadv_pwritev_locked(fh, iov, iovcnt, offset, write,
15981-
true, onfinish, bl, do_fsync,
15982-
syncdataonly);
16016+
retval = _preadv_pwritev_locked(fh, iov, iovcnt, offset, write, true,
16017+
onfinish, bl, do_fsync, syncdataonly);
1598316018
/* There are two scenarios with each having two cases to handle here
1598416019
1) async io
1598516020
1.a) r == 0:

src/client/Client.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,6 +1028,9 @@ class Client : public Dispatcher, public md_config_obs_t {
10281028
return it->second;
10291029
}
10301030
int get_fd_inode(int fd, InodeRef *in);
1031+
bool _ll_fh_exists(Fh *f) {
1032+
return ll_unclosed_fh_set.count(f);
1033+
}
10311034

10321035
// helpers
10331036
void wake_up_session_caps(MetaSession *s, bool reconnect);

src/test/client/nonblocking.cc

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -526,4 +526,88 @@ TEST_F(TestClient, LlreadvLlwritevZeroBytes) {
526526

527527
client->ll_release(fh);
528528
ASSERT_EQ(0, client->ll_unlink(root, filename, myperm));
529-
}
529+
}
530+
531+
TEST_F(TestClient, LlreadvLlwritevInvalidFileHandle) {
532+
/* Test provding null or invalid file handle returns an error
533+
as expected*/
534+
535+
Fh *fh_null = NULL;
536+
537+
char out_buf_0[] = "hello ";
538+
char out_buf_1[] = "world\n";
539+
struct iovec iov_out[2] = {
540+
{out_buf_0, sizeof(out_buf_0)},
541+
{out_buf_1, sizeof(out_buf_1)},
542+
};
543+
544+
char in_buf_0[sizeof(out_buf_0)];
545+
char in_buf_1[sizeof(out_buf_1)];
546+
struct iovec iov_in[2] = {
547+
{in_buf_0, sizeof(in_buf_0)},
548+
{in_buf_1, sizeof(in_buf_1)},
549+
};
550+
551+
std::unique_ptr<C_SaferCond> writefinish = nullptr;
552+
std::unique_ptr<C_SaferCond> readfinish = nullptr;
553+
554+
writefinish.reset(new C_SaferCond("test-nonblocking-writefinish-null-fh"));
555+
readfinish.reset(new C_SaferCond("test-nonblocking-readfinish-null-fh"));
556+
557+
int64_t rc;
558+
bufferlist bl;
559+
ssize_t bytes_written = 0, bytes_read = 0;
560+
561+
rc = client->ll_preadv_pwritev(fh_null, iov_out, 2, 0, true,
562+
writefinish.get(), nullptr);
563+
ASSERT_EQ(rc, 0);
564+
bytes_written = writefinish->wait();
565+
ASSERT_EQ(bytes_written, -CEPHFS_EBADF);
566+
567+
rc = client->ll_preadv_pwritev(fh_null, iov_in, 2, 0, false,
568+
readfinish.get(), &bl);
569+
ASSERT_EQ(rc, 0);
570+
bytes_read = readfinish->wait();
571+
ASSERT_EQ(bytes_read, -CEPHFS_EBADF);
572+
ASSERT_EQ(bl.length(), 0);
573+
574+
// test after closing the file handle
575+
int mypid = getpid();
576+
char filename[256];
577+
578+
client->unmount();
579+
TearDown();
580+
SetUp();
581+
582+
sprintf(filename, "test_llreadvllwritevinvalidfhfile%u", mypid);
583+
584+
Inode *root, *file;
585+
root = client->get_root();
586+
ASSERT_NE(root, (Inode *)NULL);
587+
588+
Fh *fh;
589+
struct ceph_statx stx;
590+
591+
ASSERT_EQ(0, client->ll_createx(root, filename, 0666,
592+
O_RDWR | O_CREAT | O_TRUNC,
593+
&file, &fh, &stx, 0, 0, myperm));
594+
595+
client->ll_release(fh);
596+
ASSERT_EQ(0, client->ll_unlink(root, filename, myperm));
597+
598+
writefinish.reset(new C_SaferCond("test-nonblocking-writefinish-invalid-fh"));
599+
readfinish.reset(new C_SaferCond("test-nonblocking-readfinish-invalid-fh"));
600+
601+
rc = client->ll_preadv_pwritev(fh, iov_out, 2, 0, true, writefinish.get(),
602+
nullptr);
603+
ASSERT_EQ(rc, 0);
604+
bytes_written = writefinish->wait();
605+
ASSERT_EQ(bytes_written, -CEPHFS_EBADF);
606+
607+
rc = client->ll_preadv_pwritev(fh, iov_in, 2, 0, false, readfinish.get(),
608+
&bl);
609+
ASSERT_EQ(rc, 0);
610+
bytes_read = readfinish->wait();
611+
ASSERT_EQ(bytes_read, -CEPHFS_EBADF);
612+
ASSERT_EQ(bl.length(), 0);
613+
}

0 commit comments

Comments
 (0)