Re: [PATCH] vhost-scsi: fix T10-PI lifecycle hard BUG after endpoint
Stefan Hajnoczi <[email protected]> Wed, 22 Jul 2026 11:14:39 -0400
| Newsgroups | dev.linux.lists.virtualization,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <CAJSP0QXMamS2rGRr4MtDM3ymtoH_DAD01NGkt4CjEJzZ6qbR5w@mail.gmail.com> |
On Wed, Jul 22, 2026 at 2:40 AM Jia Jia <[email protected]> wrote: > > vhost_scsi_setup_vq_cmds() runs only from VHOST_SCSI_SET_ENDPOINT and > allocates each command's protection scatterlist array (prot_sgl) only > when VIRTIO_SCSI_F_T10_PI is already set at that moment. Command pools > are not rebuilt later. vhost_scsi_set_features() may still flip that > bit after the endpoint is live: it updates acked_features and returns > success without reallocating prot_sgl. > > That is a feature-versus-resource lifetime mismatch. The broken order > is: > > VHOST_SET_FEATURES(0) > VHOST_SCSI_SET_ENDPOINT > setup_vq_cmds() sees no T10-PI -> prot_sgl stays NULL > VHOST_SET_FEATURES(VIRTIO_SCSI_F_T10_PI) > only acked_features changes; command resources stay as above VIRTIO_SCSI_F_T10_PI is defined in the VIRTIO spec. VIRTIO feature bits do not change once negotiated. The device must be reset in order to set the feature bits again. VHOST_F_LOG_ALL is a vhost-specific feature bit that is not covered by the VIRTIO spec and it can be changed at runtime. It is an exception. Please generalize this fix to only allow VHOST_F_LOG_ALL to be changed at runtime. Rather than protecting VIRTIO_SCSI_F_T10_PI specifically, attempts to change feature bits other than VHOST_F_LOG_ALL once the device is operational must be rejected. Perhaps other vhost device implementations have the same issue? Thanks, Stefan > submit a T10-PI WRITE with a 129-page protection payload > > The I/O path then follows the new feature bit while using the old > command objects. vhost_scsi_mapal() (static, inlined into > vhost_scsi_handle_vq() here) does: > > sg_alloc_table_chained(table, 129, first_chunk=NULL, > nents_first_chunk=inline_sg_cnt) > > With first_chunk NULL, __sg_alloc_table() sets curr_max_ents from > nents_first_chunk and calls sg_pool_alloc(129). sg_pool_index() then > hits: > > BUG_ON(nents > SG_CHUNK_SIZE); /* 129 > 128 */ > > The kernel reported the following call trace and register state: > > Call Trace: > <TASK> > ? __sg_alloc_table+0x1d8/0x250 > ? __pfx_vhost_run_work_list+0x10/0x10 [vhost] > sg_alloc_table_chained+0x59/0xf0 > ? __pfx_sg_pool_alloc+0x10/0x10 > ? vhost_scsi_calc_sgls.constprop.0+0x43/0x60 [vhost_scsi] > vhost_scsi_handle_vq+0xf02/0x1700 [vhost_scsi] > ? __pfx_vhost_scsi_handle_vq+0x10/0x10 [vhost_scsi] > vhost_scsi_handle_kick+0x37/0x50 [vhost_scsi] > vhost_run_work_list+0x8e/0xd0 [vhost] > vhost_task_fn+0xe1/0x210 > ret_from_fork+0x348/0x540 > </TASK> > > RIP: 0010:0x4 > CR2: 0000000000000004 > RSP: 0018:ffffc90000dbf940 EFLAGS: 00010202 > RAX: ffffffff82396810 RBX: ffff88811dc28b80 RCX: 0000000000000000 > RDX: 0000000000000000 RSI: 0000000000000820 RDI: 0000000000000081 > > The host worker dies and the machine stops accepting network service > until reset. The missing object is prot_sgl after a post-endpoint > T10-PI enable introduced by commit bf2d650391be ("vhost-scsi: Allocate > T10 PI structs only when enabled"). > > I also checked the other feature bits handled around endpoint setup. > Only T10-PI allocates this endpoint-time per-command resource and does > not rebuild it on a later SET_FEATURES. LOG_ALL uses lazy tvc_log and > already tears log storage down when cleared; HOTPLUG does not allocate > prot_sgl. So the chosen fix is to refuse T10-PI enable/disable while > an endpoint is active, rather than adding a second rebuild path in > set_features(). > > Return -EBUSY if vs->vs_tpg is set and the T10-PI bit would change. > Userspace must CLEAR_ENDPOINT, SET_FEATURES, then SET_ENDPOINT again so > setup_vq_cmds() can allocate protection SGLs when needed. That matches > the existing "build command resources at endpoint" model. > > Fixes: bf2d650391be ("vhost-scsi: Allocate T10 PI structs only when enabled") > Signed-off-by: Jia Jia <[email protected]> > --- > drivers/vhost/scsi.c | 10 ++++++++++ > 1 file changed, 10 insertions(+) > > diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c > index 9a1253b9d8c5..000000000000 100644 > --- a/drivers/vhost/scsi.c > +++ b/drivers/vhost/scsi.c > @@ -2219,6 +2219,7 @@ static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features) > { > struct vhost_virtqueue *vq; > bool is_log, was_log; > + bool is_t10_pi, was_t10_pi; > int i; > > if (features & ~VHOST_SCSI_FEATURES) > @@ -2234,6 +2235,13 @@ static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features) > if (!vs->dev.nvqs) > goto out; > > + is_t10_pi = features & (1ULL << VIRTIO_SCSI_F_T10_PI); > + was_t10_pi = vhost_has_feature(&vs->vqs[0].vq, VIRTIO_SCSI_F_T10_PI); > + if (vs->vs_tpg && is_t10_pi != was_t10_pi) { > + mutex_unlock(&vs->dev.mutex); > + return -EBUSY; > + } > + > is_log = features & (1 << VHOST_F_LOG_ALL); > /* > * All VQs should have same feature. > -- > 2.43.0 >