c1d5388
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
c1d5388
From: Hans de Goede <hdegoede@redhat.com>
c1d5388
Date: Tue, 19 May 2020 15:30:29 +0200
c1d5388
Subject: [PATCH] virt: vbox: Add vbg_set_host_capabilities() helper function
c1d5388
c1d5388
Add vbg_set_host_capabilities() helper function,  this is a preparation
c1d5388
patch for adding support for the VBGL_IOCTL_GUEST_CAPS_ACQUIRE ioctl.
c1d5388
c1d5388
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
c1d5388
Upstream Status: https://lore.kernel.org/lkml/20200520195440.38759-1-hdegoede@redhat.com/
c1d5388
---
c1d5388
 drivers/virt/vboxguest/vboxguest_core.c | 79 ++++++++++++++-----------
c1d5388
 1 file changed, 46 insertions(+), 33 deletions(-)
c1d5388
c1d5388
diff --git a/drivers/virt/vboxguest/vboxguest_core.c b/drivers/virt/vboxguest/vboxguest_core.c
c1d5388
index aee5eff229f2..15b3cb618c6e 100644
c1d5388
--- a/drivers/virt/vboxguest/vboxguest_core.c
c1d5388
+++ b/drivers/virt/vboxguest/vboxguest_core.c
c1d5388
@@ -661,6 +661,48 @@ static int vbg_reset_host_capabilities(struct vbg_dev *gdev)
c1d5388
 	return vbg_status_code_to_errno(rc);
c1d5388
 }
c1d5388
c1d5388
+/**
c1d5388
+ * Set guest capabilities on the host.
c1d5388
+ * Must be called with gdev->session_mutex hold.
c1d5388
+ * Return: 0 or negative errno value.
c1d5388
+ * @gdev:			The Guest extension device.
c1d5388
+ * @session:			The session.
c1d5388
+ * @session_termination:	Set if we're called by the session cleanup code.
c1d5388
+ */
c1d5388
+static int vbg_set_host_capabilities(struct vbg_dev *gdev,
c1d5388
+				     struct vbg_session *session,
c1d5388
+				     bool session_termination)
c1d5388
+{
c1d5388
+	struct vmmdev_mask *req;
c1d5388
+	u32 caps;
c1d5388
+	int rc;
c1d5388
+
c1d5388
+	WARN_ON(!mutex_is_locked(&gdev->session_mutex));
c1d5388
+
c1d5388
+	caps = gdev->set_guest_caps_tracker.mask;
c1d5388
+
c1d5388
+	if (gdev->guest_caps_host == caps)
c1d5388
+		return 0;
c1d5388
+
c1d5388
+	/* On termination the requestor is the kernel, as we're cleaning up. */
c1d5388
+	req = vbg_req_alloc(sizeof(*req), VMMDEVREQ_SET_GUEST_CAPABILITIES,
c1d5388
+			    session_termination ? VBG_KERNEL_REQUEST :
c1d5388
+						  session->requestor);
c1d5388
+	if (!req) {
c1d5388
+		gdev->guest_caps_host = U32_MAX;
c1d5388
+		return -ENOMEM;
c1d5388
+	}
c1d5388
+
c1d5388
+	req->or_mask = caps;
c1d5388
+	req->not_mask = ~caps;
c1d5388
+	rc = vbg_req_perform(gdev, req);
c1d5388
+	vbg_req_free(req, sizeof(*req));
c1d5388
+
c1d5388
+	gdev->guest_caps_host = (rc >= 0) ? caps : U32_MAX;
c1d5388
+
c1d5388
+	return vbg_status_code_to_errno(rc);
c1d5388
+}
c1d5388
+
c1d5388
 /**
c1d5388
  * Sets the guest capabilities for a session. Takes the session spinlock.
c1d5388
  * Return: 0 or negative errno value.
c1d5388
@@ -678,23 +720,8 @@ static int vbg_set_session_capabilities(struct vbg_dev *gdev,
c1d5388
 					u32 or_mask, u32 not_mask,
c1d5388
 					bool session_termination)
c1d5388
 {
c1d5388
-	struct vmmdev_mask *req;
c1d5388
 	u32 changed, previous;
c1d5388
-	int rc, ret = 0;
c1d5388
-
c1d5388
-	/*
c1d5388
-	 * Allocate a request buffer before taking the spinlock, when
c1d5388
-	 * the session is being terminated the requestor is the kernel,
c1d5388
-	 * as we're cleaning up.
c1d5388
-	 */
c1d5388
-	req = vbg_req_alloc(sizeof(*req), VMMDEVREQ_SET_GUEST_CAPABILITIES,
c1d5388
-			    session_termination ? VBG_KERNEL_REQUEST :
c1d5388
-						  session->requestor);
c1d5388
-	if (!req) {
c1d5388
-		if (!session_termination)
c1d5388
-			return -ENOMEM;
c1d5388
-		/* Ignore allocation failure, we must do session cleanup. */
c1d5388
-	}
c1d5388
+	int ret = 0;
c1d5388
c1d5388
 	mutex_lock(&gdev->session_mutex);
c1d5388
c1d5388
@@ -709,23 +736,10 @@ static int vbg_set_session_capabilities(struct vbg_dev *gdev,
c1d5388
 		goto out;
c1d5388
c1d5388
 	vbg_track_bit_usage(&gdev->set_guest_caps_tracker, changed, previous);
c1d5388
-	or_mask = gdev->set_guest_caps_tracker.mask;
c1d5388
-
c1d5388
-	if (gdev->guest_caps_host == or_mask || !req)
c1d5388
-		goto out;
c1d5388
-
c1d5388
-	gdev->guest_caps_host = or_mask;
c1d5388
-	req->or_mask = or_mask;
c1d5388
-	req->not_mask = ~or_mask;
c1d5388
-	rc = vbg_req_perform(gdev, req);
c1d5388
-	if (rc < 0) {
c1d5388
-		ret = vbg_status_code_to_errno(rc);
c1d5388
-
c1d5388
-		/* Failed, roll back (unless it's session termination time). */
c1d5388
-		gdev->guest_caps_host = U32_MAX;
c1d5388
-		if (session_termination)
c1d5388
-			goto out;
c1d5388
c1d5388
+	ret = vbg_set_host_capabilities(gdev, session, session_termination);
c1d5388
+	/* Roll back on failure, unless it's session termination time. */
c1d5388
+	if (ret < 0 && !session_termination) {
c1d5388
 		vbg_track_bit_usage(&gdev->set_guest_caps_tracker, changed,
c1d5388
 				    session->set_guest_caps);
c1d5388
 		session->set_guest_caps = previous;
c1d5388
@@ -733,7 +747,6 @@ static int vbg_set_session_capabilities(struct vbg_dev *gdev,
c1d5388
c1d5388
 out:
c1d5388
 	mutex_unlock(&gdev->session_mutex);
c1d5388
-	vbg_req_free(req, sizeof(*req));
c1d5388
c1d5388
 	return ret;
c1d5388
 }
c1d5388
-- 
c1d5388
2.26.2
c1d5388