Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

virt: vbox: Add support for the new VBG_IOCTL_ACQUIRE_GUEST_CAPABILITIES ioctl

Add support for the new VBG_IOCTL_ACQUIRE_GUEST_CAPABILITIES ioctl, this
is necessary for automatic resizing of the guest resolution to match the
VM-window size to work with the new VMSVGA virtual GPU which is now the
new default in VirtualBox.

BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1789545
Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Link: https://lore.kernel.org/r/20200709120858.63928-6-hdegoede@redhat.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Hans de Goede and committed by
Greg Kroah-Hartman
631beddc 412f84cf

+200 -1
+162 -1
drivers/virt/vboxguest/vboxguest_core.c
··· 679 679 680 680 WARN_ON(!mutex_is_locked(&gdev->session_mutex)); 681 681 682 - caps = gdev->set_guest_caps_tracker.mask; 682 + caps = gdev->acquired_guest_caps | gdev->set_guest_caps_tracker.mask; 683 683 684 684 if (gdev->guest_caps_host == caps) 685 685 return 0; ··· 704 704 } 705 705 706 706 /** 707 + * Acquire (get exclusive access) guest capabilities for a session. 708 + * Takes the session mutex. 709 + * Return: 0 or negative errno value. 710 + * @gdev: The Guest extension device. 711 + * @session: The session. 712 + * @flags: Flags (VBGL_IOC_AGC_FLAGS_XXX). 713 + * @or_mask: The capabilities to add. 714 + * @not_mask: The capabilities to remove. 715 + * @session_termination: Set if we're called by the session cleanup code. 716 + * This tweaks the error handling so we perform 717 + * proper session cleanup even if the host 718 + * misbehaves. 719 + */ 720 + static int vbg_acquire_session_capabilities(struct vbg_dev *gdev, 721 + struct vbg_session *session, 722 + u32 or_mask, u32 not_mask, 723 + u32 flags, bool session_termination) 724 + { 725 + unsigned long irqflags; 726 + bool wakeup = false; 727 + int ret = 0; 728 + 729 + mutex_lock(&gdev->session_mutex); 730 + 731 + if (gdev->set_guest_caps_tracker.mask & or_mask) { 732 + vbg_err("%s error: cannot acquire caps which are currently set\n", 733 + __func__); 734 + ret = -EINVAL; 735 + goto out; 736 + } 737 + 738 + /* 739 + * Mark any caps in the or_mask as now being in acquire-mode. Note 740 + * once caps are in acquire_mode they always stay in this mode. 741 + * This impacts event handling, so we take the event-lock. 742 + */ 743 + spin_lock_irqsave(&gdev->event_spinlock, irqflags); 744 + gdev->acquire_mode_guest_caps |= or_mask; 745 + spin_unlock_irqrestore(&gdev->event_spinlock, irqflags); 746 + 747 + /* If we only have to switch the caps to acquire mode, we're done. */ 748 + if (flags & VBGL_IOC_AGC_FLAGS_CONFIG_ACQUIRE_MODE) 749 + goto out; 750 + 751 + not_mask &= ~or_mask; /* or_mask takes priority over not_mask */ 752 + not_mask &= session->acquired_guest_caps; 753 + or_mask &= ~session->acquired_guest_caps; 754 + 755 + if (or_mask == 0 && not_mask == 0) 756 + goto out; 757 + 758 + if (gdev->acquired_guest_caps & or_mask) { 759 + ret = -EBUSY; 760 + goto out; 761 + } 762 + 763 + gdev->acquired_guest_caps |= or_mask; 764 + gdev->acquired_guest_caps &= ~not_mask; 765 + /* session->acquired_guest_caps impacts event handling, take the lock */ 766 + spin_lock_irqsave(&gdev->event_spinlock, irqflags); 767 + session->acquired_guest_caps |= or_mask; 768 + session->acquired_guest_caps &= ~not_mask; 769 + spin_unlock_irqrestore(&gdev->event_spinlock, irqflags); 770 + 771 + ret = vbg_set_host_capabilities(gdev, session, session_termination); 772 + /* Roll back on failure, unless it's session termination time. */ 773 + if (ret < 0 && !session_termination) { 774 + gdev->acquired_guest_caps &= ~or_mask; 775 + gdev->acquired_guest_caps |= not_mask; 776 + spin_lock_irqsave(&gdev->event_spinlock, irqflags); 777 + session->acquired_guest_caps &= ~or_mask; 778 + session->acquired_guest_caps |= not_mask; 779 + spin_unlock_irqrestore(&gdev->event_spinlock, irqflags); 780 + } 781 + 782 + /* 783 + * If we added a capability, check if that means some other thread in 784 + * our session should be unblocked because there are events pending 785 + * (the result of vbg_get_allowed_event_mask_for_session() may change). 786 + * 787 + * HACK ALERT! When the seamless support capability is added we generate 788 + * a seamless change event so that the ring-3 client can sync with 789 + * the seamless state. 790 + */ 791 + if (ret == 0 && or_mask != 0) { 792 + spin_lock_irqsave(&gdev->event_spinlock, irqflags); 793 + 794 + if (or_mask & VMMDEV_GUEST_SUPPORTS_SEAMLESS) 795 + gdev->pending_events |= 796 + VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST; 797 + 798 + if (gdev->pending_events) 799 + wakeup = true; 800 + 801 + spin_unlock_irqrestore(&gdev->event_spinlock, irqflags); 802 + 803 + if (wakeup) 804 + wake_up(&gdev->event_wq); 805 + } 806 + 807 + out: 808 + mutex_unlock(&gdev->session_mutex); 809 + 810 + return ret; 811 + } 812 + 813 + /** 707 814 * Sets the guest capabilities for a session. Takes the session spinlock. 708 815 * Return: 0 or negative errno value. 709 816 * @gdev: The Guest extension device. ··· 831 724 int ret = 0; 832 725 833 726 mutex_lock(&gdev->session_mutex); 727 + 728 + if (gdev->acquire_mode_guest_caps & or_mask) { 729 + vbg_err("%s error: cannot set caps which are in acquire_mode\n", 730 + __func__); 731 + ret = -EBUSY; 732 + goto out; 733 + } 834 734 835 735 /* Apply the changes to the session mask. */ 836 736 previous = session->set_guest_caps; ··· 1076 962 struct vbg_dev *gdev = session->gdev; 1077 963 int i, rc; 1078 964 965 + vbg_acquire_session_capabilities(gdev, session, 0, U32_MAX, 0, true); 1079 966 vbg_set_session_capabilities(gdev, session, 0, U32_MAX, true); 1080 967 vbg_set_session_event_filter(gdev, session, 0, U32_MAX, true); 1081 968 ··· 1134 1019 return 0; 1135 1020 } 1136 1021 1022 + /* Must be called with the event_lock held */ 1023 + static u32 vbg_get_allowed_event_mask_for_session(struct vbg_dev *gdev, 1024 + struct vbg_session *session) 1025 + { 1026 + u32 acquire_mode_caps = gdev->acquire_mode_guest_caps; 1027 + u32 session_acquired_caps = session->acquired_guest_caps; 1028 + u32 allowed_events = VMMDEV_EVENT_VALID_EVENT_MASK; 1029 + 1030 + if ((acquire_mode_caps & VMMDEV_GUEST_SUPPORTS_GRAPHICS) && 1031 + !(session_acquired_caps & VMMDEV_GUEST_SUPPORTS_GRAPHICS)) 1032 + allowed_events &= ~VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST; 1033 + 1034 + if ((acquire_mode_caps & VMMDEV_GUEST_SUPPORTS_SEAMLESS) && 1035 + !(session_acquired_caps & VMMDEV_GUEST_SUPPORTS_SEAMLESS)) 1036 + allowed_events &= ~VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST; 1037 + 1038 + return allowed_events; 1039 + } 1040 + 1137 1041 static bool vbg_wait_event_cond(struct vbg_dev *gdev, 1138 1042 struct vbg_session *session, 1139 1043 u32 event_mask) ··· 1164 1030 spin_lock_irqsave(&gdev->event_spinlock, flags); 1165 1031 1166 1032 events = gdev->pending_events & event_mask; 1033 + events &= vbg_get_allowed_event_mask_for_session(gdev, session); 1167 1034 wakeup = events || session->cancel_waiters; 1168 1035 1169 1036 spin_unlock_irqrestore(&gdev->event_spinlock, flags); ··· 1179 1044 { 1180 1045 u32 events = gdev->pending_events & event_mask; 1181 1046 1047 + events &= vbg_get_allowed_event_mask_for_session(gdev, session); 1182 1048 gdev->pending_events &= ~events; 1183 1049 return events; 1184 1050 } ··· 1581 1445 false); 1582 1446 } 1583 1447 1448 + static int vbg_ioctl_acquire_guest_capabilities(struct vbg_dev *gdev, 1449 + struct vbg_session *session, 1450 + struct vbg_ioctl_acquire_guest_caps *caps) 1451 + { 1452 + u32 flags, or_mask, not_mask; 1453 + 1454 + if (vbg_ioctl_chk(&caps->hdr, sizeof(caps->u.in), 0)) 1455 + return -EINVAL; 1456 + 1457 + flags = caps->u.in.flags; 1458 + or_mask = caps->u.in.or_mask; 1459 + not_mask = caps->u.in.not_mask; 1460 + 1461 + if (flags & ~VBGL_IOC_AGC_FLAGS_VALID_MASK) 1462 + return -EINVAL; 1463 + 1464 + if ((or_mask | not_mask) & ~VMMDEV_GUEST_CAPABILITIES_MASK) 1465 + return -EINVAL; 1466 + 1467 + return vbg_acquire_session_capabilities(gdev, session, or_mask, 1468 + not_mask, flags, false); 1469 + } 1470 + 1584 1471 static int vbg_ioctl_change_guest_capabilities(struct vbg_dev *gdev, 1585 1472 struct vbg_session *session, struct vbg_ioctl_set_guest_caps *caps) 1586 1473 { ··· 1713 1554 return vbg_ioctl_interrupt_all_wait_events(gdev, session, data); 1714 1555 case VBG_IOCTL_CHANGE_FILTER_MASK: 1715 1556 return vbg_ioctl_change_filter_mask(gdev, session, data); 1557 + case VBG_IOCTL_ACQUIRE_GUEST_CAPABILITIES: 1558 + return vbg_ioctl_acquire_guest_capabilities(gdev, session, data); 1716 1559 case VBG_IOCTL_CHANGE_GUEST_CAPABILITIES: 1717 1560 return vbg_ioctl_change_guest_capabilities(gdev, session, data); 1718 1561 case VBG_IOCTL_CHECK_BALLOON:
+14
drivers/virt/vboxguest/vboxguest_core.h
··· 118 118 u32 event_filter_host; 119 119 120 120 /** 121 + * Guest capabilities which have been switched to acquire_mode. 122 + */ 123 + u32 acquire_mode_guest_caps; 124 + /** 125 + * Guest capabilities acquired by vbg_acquire_session_capabilities(). 126 + * Only one session can acquire a capability at a time. 127 + */ 128 + u32 acquired_guest_caps; 129 + /** 121 130 * Usage counters for guest capabilities requested through 122 131 * vbg_set_session_capabilities(). Indexed by capability bit 123 132 * number, one count per session using a capability. ··· 173 164 * host filter. Protected by vbg_gdev.session_mutex. 174 165 */ 175 166 u32 event_filter; 167 + /** 168 + * Guest capabilities acquired by vbg_acquire_session_capabilities(). 169 + * Only one session can acquire a capability at a time. 170 + */ 171 + u32 acquired_guest_caps; 176 172 /** 177 173 * Guest capabilities set through vbg_set_session_capabilities(). 178 174 * A capability claimed by any guest session will be reported to the
+24
include/uapi/linux/vboxguest.h
··· 257 257 _IOWR('V', 12, struct vbg_ioctl_change_filter) 258 258 259 259 260 + /** VBG_IOCTL_ACQUIRE_GUEST_CAPABILITIES data structure. */ 261 + struct vbg_ioctl_acquire_guest_caps { 262 + /** The header. */ 263 + struct vbg_ioctl_hdr hdr; 264 + union { 265 + struct { 266 + /** Flags (VBGL_IOC_AGC_FLAGS_XXX). */ 267 + __u32 flags; 268 + /** Capabilities to set (VMMDEV_GUEST_SUPPORTS_XXX). */ 269 + __u32 or_mask; 270 + /** Capabilities to drop (VMMDEV_GUEST_SUPPORTS_XXX). */ 271 + __u32 not_mask; 272 + } in; 273 + } u; 274 + }; 275 + VMMDEV_ASSERT_SIZE(vbg_ioctl_acquire_guest_caps, 24 + 12); 276 + 277 + #define VBGL_IOC_AGC_FLAGS_CONFIG_ACQUIRE_MODE 0x00000001 278 + #define VBGL_IOC_AGC_FLAGS_VALID_MASK 0x00000001 279 + 280 + #define VBG_IOCTL_ACQUIRE_GUEST_CAPABILITIES \ 281 + _IOWR('V', 13, struct vbg_ioctl_acquire_guest_caps) 282 + 283 + 260 284 /** VBG_IOCTL_CHANGE_GUEST_CAPABILITIES data structure. */ 261 285 struct vbg_ioctl_set_guest_caps { 262 286 /** The header. */