diff options
author | Michael S. Tsirkin <mst@redhat.com> | 2013-09-17 02:30:34 -0400 |
---|---|---|
committer | Michael S. Tsirkin <mst@redhat.com> | 2013-09-17 15:55:46 -0400 |
commit | 595cb754983d4387cb25b3dcf08f5129663d634e (patch) | |
tree | fbd228ea66ec0cf53681efb952fc084a8b6603f0 /drivers/vhost/scsi.c | |
parent | ac9fde2474d04bd6574a037482e3de02b488a6c6 (diff) |
vhost/scsi: use vmalloc for order-10 allocation
As vhost scsi device struct is large, if the device is
created on a busy system, kzalloc() might fail, so this patch does a
fallback to vzalloc().
As vmalloc() adds overhead on data-path, add __GFP_REPEAT
to kzalloc() flags to do this fallback only when really needed.
Reviewed-by: Asias He <asias@redhat.com>
Reported-by: Dan Aloni <alonid@stratoscale.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'drivers/vhost/scsi.c')
-rw-r--r-- | drivers/vhost/scsi.c | 41 |
1 files changed, 27 insertions, 14 deletions
diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 4b79a1f2f901..38ccf4ad6b7a 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c | |||
@@ -1373,21 +1373,30 @@ static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features) | |||
1373 | return 0; | 1373 | return 0; |
1374 | } | 1374 | } |
1375 | 1375 | ||
1376 | static void vhost_scsi_free(struct vhost_scsi *vs) | ||
1377 | { | ||
1378 | if (is_vmalloc_addr(vs)) | ||
1379 | vfree(vs); | ||
1380 | else | ||
1381 | kfree(vs); | ||
1382 | } | ||
1383 | |||
1376 | static int vhost_scsi_open(struct inode *inode, struct file *f) | 1384 | static int vhost_scsi_open(struct inode *inode, struct file *f) |
1377 | { | 1385 | { |
1378 | struct vhost_scsi *vs; | 1386 | struct vhost_scsi *vs; |
1379 | struct vhost_virtqueue **vqs; | 1387 | struct vhost_virtqueue **vqs; |
1380 | int r, i; | 1388 | int r = -ENOMEM, i; |
1381 | 1389 | ||
1382 | vs = kzalloc(sizeof(*vs), GFP_KERNEL); | 1390 | vs = kzalloc(sizeof(*vs), GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT); |
1383 | if (!vs) | 1391 | if (!vs) { |
1384 | return -ENOMEM; | 1392 | vs = vzalloc(sizeof(*vs)); |
1393 | if (!vs) | ||
1394 | goto err_vs; | ||
1395 | } | ||
1385 | 1396 | ||
1386 | vqs = kmalloc(VHOST_SCSI_MAX_VQ * sizeof(*vqs), GFP_KERNEL); | 1397 | vqs = kmalloc(VHOST_SCSI_MAX_VQ * sizeof(*vqs), GFP_KERNEL); |
1387 | if (!vqs) { | 1398 | if (!vqs) |
1388 | kfree(vs); | 1399 | goto err_vqs; |
1389 | return -ENOMEM; | ||
1390 | } | ||
1391 | 1400 | ||
1392 | vhost_work_init(&vs->vs_completion_work, vhost_scsi_complete_cmd_work); | 1401 | vhost_work_init(&vs->vs_completion_work, vhost_scsi_complete_cmd_work); |
1393 | vhost_work_init(&vs->vs_event_work, tcm_vhost_evt_work); | 1402 | vhost_work_init(&vs->vs_event_work, tcm_vhost_evt_work); |
@@ -1407,14 +1416,18 @@ static int vhost_scsi_open(struct inode *inode, struct file *f) | |||
1407 | 1416 | ||
1408 | tcm_vhost_init_inflight(vs, NULL); | 1417 | tcm_vhost_init_inflight(vs, NULL); |
1409 | 1418 | ||
1410 | if (r < 0) { | 1419 | if (r < 0) |
1411 | kfree(vqs); | 1420 | goto err_init; |
1412 | kfree(vs); | ||
1413 | return r; | ||
1414 | } | ||
1415 | 1421 | ||
1416 | f->private_data = vs; | 1422 | f->private_data = vs; |
1417 | return 0; | 1423 | return 0; |
1424 | |||
1425 | err_init: | ||
1426 | kfree(vqs); | ||
1427 | err_vqs: | ||
1428 | vhost_scsi_free(vs); | ||
1429 | err_vs: | ||
1430 | return r; | ||
1418 | } | 1431 | } |
1419 | 1432 | ||
1420 | static int vhost_scsi_release(struct inode *inode, struct file *f) | 1433 | static int vhost_scsi_release(struct inode *inode, struct file *f) |
@@ -1431,7 +1444,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. */ | 1444 | /* Jobs can re-queue themselves in evt kick handler. Do extra flush. */ |
1432 | vhost_scsi_flush(vs); | 1445 | vhost_scsi_flush(vs); |
1433 | kfree(vs->dev.vqs); | 1446 | kfree(vs->dev.vqs); |
1434 | kfree(vs); | 1447 | vhost_scsi_free(vs); |
1435 | return 0; | 1448 | return 0; |
1436 | } | 1449 | } |
1437 | 1450 | ||