Skip to content

Commit c2c5c25

Browse files
Dongli Zhangmstsirkin
authored andcommitted
vhost-scsi: log I/O queue write descriptors
Log write descriptors for the I/O queue, leveraging vhost_scsi_get_desc() and vhost_get_vq_desc() to retrieve the array of write descriptors to obtain the log buffer. In addition, introduce a vhost-scsi specific function to log vring descriptors. In this function, the 'partial' argument is set to false, and the 'len' argument is set to 0, because vhost-scsi always logs all pages shared by a vring descriptor. Add WARN_ON_ONCE() since vhost-scsi doesn't support VIRTIO_F_ACCESS_PLATFORM. The per-cmd log buffer is allocated on demand in the submission path after VHOST_F_LOG_ALL is set. Return -ENOMEM on allocation failure, in order to send SAM_STAT_TASK_SET_FULL to the guest. It isn't reclaimed in the completion path. Instead, it is reclaimed when VHOST_F_LOG_ALL is removed, or during VHOST_SCSI_SET_ENDPOINT when all commands are destroyed. Store the log buffer during the submission path and log it in the completion path. Logging is also required in the error handling path of the submission process. Suggested-by: Joao Martins <joao.m.martins@oracle.com> Signed-off-by: Dongli Zhang <dongli.zhang@oracle.com> Message-Id: <20250403063028.16045-7-dongli.zhang@oracle.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Reviewed-by: Mike Christie <michael.christie@oracle.com>
1 parent e5e6b15 commit c2c5c25

File tree

1 file changed

+116
-3
lines changed

1 file changed

+116
-3
lines changed

drivers/vhost/scsi.c

Lines changed: 116 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,11 @@ struct vhost_scsi_cmd {
133133
struct se_cmd tvc_se_cmd;
134134
/* Sense buffer that will be mapped into outgoing status */
135135
unsigned char tvc_sense_buf[TRANSPORT_SENSE_BUFFER];
136+
/*
137+
* Dirty write descriptors of this command.
138+
*/
139+
struct vhost_log *tvc_log;
140+
unsigned int tvc_log_num;
136141
/* Completed commands list, serviced from vhost worker thread */
137142
struct llist_node tvc_completion_list;
138143
/* Used to track inflight cmd */
@@ -362,6 +367,45 @@ static int vhost_scsi_check_prot_fabric_only(struct se_portal_group *se_tpg)
362367
return tpg->tv_fabric_prot_type;
363368
}
364369

370+
static int vhost_scsi_copy_cmd_log(struct vhost_virtqueue *vq,
371+
struct vhost_scsi_cmd *cmd,
372+
struct vhost_log *log,
373+
unsigned int log_num)
374+
{
375+
if (!cmd->tvc_log)
376+
cmd->tvc_log = kmalloc_array(vq->dev->iov_limit,
377+
sizeof(*cmd->tvc_log),
378+
GFP_KERNEL);
379+
380+
if (unlikely(!cmd->tvc_log)) {
381+
vq_err(vq, "Failed to alloc tvc_log\n");
382+
return -ENOMEM;
383+
}
384+
385+
memcpy(cmd->tvc_log, log, sizeof(*cmd->tvc_log) * log_num);
386+
cmd->tvc_log_num = log_num;
387+
388+
return 0;
389+
}
390+
391+
static void vhost_scsi_log_write(struct vhost_virtqueue *vq,
392+
struct vhost_log *log,
393+
unsigned int log_num)
394+
{
395+
if (likely(!vhost_has_feature(vq, VHOST_F_LOG_ALL)))
396+
return;
397+
398+
if (likely(!log_num || !log))
399+
return;
400+
401+
/*
402+
* vhost-scsi doesn't support VIRTIO_F_ACCESS_PLATFORM.
403+
* No requirement for vq->iotlb case.
404+
*/
405+
WARN_ON_ONCE(unlikely(vq->iotlb));
406+
vhost_log_write(vq, log, log_num, U64_MAX, NULL, 0);
407+
}
408+
365409
static void vhost_scsi_release_cmd_res(struct se_cmd *se_cmd)
366410
{
367411
struct vhost_scsi_cmd *tv_cmd = container_of(se_cmd,
@@ -660,6 +704,9 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
660704
} else
661705
pr_err("Faulted on virtio_scsi_cmd_resp\n");
662706

707+
vhost_scsi_log_write(cmd->tvc_vq, cmd->tvc_log,
708+
cmd->tvc_log_num);
709+
663710
vhost_scsi_release_cmd_res(se_cmd);
664711
}
665712

@@ -676,6 +723,7 @@ vhost_scsi_get_cmd(struct vhost_virtqueue *vq, u64 scsi_tag)
676723
struct vhost_scsi_virtqueue, vq);
677724
struct vhost_scsi_cmd *cmd;
678725
struct scatterlist *sgl, *prot_sgl;
726+
struct vhost_log *log;
679727
int tag;
680728

681729
tag = sbitmap_get(&svq->scsi_tags);
@@ -687,9 +735,11 @@ vhost_scsi_get_cmd(struct vhost_virtqueue *vq, u64 scsi_tag)
687735
cmd = &svq->scsi_cmds[tag];
688736
sgl = cmd->sgl;
689737
prot_sgl = cmd->prot_sgl;
738+
log = cmd->tvc_log;
690739
memset(cmd, 0, sizeof(*cmd));
691740
cmd->sgl = sgl;
692741
cmd->prot_sgl = prot_sgl;
742+
cmd->tvc_log = log;
693743
cmd->tvc_se_cmd.map_tag = tag;
694744
cmd->inflight = vhost_scsi_get_inflight(vq);
695745

@@ -1225,6 +1275,8 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
12251275
u8 task_attr;
12261276
bool t10_pi = vhost_has_feature(vq, VIRTIO_SCSI_F_T10_PI);
12271277
u8 *cdb;
1278+
struct vhost_log *vq_log;
1279+
unsigned int log_num;
12281280

12291281
mutex_lock(&vq->mutex);
12301282
/*
@@ -1240,8 +1292,11 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
12401292

12411293
vhost_disable_notify(&vs->dev, vq);
12421294

1295+
vq_log = unlikely(vhost_has_feature(vq, VHOST_F_LOG_ALL)) ?
1296+
vq->log : NULL;
1297+
12431298
do {
1244-
ret = vhost_scsi_get_desc(vs, vq, &vc, NULL, NULL);
1299+
ret = vhost_scsi_get_desc(vs, vq, &vc, vq_log, &log_num);
12451300
if (ret)
12461301
goto err;
12471302

@@ -1390,6 +1445,14 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
13901445
goto err;
13911446
}
13921447

1448+
if (unlikely(vq_log && log_num)) {
1449+
ret = vhost_scsi_copy_cmd_log(vq, cmd, vq_log, log_num);
1450+
if (unlikely(ret)) {
1451+
vhost_scsi_release_cmd_res(&cmd->tvc_se_cmd);
1452+
goto err;
1453+
}
1454+
}
1455+
13931456
pr_debug("vhost_scsi got command opcode: %#02x, lun: %d\n",
13941457
cdb[0], lun);
13951458
pr_debug("cmd: %p exp_data_len: %d, prot_bytes: %d data_direction:"
@@ -1425,11 +1488,14 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
14251488
*/
14261489
if (ret == -ENXIO)
14271490
break;
1428-
else if (ret == -EIO)
1491+
else if (ret == -EIO) {
14291492
vhost_scsi_send_bad_target(vs, vq, &vc, TYPE_IO_CMD);
1430-
else if (ret == -ENOMEM)
1493+
vhost_scsi_log_write(vq, vq_log, log_num);
1494+
} else if (ret == -ENOMEM) {
14311495
vhost_scsi_send_status(vs, vq, &vc,
14321496
SAM_STAT_TASK_SET_FULL);
1497+
vhost_scsi_log_write(vq, vq_log, log_num);
1498+
}
14331499
} while (likely(!vhost_exceeds_weight(vq, ++c, 0)));
14341500
out:
14351501
mutex_unlock(&vq->mutex);
@@ -1760,6 +1826,24 @@ static void vhost_scsi_flush(struct vhost_scsi *vs)
17601826
wait_for_completion(&vs->old_inflight[i]->comp);
17611827
}
17621828

1829+
static void vhost_scsi_destroy_vq_log(struct vhost_virtqueue *vq)
1830+
{
1831+
struct vhost_scsi_virtqueue *svq = container_of(vq,
1832+
struct vhost_scsi_virtqueue, vq);
1833+
struct vhost_scsi_cmd *tv_cmd;
1834+
unsigned int i;
1835+
1836+
if (!svq->scsi_cmds)
1837+
return;
1838+
1839+
for (i = 0; i < svq->max_cmds; i++) {
1840+
tv_cmd = &svq->scsi_cmds[i];
1841+
kfree(tv_cmd->tvc_log);
1842+
tv_cmd->tvc_log = NULL;
1843+
tv_cmd->tvc_log_num = 0;
1844+
}
1845+
}
1846+
17631847
static void vhost_scsi_destroy_vq_cmds(struct vhost_virtqueue *vq)
17641848
{
17651849
struct vhost_scsi_virtqueue *svq = container_of(vq,
@@ -1779,6 +1863,7 @@ static void vhost_scsi_destroy_vq_cmds(struct vhost_virtqueue *vq)
17791863

17801864
sbitmap_free(&svq->scsi_tags);
17811865
kfree(svq->upages);
1866+
vhost_scsi_destroy_vq_log(vq);
17821867
kfree(svq->scsi_cmds);
17831868
svq->scsi_cmds = NULL;
17841869
}
@@ -2088,6 +2173,7 @@ vhost_scsi_clear_endpoint(struct vhost_scsi *vs,
20882173
static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features)
20892174
{
20902175
struct vhost_virtqueue *vq;
2176+
bool is_log, was_log;
20912177
int i;
20922178

20932179
if (features & ~VHOST_SCSI_FEATURES)
@@ -2100,12 +2186,39 @@ static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features)
21002186
return -EFAULT;
21012187
}
21022188

2189+
if (!vs->dev.nvqs)
2190+
goto out;
2191+
2192+
is_log = features & (1 << VHOST_F_LOG_ALL);
2193+
/*
2194+
* All VQs should have same feature.
2195+
*/
2196+
was_log = vhost_has_feature(&vs->vqs[0].vq, VHOST_F_LOG_ALL);
2197+
21032198
for (i = 0; i < vs->dev.nvqs; i++) {
21042199
vq = &vs->vqs[i].vq;
21052200
mutex_lock(&vq->mutex);
21062201
vq->acked_features = features;
21072202
mutex_unlock(&vq->mutex);
21082203
}
2204+
2205+
/*
2206+
* If VHOST_F_LOG_ALL is removed, free tvc_log after
2207+
* vq->acked_features is committed.
2208+
*/
2209+
if (!is_log && was_log) {
2210+
for (i = VHOST_SCSI_VQ_IO; i < vs->dev.nvqs; i++) {
2211+
if (!vs->vqs[i].scsi_cmds)
2212+
continue;
2213+
2214+
vq = &vs->vqs[i].vq;
2215+
mutex_lock(&vq->mutex);
2216+
vhost_scsi_destroy_vq_log(vq);
2217+
mutex_unlock(&vq->mutex);
2218+
}
2219+
}
2220+
2221+
out:
21092222
mutex_unlock(&vs->dev.mutex);
21102223
return 0;
21112224
}

0 commit comments

Comments
 (0)