]> xenbits.xensource.com Git - libvirt.git/commitdiff
rpc: message related sizes enlarged
authorDaniel Hansel <daniel.hansel@linux.vnet.ibm.com>
Tue, 7 May 2013 11:22:00 +0000 (13:22 +0200)
committerMichal Privoznik <mprivozn@redhat.com>
Tue, 7 May 2013 11:29:58 +0000 (13:29 +0200)
We have seen an issue on s390x platform where domain XMLs larger than 1MB
were used. The define command was finished successfully. The dumpxml command
was not successful (i.e. could not encode message payload).

Enlarged message related sizes (e.g. maximum string size, message size, etc.)
to handle larger system configurations used on s390x platform.

To improve handling of the RPC message size the allocation during encode process
is changed to a dynamic one (i.e. starting with 64kB initial size and increasing
that size in steps up to 16MB if the payload data is larger).

Signed-off-by: Daniel Hansel <daniel.hansel@linux.vnet.ibm.com>
Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com>
src/libvirt.c
src/remote/remote_protocol.x
src/rpc/virnetmessage.c
src/rpc/virnetmessage.h
src/rpc/virnetprotocol.x
tests/virnetmessagetest.c

index 467f6dde45df3734dd12c379bb538c32d949fb07..33a441994167433c0d8f81dd49e477cb0f586f30 100644 (file)
@@ -7786,6 +7786,8 @@ error:
  * For your program to be able to work reliably over a remote
  * connection you should split large requests to <= 65536 bytes.
  * However, with 0.9.13 this RPC limit has been raised to 1M byte.
+ * Starting with version 1.0.6 the RPC limit has been raised again.
+ * Now large requests up to 16M byte are supported.
  *
  * Returns: 0 in case of success or -1 in case of failure.
  */
@@ -7936,6 +7938,8 @@ error:
  * For your program to be able to work reliably over a remote
  * connection you should split large requests to <= 65536 bytes.
  * However, with 0.9.13 this RPC limit has been raised to 1M byte.
+ * Starting with version 1.0.6 the RPC limit has been raised again.
+ * Now large requests up to 16M byte are supported.
  *
  * Returns: 0 in case of success or -1 in case of failure.
  */
index 512ba2e292acaa668fcd9f4fbb3e0904ef2c6d09..f61d10c0cdaae382b1e1c20ee33c0f4dfef02d2c 100644 (file)
@@ -65,7 +65,7 @@
  * This is an arbitrary limit designed to stop the decoder from trying
  * to allocate unbounded amounts of memory when fed with a bad message.
  */
-const REMOTE_STRING_MAX = 1048576;
+const REMOTE_STRING_MAX = 4194304;
 
 /* A long string, which may NOT be NULL. */
 typedef string remote_nonnull_string<REMOTE_STRING_MAX>;
@@ -160,13 +160,13 @@ const REMOTE_DOMAIN_SNAPSHOT_LIST_NAMES_MAX = 1024;
  * Note applications need to be aware of this limit and issue multiple
  * requests for large amounts of data.
  */
-const REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX = 1048576;
+const REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX = 4194304;
 
 /* Maximum length of a memory peek buffer message.
  * Note applications need to be aware of this limit and issue multiple
  * requests for large amounts of data.
  */
-const REMOTE_DOMAIN_MEMORY_PEEK_BUFFER_MAX = 1048576;
+const REMOTE_DOMAIN_MEMORY_PEEK_BUFFER_MAX = 4194304;
 
 /*
  * Maximum length of a security label list.
index 647fef7be431cadeb6a662a861164a1fa1b7bde1..b2c6e5b02aa5413df8285add14322033c3f2008c 100644 (file)
@@ -221,7 +221,7 @@ int virNetMessageEncodeHeader(virNetMessagePtr msg)
     int ret = -1;
     unsigned int len = 0;
 
-    msg->bufferLength = VIR_NET_MESSAGE_MAX + VIR_NET_MESSAGE_LEN_MAX;
+    msg->bufferLength = VIR_NET_MESSAGE_INITIAL + VIR_NET_MESSAGE_LEN_MAX;
     if (VIR_REALLOC_N(msg->buffer, msg->bufferLength) < 0) {
         virReportOOMError();
         return ret;
@@ -351,9 +351,27 @@ int virNetMessageEncodePayload(virNetMessagePtr msg,
     xdrmem_create(&xdr, msg->buffer + msg->bufferOffset,
                   msg->bufferLength - msg->bufferOffset, XDR_ENCODE);
 
-    if (!(*filter)(&xdr, data)) {
-        virReportError(VIR_ERR_RPC, "%s", _("Unable to encode message payload"));
-        goto error;
+    /* Try to encode the payload. If the buffer is too small increase it. */
+    while (!(*filter)(&xdr, data)) {
+        if ((msg->bufferLength - VIR_NET_MESSAGE_LEN_MAX) * 4 > VIR_NET_MESSAGE_MAX) {
+            virReportError(VIR_ERR_RPC, "%s", _("Unable to encode message payload"));
+            goto error;
+        }
+
+        xdr_destroy(&xdr);
+
+        msg->bufferLength = (msg->bufferLength - VIR_NET_MESSAGE_LEN_MAX) * 4 +
+            VIR_NET_MESSAGE_LEN_MAX;
+
+        if (VIR_REALLOC_N(msg->buffer, msg->bufferLength) < 0) {
+            virReportOOMError();
+            goto error;
+        }
+
+        xdrmem_create(&xdr, msg->buffer + msg->bufferOffset,
+                      msg->bufferLength - msg->bufferOffset, XDR_ENCODE);
+
+        VIR_DEBUG("Increased message buffer length = %zu", msg->bufferLength);
     }
 
     /* Get the length stored in buffer. */
@@ -415,11 +433,23 @@ int virNetMessageEncodePayloadRaw(virNetMessagePtr msg,
     XDR xdr;
     unsigned int msglen;
 
+    /* If the message buffer is too small for the payload increase it accordingly. */
     if ((msg->bufferLength - msg->bufferOffset) < len) {
-        virReportError(VIR_ERR_RPC,
-                    _("Stream data too long to send (%zu bytes needed, %zu bytes available)"),
-                    len, (msg->bufferLength - msg->bufferOffset));
-        return -1;
+        if ((msg->bufferOffset + len) > VIR_NET_MESSAGE_MAX) {
+            virReportError(VIR_ERR_RPC,
+                           _("Stream data too long to send (%zu bytes needed, %zu bytes available)"),
+                           len, (VIR_NET_MESSAGE_MAX - msg->bufferOffset));
+            return -1;
+        }
+
+        msg->bufferLength = msg->bufferOffset + len;
+
+        if (VIR_REALLOC_N(msg->buffer, msg->bufferLength) < 0) {
+            virReportOOMError();
+            return -1;
+        }
+
+        VIR_DEBUG("Increased message buffer length = %zu", msg->bufferLength);
     }
 
     memcpy(msg->buffer + msg->bufferOffset, data, len);
index dfa1c6ca87c2c94ff1f145732ad168e89ba6bbae..c94dddc2591c820afc7d79ded67da1a14f46d926 100644 (file)
@@ -34,7 +34,8 @@ typedef void (*virNetMessageFreeCallback)(virNetMessagePtr msg, void *opaque);
 struct _virNetMessage {
     bool tracked;
 
-    char *buffer; /* Typically VIR_NET_MESSAGE_MAX + VIR_NET_MESSAGE_LEN_MAX */
+    char *buffer; /* Initially VIR_NET_MESSAGE_INITIAL + VIR_NET_MESSAGE_LEN_MAX */
+                  /* Maximum   VIR_NET_MESSAGE_MAX     + VIR_NET_MESSAGE_LEN_MAX */
     size_t bufferLength;
     size_t bufferOffset;
 
index eb2e81d7d481beaefadf1ab00fb8df8a3e359929..131e40b1c3fefc2704ba9b6a01655365f31ad113 100644 (file)
 
 /*----- Data types. -----*/
 
+/* Initial message size.
+ * When the message payload is larger this initial size will be
+ * quadrupled until the maximum total message size is reached.
+ */
+const VIR_NET_MESSAGE_INITIAL = 65536;
+
 /* Maximum total message size (serialised). */
-const VIR_NET_MESSAGE_MAX = 4194304;
+const VIR_NET_MESSAGE_MAX = 16777216;
 
 /* Size of struct virNetMessageHeader (serialised)*/
 const VIR_NET_MESSAGE_HEADER_MAX = 24;
 
 /* Size of message payload */
-const VIR_NET_MESSAGE_PAYLOAD_MAX = 4194280;
+const VIR_NET_MESSAGE_PAYLOAD_MAX = 16777192;
 
-/* Size of message length field. Not counted in VIR_NET_MESSAGE_MAX */
+/* Size of message length field. Not counted in VIR_NET_MESSAGE_MAX
+ * and VIR_NET_MESSAGE_INITIAL.
+ */
 const VIR_NET_MESSAGE_LEN_MAX = 4;
 
 /* Length of long, but not unbounded, strings.
  * This is an arbitrary limit designed to stop the decoder from trying
  * to allocate unbounded amounts of memory when fed with a bad message.
  */
-const VIR_NET_MESSAGE_STRING_MAX = 1048576;
+const VIR_NET_MESSAGE_STRING_MAX = 4194304;
 
 /* Limit on number of File Descriptors allowed to be
  * passed per message
index 96defe420f07d0fbb10ed5569b18f74afaf2dba0..fabeffd19b24b7607e56a2220460bc0870d703b5 100644 (file)
@@ -46,7 +46,7 @@ static int testMessageHeaderEncode(const void *args ATTRIBUTE_UNUSED)
     };
     /* According to doc to virNetMessageEncodeHeader(&msg):
      * msg->buffer will be this long */
-    unsigned long msg_buf_size = VIR_NET_MESSAGE_MAX + VIR_NET_MESSAGE_LEN_MAX;
+    unsigned long msg_buf_size = VIR_NET_MESSAGE_INITIAL + VIR_NET_MESSAGE_LEN_MAX;
     int ret = -1;
 
     if (!msg) {