diff options
Diffstat (limited to 'drivers/vhost/scsi.c')
-rw-r--r-- | drivers/vhost/scsi.c | 52 |
1 files changed, 35 insertions, 17 deletions
diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 4b79a1f2f901..e663921eebb6 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c | |||
@@ -461,7 +461,7 @@ static void tcm_vhost_release_cmd(struct se_cmd *se_cmd) | |||
461 | u32 i; | 461 | u32 i; |
462 | for (i = 0; i < tv_cmd->tvc_sgl_count; i++) | 462 | for (i = 0; i < tv_cmd->tvc_sgl_count; i++) |
463 | put_page(sg_page(&tv_cmd->tvc_sgl[i])); | 463 | put_page(sg_page(&tv_cmd->tvc_sgl[i])); |
464 | } | 464 | } |
465 | 465 | ||
466 | tcm_vhost_put_inflight(tv_cmd->inflight); | 466 | tcm_vhost_put_inflight(tv_cmd->inflight); |
467 | percpu_ida_free(&se_sess->sess_tag_pool, se_cmd->map_tag); | 467 | percpu_ida_free(&se_sess->sess_tag_pool, se_cmd->map_tag); |
@@ -728,7 +728,12 @@ vhost_scsi_get_tag(struct vhost_virtqueue *vq, | |||
728 | } | 728 | } |
729 | se_sess = tv_nexus->tvn_se_sess; | 729 | se_sess = tv_nexus->tvn_se_sess; |
730 | 730 | ||
731 | tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_KERNEL); | 731 | tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_ATOMIC); |
732 | if (tag < 0) { | ||
733 | pr_err("Unable to obtain tag for tcm_vhost_cmd\n"); | ||
734 | return ERR_PTR(-ENOMEM); | ||
735 | } | ||
736 | |||
732 | cmd = &((struct tcm_vhost_cmd *)se_sess->sess_cmd_map)[tag]; | 737 | cmd = &((struct tcm_vhost_cmd *)se_sess->sess_cmd_map)[tag]; |
733 | sg = cmd->tvc_sgl; | 738 | sg = cmd->tvc_sgl; |
734 | pages = cmd->tvc_upages; | 739 | pages = cmd->tvc_upages; |
@@ -1051,7 +1056,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq) | |||
1051 | if (data_direction != DMA_NONE) { | 1056 | if (data_direction != DMA_NONE) { |
1052 | ret = vhost_scsi_map_iov_to_sgl(cmd, | 1057 | ret = vhost_scsi_map_iov_to_sgl(cmd, |
1053 | &vq->iov[data_first], data_num, | 1058 | &vq->iov[data_first], data_num, |
1054 | data_direction == DMA_TO_DEVICE); | 1059 | data_direction == DMA_FROM_DEVICE); |
1055 | if (unlikely(ret)) { | 1060 | if (unlikely(ret)) { |
1056 | vq_err(vq, "Failed to map iov to sgl\n"); | 1061 | vq_err(vq, "Failed to map iov to sgl\n"); |
1057 | goto err_free; | 1062 | goto err_free; |
@@ -1373,21 +1378,30 @@ static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features) | |||
1373 | return 0; | 1378 | return 0; |
1374 | } | 1379 | } |
1375 | 1380 | ||
1381 | static void vhost_scsi_free(struct vhost_scsi *vs) | ||
1382 | { | ||
1383 | if (is_vmalloc_addr(vs)) | ||
1384 | vfree(vs); | ||
1385 | else | ||
1386 | kfree(vs); | ||
1387 | } | ||
1388 | |||
1376 | static int vhost_scsi_open(struct inode *inode, struct file *f) | 1389 | static int vhost_scsi_open(struct inode *inode, struct file *f) |
1377 | { | 1390 | { |
1378 | struct vhost_scsi *vs; | 1391 | struct vhost_scsi *vs; |
1379 | struct vhost_virtqueue **vqs; | 1392 | struct vhost_virtqueue **vqs; |
1380 | int r, i; | 1393 | int r = -ENOMEM, i; |
1381 | 1394 | ||
1382 | vs = kzalloc(sizeof(*vs), GFP_KERNEL); | 1395 | vs = kzalloc(sizeof(*vs), GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT); |
1383 | if (!vs) | 1396 | if (!vs) { |
1384 | return -ENOMEM; | 1397 | vs = vzalloc(sizeof(*vs)); |
1398 | if (!vs) | ||
1399 | goto err_vs; | ||
1400 | } | ||
1385 | 1401 | ||
1386 | vqs = kmalloc(VHOST_SCSI_MAX_VQ * sizeof(*vqs), GFP_KERNEL); | 1402 | vqs = kmalloc(VHOST_SCSI_MAX_VQ * sizeof(*vqs), GFP_KERNEL); |
1387 | if (!vqs) { | 1403 | if (!vqs) |
1388 | kfree(vs); | 1404 | goto err_vqs; |
1389 | return -ENOMEM; | ||
1390 | } | ||
1391 | 1405 | ||
1392 | vhost_work_init(&vs->vs_completion_work, vhost_scsi_complete_cmd_work); | 1406 | vhost_work_init(&vs->vs_completion_work, vhost_scsi_complete_cmd_work); |
1393 | vhost_work_init(&vs->vs_event_work, tcm_vhost_evt_work); | 1407 | vhost_work_init(&vs->vs_event_work, tcm_vhost_evt_work); |
@@ -1407,14 +1421,18 @@ static int vhost_scsi_open(struct inode *inode, struct file *f) | |||
1407 | 1421 | ||
1408 | tcm_vhost_init_inflight(vs, NULL); | 1422 | tcm_vhost_init_inflight(vs, NULL); |
1409 | 1423 | ||
1410 | if (r < 0) { | 1424 | if (r < 0) |
1411 | kfree(vqs); | 1425 | goto err_init; |
1412 | kfree(vs); | ||
1413 | return r; | ||
1414 | } | ||
1415 | 1426 | ||
1416 | f->private_data = vs; | 1427 | f->private_data = vs; |
1417 | return 0; | 1428 | return 0; |
1429 | |||
1430 | err_init: | ||
1431 | kfree(vqs); | ||
1432 | err_vqs: | ||
1433 | vhost_scsi_free(vs); | ||
1434 | err_vs: | ||
1435 | return r; | ||
1418 | } | 1436 | } |
1419 | 1437 | ||
1420 | static int vhost_scsi_release(struct inode *inode, struct file *f) | 1438 | static int vhost_scsi_release(struct inode *inode, struct file *f) |
@@ -1431,7 +1449,7 @@ static int vhost_scsi_release(struct inode *inode, struct file *f) | |||
1431 | /* Jobs can re-queue themselves in evt kick handler. Do extra flush. */ | 1449 | /* Jobs can re-queue themselves in evt kick handler. Do extra flush. */ |
1432 | vhost_scsi_flush(vs); | 1450 | vhost_scsi_flush(vs); |
1433 | kfree(vs->dev.vqs); | 1451 | kfree(vs->dev.vqs); |
1434 | kfree(vs); | 1452 | vhost_scsi_free(vs); |
1435 | return 0; | 1453 | return 0; |
1436 | } | 1454 | } |
1437 | 1455 | ||