Re: [PATCH v4 6/7] lightnvm: track inflight target creations

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> On 16 Apr 2019, at 12.16, Igor Konopko <igor.j.konopko@xxxxxxxxx> wrote:
> 
> When creation process is still in progress, target is not yet on
> targets list. This causes a chance for removing whole lightnvm
> subsystem by calling nvm_unregister() in the meantime and finally by
> causing kernel panic inside target init function.
> 
> This patch changes the behaviour by adding kref variable which tracks
> all the users of nvm_dev structure. When nvm_dev is allocated, kref
> value is set to 1. Then before every target creation the value is
> increased and decreased after target removal. The extra reference
> is decreased when nvm subsystem is unregistered.
> 
> Signed-off-by: Igor Konopko <igor.j.konopko@xxxxxxxxx>
> ---
> drivers/lightnvm/core.c  | 41 +++++++++++++++++++++++++++++++----------
> include/linux/lightnvm.h |  1 +
> 2 files changed, 32 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
> index e2abe88..0e9f7996 100644
> --- a/drivers/lightnvm/core.c
> +++ b/drivers/lightnvm/core.c
> @@ -45,6 +45,8 @@ struct nvm_dev_map {
> 	int num_ch;
> };
> 
> +static void nvm_free(struct kref *ref);
> +
> static struct nvm_target *nvm_find_target(struct nvm_dev *dev, const char *name)
> {
> 	struct nvm_target *tgt;
> @@ -501,6 +503,7 @@ static int nvm_remove_tgt(struct nvm_dev *dev, struct nvm_ioctl_remove *remove)
> 	}
> 	__nvm_remove_target(t, true);
> 	mutex_unlock(&dev->mlock);
> +	kref_put(&dev->ref, nvm_free);
> 
> 	return 0;
> }
> @@ -1094,15 +1097,16 @@ static int nvm_core_init(struct nvm_dev *dev)
> 	return ret;
> }
> 
> -static void nvm_free(struct nvm_dev *dev)
> +static void nvm_free(struct kref *ref)
> {
> -	if (!dev)
> -		return;
> +	struct nvm_dev *dev = container_of(ref, struct nvm_dev, ref);
> 
> 	if (dev->dma_pool)
> 		dev->ops->destroy_dma_pool(dev->dma_pool);
> 
> -	nvm_unregister_map(dev);
> +	if (dev->rmap)
> +		nvm_unregister_map(dev);
> +
> 	kfree(dev->lun_map);
> 	kfree(dev);
> }
> @@ -1139,7 +1143,13 @@ static int nvm_init(struct nvm_dev *dev)
> 
> struct nvm_dev *nvm_alloc_dev(int node)
> {
> -	return kzalloc_node(sizeof(struct nvm_dev), GFP_KERNEL, node);
> +	struct nvm_dev *dev;
> +
> +	dev = kzalloc_node(sizeof(struct nvm_dev), GFP_KERNEL, node);
> +	if (dev)
> +		kref_init(&dev->ref);
> +
> +	return dev;
> }
> EXPORT_SYMBOL(nvm_alloc_dev);
> 
> @@ -1147,12 +1157,16 @@ int nvm_register(struct nvm_dev *dev)
> {
> 	int ret, exp_pool_size;
> 
> -	if (!dev->q || !dev->ops)
> +	if (!dev->q || !dev->ops) {
> +		kref_put(&dev->ref, nvm_free);
> 		return -EINVAL;
> +	}
> 
> 	ret = nvm_init(dev);
> -	if (ret)
> +	if (ret) {
> +		kref_put(&dev->ref, nvm_free);
> 		return ret;
> +	}
> 
> 	exp_pool_size = max_t(int, PAGE_SIZE,
> 			      (NVM_MAX_VLBA * (sizeof(u64) + dev->geo.sos)));
> @@ -1162,7 +1176,7 @@ int nvm_register(struct nvm_dev *dev)
> 						  exp_pool_size);
> 	if (!dev->dma_pool) {
> 		pr_err("nvm: could not create dma pool\n");
> -		nvm_free(dev);
> +		kref_put(&dev->ref, nvm_free);
> 		return -ENOMEM;
> 	}
> 
> @@ -1184,6 +1198,7 @@ void nvm_unregister(struct nvm_dev *dev)
> 		if (t->dev->parent != dev)
> 			continue;
> 		__nvm_remove_target(t, false);
> +		kref_put(&dev->ref, nvm_free);
> 	}
> 	mutex_unlock(&dev->mlock);
> 
> @@ -1191,13 +1206,14 @@ void nvm_unregister(struct nvm_dev *dev)
> 	list_del(&dev->devices);
> 	up_write(&nvm_lock);
> 
> -	nvm_free(dev);
> +	kref_put(&dev->ref, nvm_free);
> }
> EXPORT_SYMBOL(nvm_unregister);
> 
> static int __nvm_configure_create(struct nvm_ioctl_create *create)
> {
> 	struct nvm_dev *dev;
> +	int ret;
> 
> 	down_write(&nvm_lock);
> 	dev = nvm_find_nvm_dev(create->dev);
> @@ -1208,7 +1224,12 @@ static int __nvm_configure_create(struct nvm_ioctl_create *create)
> 		return -EINVAL;
> 	}
> 
> -	return nvm_create_tgt(dev, create);
> +	kref_get(&dev->ref);
> +	ret = nvm_create_tgt(dev, create);
> +	if (ret)
> +		kref_put(&dev->ref, nvm_free);
> +
> +	return ret;
> }
> 
> static long nvm_ioctl_info(struct file *file, void __user *arg)
> diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
> index d3b0270..4d0d565 100644
> --- a/include/linux/lightnvm.h
> +++ b/include/linux/lightnvm.h
> @@ -428,6 +428,7 @@ struct nvm_dev {
> 	char name[DISK_NAME_LEN];
> 	void *private_data;
> 
> +	struct kref ref;
> 	void *rmap;
> 
> 	struct mutex mlock;
> --
> 2.9.5

Much better with the kref()


Reviewed-by: Javier González <javier@xxxxxxxxxxx>

Attachment: signature.asc
Description: Message signed with OpenPGP


[Index of Archives]     [Linux RAID]     [Linux SCSI]     [Linux ATA RAID]     [IDE]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Device Mapper]

  Powered by Linux