rgw: fix memory fragmentation problem reading data from client. 21098/head
authorMarcus Watts <mwatts@redhat.com>
Mon, 5 Mar 2018 21:10:29 +0000 (16:10 -0500)
committerNathan Cutler <ncutler@suse.com>
Fri, 6 Apr 2018 14:49:58 +0000 (16:49 +0200)
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 <mwatts@redhat.com>
(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
src/rgw/rgw_civetweb.h

index e20f074795bbb7f7009493c5d8bcae6c8bf5a21d..25ba4957f798335cca01c7aa2993207975d5e94d 100644 (file)
@@ -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()
index f8a7cb5756e0cbfb1a0aee1346f4c02ec0b790b9..bdcd6d3957b46eff21a9dab1928a98c43b9bb2da 100644 (file)
@@ -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;