diff mbox series

[v2,4/6] libxc: use multicall for memory-op on Linux (and Solaris)

Message ID f56ceeaf-745b-9064-e6c1-83bdb0d04360@suse.com (mailing list archive)
State New, archived
Headers show
Series allow xc_domain_maximum_gpfn() to observe full GFN value | expand

Commit Message

Jan Beulich June 22, 2021, 3:19 p.m. UTC
Some sub-functions, XENMEM_maximum_gpfn and XENMEM_maximum_ram_page in
particular, can return values requiring more than 31 bits to represent.
Hence we cannot issue the hypercall directly when the return value of
ioctl() is used to propagate this value (note that this is not the case
for the BSDs, and MiniOS already wraps all hypercalls in a multicall).

Suggested-by: Jürgen Groß <jgross@suse.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Ian Jackson <iwj@xenproject.org>

Comments

Andrew Cooper June 22, 2021, 7:35 p.m. UTC | #1
On 22/06/2021 16:19, Jan Beulich wrote:
> Some sub-functions, XENMEM_maximum_gpfn and XENMEM_maximum_ram_page in
> particular, can return values requiring more than 31 bits to represent.
> Hence we cannot issue the hypercall directly when the return value of
> ioctl() is used to propagate this value (note that this is not the case
> for the BSDs, and MiniOS already wraps all hypercalls in a multicall).

It took me 3 readings to realise you weren't saying that BSDs used
multicall (which they don't).

Instead, I'd suggest rewording it.

"Some sub-functions, XENMEM_maximum_gpfn and XENMEM_maximum_ram_page in
particular, can return values requiring more than 31 bits to represent.

The BSDs deliberately avoid using the ioctl() return value, and MiniOS
already uses a multicall.  They aren't affected.

Linux and Solaris however do use the ioctl() return value, which must be
avoided in this case to avoid truncation."

Or something similar.

With a suitable improvement along these lines, Acked-by: Andrew Cooper
<andrew.cooper3@citrix.com>
diff mbox series

Patch

--- a/tools/libs/ctrl/xc_private.c
+++ b/tools/libs/ctrl/xc_private.c
@@ -337,8 +337,47 @@  long do_memory_op(xc_interface *xch, int
         goto out1;
     }
 
-    ret = xencall2(xch->xcall, __HYPERVISOR_memory_op,
-                   cmd, HYPERCALL_BUFFER_AS_ARG(arg));
+#if defined(__linux__) || defined(__sun__)
+    /*
+     * Some sub-ops return values which don't fit in "int". On platforms
+     * without a specific hypercall return value field in the privcmd
+     * interface structure, issue the request as a single-element multicall,
+     * to be able to capture the full return value.
+     */
+    if ( sizeof(long) > sizeof(int) )
+    {
+        multicall_entry_t multicall = {
+            .op = __HYPERVISOR_memory_op,
+            .args[0] = cmd,
+            .args[1] = HYPERCALL_BUFFER_AS_ARG(arg),
+        }, *call = &multicall;
+        DECLARE_HYPERCALL_BOUNCE(call, sizeof(*call),
+                                 XC_HYPERCALL_BUFFER_BOUNCE_BOTH);
+
+        if ( xc_hypercall_bounce_pre(xch, call) )
+        {
+            PERROR("Could not bounce buffer for memory_op hypercall");
+            goto out1;
+        }
+
+        ret = do_multicall_op(xch, HYPERCALL_BUFFER(call), 1);
+
+        xc_hypercall_bounce_post(xch, call);
+
+        if ( !ret )
+        {
+            ret = multicall.result;
+            if ( multicall.result > ~0xfffUL )
+            {
+                errno = -ret;
+                ret = -1;
+            }
+        }
+    }
+    else
+#endif
+        ret = xencall2L(xch->xcall, __HYPERVISOR_memory_op,
+                        cmd, HYPERCALL_BUFFER_AS_ARG(arg));
 
     xc_hypercall_bounce_post(xch, arg);
  out1: