From c7d197520c383314de6091c888a26e575ce972d5 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Fri, 6 Dec 2024 16:51:51 +0100 Subject: [PATCH] librbd/migration/HttpClient: avoid reusing ssl_stream after shut down ssl_stream objects can't be reused after shut down: despite a successful reconnect and handshake, any attempt to read or write fails with "end of stream" (beast.http:1) or "protocol is shutdown" (asio.ssl:337690831) error respectively. This doesn't appear to be documented, but Beast and ASIO authors both mention that the stream must be destroyed and recreated [1][2]. This was missed because the only integration test with a big enough image used http instead of https. [1] https://github.com/boostorg/beast/issues/821#issuecomment-338354949 [2] https://github.com/chriskohlhoff/asio/issues/804#issuecomment-872746894 Fixes: https://tracker.ceph.com/issues/69178 Signed-off-by: Ilya Dryomov (cherry picked from commit 20885b11794ba80d5cddd178994865a83da7240f) --- .../rbd/migration/6-prepare/qcow2-https.yaml | 8 ++++++++ src/librbd/migration/HttpClient.cc | 18 +++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 qa/suites/rbd/migration/6-prepare/qcow2-https.yaml diff --git a/qa/suites/rbd/migration/6-prepare/qcow2-https.yaml b/qa/suites/rbd/migration/6-prepare/qcow2-https.yaml new file mode 100644 index 0000000000000..d2072c41a68c7 --- /dev/null +++ b/qa/suites/rbd/migration/6-prepare/qcow2-https.yaml @@ -0,0 +1,8 @@ +tasks: + - exec: + client.0: + - mkdir /home/ubuntu/cephtest/migration + - qemu-img create -f qcow2 /home/ubuntu/cephtest/migration/empty.qcow2 1G + - echo '{"type":"qcow","stream":{"type":"http","url":"https://download.ceph.com/qa/ubuntu-12.04.qcow2"}}' | rbd migration prepare --import-only --source-spec-path - client.0.0 + - rbd migration prepare --import-only --source-spec '{"type":"qcow","stream":{"type":"file","file_path":"/home/ubuntu/cephtest/migration/empty.qcow2"}}' client.0.1 + - rbd migration prepare --import-only --source-spec '{"type":"qcow","stream":{"type":"file","file_path":"/home/ubuntu/cephtest/migration/empty.qcow2"}}' client.0.2 diff --git a/src/librbd/migration/HttpClient.cc b/src/librbd/migration/HttpClient.cc index dbe7a16416c64..5ad962485b1c5 100644 --- a/src/librbd/migration/HttpClient.cc +++ b/src/librbd/migration/HttpClient.cc @@ -187,6 +187,7 @@ protected: virtual void connect(boost::asio::ip::tcp::resolver::results_type results, Context* on_finish) = 0; virtual void disconnect(Context* on_finish) = 0; + virtual void reset_stream() = 0; void close_socket() { auto cct = m_http_client->m_cct; @@ -527,6 +528,7 @@ private: ceph_assert(next_state == STATE_RESET_CONNECTING); ceph_assert(on_finish == nullptr); shutdown_socket(); + reset_stream(); resolve_host(nullptr); return; } else if (current_state == STATE_RESET_CONNECTING) { @@ -612,9 +614,12 @@ protected: on_finish->complete(0); } + void reset_stream() override { + // no-op -- tcp_stream object can be reused after shut down + } + private: boost::beast::tcp_stream m_stream; - }; #undef dout_prefix @@ -668,6 +673,17 @@ protected: shutdown(r, on_finish); })); } + void reset_stream() override { + auto http_client = this->m_http_client; + auto cct = http_client->m_cct; + ldout(cct, 15) << dendl; + + // ssl_stream object can't be reused after shut down -- move-in + // a freshly constructed instance + m_stream = boost::beast::ssl_stream( + http_client->m_strand, http_client->m_ssl_context); + } + private: boost::beast::ssl_stream m_stream; bool m_ssl_enabled = false; -- 2.39.5