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>
This commit is contained in:
parent
ac9fde2474
commit
595cb75498
@ -1373,21 +1373,30 @@ static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void vhost_scsi_free(struct vhost_scsi *vs)
|
||||||
|
{
|
||||||
|
if (is_vmalloc_addr(vs))
|
||||||
|
vfree(vs);
|
||||||
|
else
|
||||||
|
kfree(vs);
|
||||||
|
}
|
||||||
|
|
||||||
static int vhost_scsi_open(struct inode *inode, struct file *f)
|
static int vhost_scsi_open(struct inode *inode, struct file *f)
|
||||||
{
|
{
|
||||||
struct vhost_scsi *vs;
|
struct vhost_scsi *vs;
|
||||||
struct vhost_virtqueue **vqs;
|
struct vhost_virtqueue **vqs;
|
||||||
int r, i;
|
int r = -ENOMEM, i;
|
||||||
|
|
||||||
vs = kzalloc(sizeof(*vs), GFP_KERNEL);
|
vs = kzalloc(sizeof(*vs), GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT);
|
||||||
if (!vs)
|
if (!vs) {
|
||||||
return -ENOMEM;
|
vs = vzalloc(sizeof(*vs));
|
||||||
|
if (!vs)
|
||||||
|
goto err_vs;
|
||||||
|
}
|
||||||
|
|
||||||
vqs = kmalloc(VHOST_SCSI_MAX_VQ * sizeof(*vqs), GFP_KERNEL);
|
vqs = kmalloc(VHOST_SCSI_MAX_VQ * sizeof(*vqs), GFP_KERNEL);
|
||||||
if (!vqs) {
|
if (!vqs)
|
||||||
kfree(vs);
|
goto err_vqs;
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
vhost_work_init(&vs->vs_completion_work, vhost_scsi_complete_cmd_work);
|
vhost_work_init(&vs->vs_completion_work, vhost_scsi_complete_cmd_work);
|
||||||
vhost_work_init(&vs->vs_event_work, tcm_vhost_evt_work);
|
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)
|
|||||||
|
|
||||||
tcm_vhost_init_inflight(vs, NULL);
|
tcm_vhost_init_inflight(vs, NULL);
|
||||||
|
|
||||||
if (r < 0) {
|
if (r < 0)
|
||||||
kfree(vqs);
|
goto err_init;
|
||||||
kfree(vs);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
f->private_data = vs;
|
f->private_data = vs;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_init:
|
||||||
|
kfree(vqs);
|
||||||
|
err_vqs:
|
||||||
|
vhost_scsi_free(vs);
|
||||||
|
err_vs:
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vhost_scsi_release(struct inode *inode, struct file *f)
|
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)
|
|||||||
/* Jobs can re-queue themselves in evt kick handler. Do extra flush. */
|
/* Jobs can re-queue themselves in evt kick handler. Do extra flush. */
|
||||||
vhost_scsi_flush(vs);
|
vhost_scsi_flush(vs);
|
||||||
kfree(vs->dev.vqs);
|
kfree(vs->dev.vqs);
|
||||||
kfree(vs);
|
vhost_scsi_free(vs);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user