static struct class *mbochs_class;
static struct cdev mbochs_cdev;
static struct device mbochs_dev;
-static int mbochs_used_mbytes;
+static atomic_t mbochs_avail_mbytes;
static const struct vfio_device_ops mbochs_dev_ops;
struct vfio_region_info_ext {
static int mbochs_probe(struct mdev_device *mdev)
{
+ int avail_mbytes = atomic_read(&mbochs_avail_mbytes);
const struct mbochs_type *type =
&mbochs_types[mdev_get_type_group_id(mdev)];
struct device *dev = mdev_dev(mdev);
struct mdev_state *mdev_state;
int ret = -ENOMEM;
- if (type->mbytes + mbochs_used_mbytes > max_mbytes)
- return -ENOMEM;
+ do {
+ if (avail_mbytes < type->mbytes)
+ return -ENOSPC;
+ } while (!atomic_try_cmpxchg(&mbochs_avail_mbytes, &avail_mbytes,
+ avail_mbytes - type->mbytes));
mdev_state = kzalloc(sizeof(struct mdev_state), GFP_KERNEL);
if (mdev_state == NULL)
- return -ENOMEM;
+ goto err_avail;
vfio_init_group_dev(&mdev_state->vdev, &mdev->dev, &mbochs_dev_ops);
mdev_state->vconfig = kzalloc(MBOCHS_CONFIG_SPACE_SIZE, GFP_KERNEL);
mbochs_create_config_space(mdev_state);
mbochs_reset(mdev_state);
- mbochs_used_mbytes += type->mbytes;
-
ret = vfio_register_group_dev(&mdev_state->vdev);
if (ret)
goto err_mem;
dev_set_drvdata(&mdev->dev, mdev_state);
return 0;
-
err_mem:
+ kfree(mdev_state->pages);
kfree(mdev_state->vconfig);
kfree(mdev_state);
+err_avail:
+ atomic_add(type->mbytes, &mbochs_avail_mbytes);
return ret;
}
{
struct mdev_state *mdev_state = dev_get_drvdata(&mdev->dev);
- mbochs_used_mbytes -= mdev_state->type->mbytes;
vfio_unregister_group_dev(&mdev_state->vdev);
+ atomic_add(mdev_state->type->mbytes, &mbochs_avail_mbytes);
kfree(mdev_state->pages);
kfree(mdev_state->vconfig);
kfree(mdev_state);
{
const struct mbochs_type *type =
&mbochs_types[mtype_get_type_group_id(mtype)];
- int count = (max_mbytes - mbochs_used_mbytes) / type->mbytes;
+ int count = atomic_read(&mbochs_avail_mbytes) / type->mbytes;
return sprintf(buf, "%d\n", count);
}
{
int ret = 0;
+ atomic_set(&mbochs_avail_mbytes, max_mbytes);
+
ret = alloc_chrdev_region(&mbochs_devt, 0, MINORMASK + 1, MBOCHS_NAME);
if (ret < 0) {
pr_err("Error: failed to register mbochs_dev, err: %d\n", ret);