From 82e57cfb69f80b3f0c114e51fb88d5fed70e1f4b Mon Sep 17 00:00:00 2001 From: Marcus Watts Date: Mon, 5 Mar 2018 16:10:29 -0500 Subject: [PATCH] rgw: fix memory fragmentation problem reading data from client. mg_read returns 0 on EOF. In some versions of civetweb, mg_read can return "short" reads. The logic in the rest of ceph depends on a read always filling its buffer when possible. So loop here and fill the buffer. Looping to fill the buffer means we must also track when mg_read returns EOF, because after that further calls to mg_read will return -1. Fixes: https://tracker.ceph.com/issues/23207 Signed-off-by: Marcus Watts (cherry picked from commit d9a150b1f1f9ec3952555186722c9b13d7448e2d) Conflicts: src/rgw/rgw_civetweb.cc: - master RGWCivetWeb::RGWCivetWeb() becomes RGWMongoose::RGWMongoose() in jewel, with slightly different initializer list; adapt mg_read() call for jewel - master RGWCivetWeb::read_data() becomes RGWMongoose::read_data() in jewel, and inside this function we return -EIO in jewel, instead of throwing an exception --- src/rgw/rgw_civetweb.cc | 20 +++++++++++++++++--- src/rgw/rgw_civetweb.h | 1 + 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/rgw/rgw_civetweb.cc b/src/rgw/rgw_civetweb.cc index e20f074795bbb..25ba4957f7983 100644 --- a/src/rgw/rgw_civetweb.cc +++ b/src/rgw/rgw_civetweb.cc @@ -32,7 +32,8 @@ int RGWMongoose::write_data(const char *buf, int len) RGWMongoose::RGWMongoose(mg_connection *_conn) : conn(_conn), status_num(0), header_done(false), sent_header(false), has_content_length(false), - explicit_keepalive(false), explicit_conn_close(false) + explicit_keepalive(false), explicit_conn_close(false), + got_eof_on_read(false) { sockaddr *lsa = mg_get_local_addr(conn); switch(lsa->sa_family) { @@ -49,8 +50,21 @@ RGWMongoose::RGWMongoose(mg_connection *_conn) int RGWMongoose::read_data(char *buf, int len) { - const int ret = mg_read(conn, buf, len); - return (ret >= 0) ? ret : -EIO; + int c, ret; + if (got_eof_on_read) { + return 0; + } + for (c = 0; c < len; c += ret) { + ret = mg_read(conn, buf+c, len-c); + if (ret < 0) { + return -EIO; + } + if (!ret) { + got_eof_on_read = true; + break; + } + } + return c; } void RGWMongoose::flush() diff --git a/src/rgw/rgw_civetweb.h b/src/rgw/rgw_civetweb.h index f8a7cb5756e0c..bdcd6d3957b46 100644 --- a/src/rgw/rgw_civetweb.h +++ b/src/rgw/rgw_civetweb.h @@ -25,6 +25,7 @@ class RGWMongoose : public RGWStreamIO bool has_content_length; bool explicit_keepalive; bool explicit_conn_close; + bool got_eof_on_read; public: int init_env(CephContext *cct) override; -- 2.39.5