public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Dominik Budzowski <dominik@budzowski.pl>
To: pve-devel@lists.proxmox.com
Cc: Dominik Budzowski <dominik@budzowski.pl>
Subject: [PATCH pve-manager v2] ui: qemu: HDEdit: add iothread-vq-mapping support
Date: Fri,  5 Jun 2026 18:05:58 +0200	[thread overview]
Message-ID: <20260605160558.15783-1-dominik@budzowski.pl> (raw)

Replace the 'IO thread' checkbox with a proxmoxKVComboBox offering three
mutually exclusive modes:
  - disabled    (no iothread, default)
  - IO thread   (classic single iothread)
  - VQ mapping  (pool of N iothreads via iothread-vq-mapping)

A 'VQ count' spinner (2-16, default 2) appears only when 'VQ mapping' is
selected, keeping the panel compact otherwise.

In create/wizard mode the selector auto-defaults to 'IO thread' for virtio
and virtio-scsi-single controllers via a ViewModel formula, preserving the
previous checkbox behaviour.

Resolves: https://bugzilla.proxmox.com/show_bug.cgi?id=6350
Signed-off-by: Dominik Budzowski <dominik@budzowski.pl>
---
Changes in v2:
 - Replace two mutually exclusive checkboxes (IO thread + VQ Mapping) with
   a single proxmoxKVComboBox, following the pattern of Cache/AIO selectors
 - VQ count field is now hidden (not just disabled) when VQ mapping is not
   selected, reducing visual clutter
 - Default VQ count changed from 4 to 2
 - Fix label capitalisation: 'IO thread', 'VQ mapping' (lowercase)

 www/manager6/qemu/HDEdit.js | 58 ++++++++++++++++++++++++++++++++-----
 1 file changed, 50 insertions(+), 8 deletions(-)

diff --git a/www/manager6/qemu/HDEdit.js b/www/manager6/qemu/HDEdit.js
index 1bb2bfd..b1c2220 100644
--- a/www/manager6/qemu/HDEdit.js
+++ b/www/manager6/qemu/HDEdit.js
@@ -19,6 +19,10 @@ Ext.define('PVE.qemu.HDInputPanel', {
             isVirtIO: false,
             isSCSISingle: false,
         },
+        formulas: {
+            defaultIothreadMode: get =>
+                (get('isVirtIO') || (get('isSCSI') && get('isSCSISingle'))) ? 'iothread' : '__default__',
+        },
     },
 
     controller: {
@@ -92,7 +96,14 @@ Ext.define('PVE.qemu.HDInputPanel', {
         PVE.Utils.propertyStringSet(me.drive, values.noreplicate, 'replicate', 'no');
         PVE.Utils.propertyStringSet(me.drive, values.discard, 'discard', 'on');
         PVE.Utils.propertyStringSet(me.drive, values.ssd, 'ssd', 'on');
-        PVE.Utils.propertyStringSet(me.drive, values.iothread, 'iothread', 'on');
+        let iothreadCombo = me.down('[name=iothread_mode]');
+        let iothreadMode = (iothreadCombo && !iothreadCombo.disabled) ? values.iothread_mode : '__default__';
+        PVE.Utils.propertyStringSet(me.drive, iothreadMode === 'iothread', 'iothread', 'on');
+        PVE.Utils.propertyStringSet(
+            me.drive,
+            iothreadMode === 'vq-mapping' ? values.iothread_vq_mapping : undefined,
+            'iothread_vq_mapping',
+        );
         PVE.Utils.propertyStringSet(me.drive, values.readOnly, 'ro', 'on');
         PVE.Utils.propertyStringSet(me.drive, values.cache, 'cache');
         PVE.Utils.propertyStringSet(me.drive, values.aio, 'aio');
@@ -153,7 +164,14 @@ Ext.define('PVE.qemu.HDInputPanel', {
         values.cache = drive.cache || '__default__';
         values.discard = drive.discard === 'on';
         values.ssd = PVE.Parser.parseBoolean(drive.ssd);
-        values.iothread = PVE.Parser.parseBoolean(drive.iothread);
+        let iothreadMode = '__default__';
+        if (drive.iothread_vq_mapping) {
+            iothreadMode = 'vq-mapping';
+        } else if (PVE.Parser.parseBoolean(drive.iothread)) {
+            iothreadMode = 'iothread';
+        }
+        values.iothread_mode = iothreadMode;
+        values.iothread_vq_mapping = drive.iothread_vq_mapping ? parseInt(drive.iothread_vq_mapping, 10) : 2;
         values.readOnly = PVE.Parser.parseBoolean(drive.ro);
         values.aio = drive.aio || '__default__';
 
@@ -318,20 +336,44 @@ Ext.define('PVE.qemu.HDInputPanel', {
                 name: 'discard',
             },
             {
-                xtype: 'proxmoxcheckbox',
-                name: 'iothread',
-                fieldLabel: 'IO thread',
-                clearOnDisable: true,
+                xtype: 'proxmoxKVComboBox',
+                name: 'iothread_mode',
+                fieldLabel: gettext('IO thread'),
+                deleteEmpty: false,
+                value: '__default__',
+                comboItems: [
+                    ['__default__', gettext('disabled')],
+                    ['iothread', gettext('IO thread')],
+                    ['vq-mapping', gettext('VQ mapping')],
+                ],
                 bind:
                     me.insideWizard || me.isCreate
                         ? {
                               disabled: '{!isVirtIO && !isSCSI}',
-                              // Checkbox.setValue handles Arrays in a different way, therefore cast to bool
-                              value: '{!!isVirtIO || (isSCSI && isSCSISingle)}',
+                              value: '{defaultIothreadMode}',
                           }
                         : {
                               disabled: '{!isVirtIO && !isSCSI}',
                           },
+                listeners: {
+                    change: function(combo, val) {
+                        let countField = combo.up('window').down('[name=iothread_vq_mapping]');
+                        if (countField) {
+                            countField.setVisible(val === 'vq-mapping');
+                            if (val !== 'vq-mapping') countField.setValue(2);
+                        }
+                    },
+                },
+            },
+            {
+                xtype: 'proxmoxintegerfield',
+                name: 'iothread_vq_mapping',
+                fieldLabel: gettext('VQ count'),
+                minValue: 2,
+                maxValue: 16,
+                value: 2,
+                hidden: true,
+                allowBlank: false,
             },
         );
 
-- 
2.47.3




                 reply	other threads:[~2026-06-05 19:41 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260605160558.15783-1-dominik@budzowski.pl \
    --to=dominik@budzowski.pl \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal