From patchwork Fri Nov 27 04:09:43 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wenwei Tao X-Patchwork-Id: 7710871 Return-Path: X-Original-To: patchwork-linux-block@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 9C3C5BF90C for ; Fri, 27 Nov 2015 04:12:19 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 9AC2F205B6 for ; Fri, 27 Nov 2015 04:12:18 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 81B0E205B3 for ; Fri, 27 Nov 2015 04:12:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753939AbbK0EKz (ORCPT ); Thu, 26 Nov 2015 23:10:55 -0500 Received: from mail-pa0-f66.google.com ([209.85.220.66]:34891 "EHLO mail-pa0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753883AbbK0EKQ (ORCPT ); Thu, 26 Nov 2015 23:10:16 -0500 Received: by padhk6 with SMTP id hk6so13577624pad.2; Thu, 26 Nov 2015 20:10:16 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=NBPaJiynv3UKpRRhhPtk6AGpL+0p4cZf/zd8MZExask=; b=TqNJNzV2pEIUqBm3QBwEG05ZDhH0/MXkC0EIynLH5LbwLwZZa3spcP6Q2B5GADtDWw RtHJcIaqC/3AJ0e2a7okCK6bUpHGUDiqhWfI2WyYXx9WGsOjQittzo0JdwHYO/dpzUdA hHGNvOeXJHGw/4+3P9y0w2nIHC9OPKk2qWXskfpAteumfWq28HDeiuH6lU3BFJKL23Tr Iv+K+lgBQ3+DZHjrKUCD+VKV2nuqH5NzXSCX1xPxG7eHNnc7GCij+BsqbWbyK4sV5478 2pKjyP3GEQklBnW74f7jjR1tchUmCUEk2co8LFwoXJwJTz0Z/k7pzUJtsNgW6FkHBouI PeBA== X-Received: by 10.98.73.13 with SMTP id w13mr43980222pfa.72.1448597416296; Thu, 26 Nov 2015 20:10:16 -0800 (PST) Received: from localhost.localdomain.com ([111.204.49.2]) by smtp.gmail.com with ESMTPSA id l20sm30462958pfi.10.2015.11.26.20.10.13 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 26 Nov 2015 20:10:15 -0800 (PST) From: Wenwei Tao To: mb@lightnvm.io, keith.busch@intel.com, axboe@fb.com Cc: linux-kernel@vger.kernel.org, linux-block@vger.kernel.org, linux-nvme@lists.infradead.org Subject: [PATCH v2 2/3] lightnvm: handle targets when corresponding nvm device exit Date: Fri, 27 Nov 2015 12:09:43 +0800 Message-Id: <1448597384-27976-3-git-send-email-ww.tao0320@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1448597384-27976-1-git-send-email-ww.tao0320@gmail.com> References: <1448597384-27976-1-git-send-email-ww.tao0320@gmail.com> Sender: linux-block-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-block@vger.kernel.org X-Spam-Status: No, score=-7.8 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP block creations of new targets, remove exiting targets when underlying device was gone. Signed-off-by: Wenwei Tao --- drivers/lightnvm/core.c | 128 +++++++++++++++++++++++++++++++---------------- include/linux/lightnvm.h | 3 ++ 2 files changed, 87 insertions(+), 44 deletions(-) diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index 071a3e4..984db2f 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -33,6 +33,17 @@ static LIST_HEAD(nvm_targets); static LIST_HEAD(nvm_mgrs); static LIST_HEAD(nvm_devices); static DECLARE_RWSEM(nvm_lock); +#define NVM_EXITING 1 + +static inline int NvmExiting(struct nvm_dev *dev) +{ + return ((unsigned long)dev->ppalist_pool & NVM_EXITING) != 0; +} + +static inline void *ppalist_pool(struct nvm_dev *dev) +{ + return (void *)((unsigned long)dev->ppalist_pool & ~NVM_EXITING); +} static struct nvm_tgt_type *nvm_find_target_type(const char *name) { @@ -74,7 +85,7 @@ EXPORT_SYMBOL(nvm_unregister_target); void *nvm_dev_dma_alloc(struct nvm_dev *dev, gfp_t mem_flags, dma_addr_t *dma_handler) { - return dev->ops->dev_dma_alloc(dev->q, dev->ppalist_pool, mem_flags, + return dev->ops->dev_dma_alloc(dev->q, ppalist_pool(dev), mem_flags, dma_handler); } EXPORT_SYMBOL(nvm_dev_dma_alloc); @@ -82,7 +93,7 @@ EXPORT_SYMBOL(nvm_dev_dma_alloc); void nvm_dev_dma_free(struct nvm_dev *dev, void *ppa_list, dma_addr_t dma_handler) { - dev->ops->dev_dma_free(dev->ppalist_pool, ppa_list, dma_handler); + dev->ops->dev_dma_free(ppalist_pool(dev), ppa_list, dma_handler); } EXPORT_SYMBOL(nvm_dev_dma_free); @@ -228,15 +239,6 @@ static int nvm_core_init(struct nvm_dev *dev) return 0; } -static void nvm_free(struct nvm_dev *dev) -{ - if (!dev) - return; - - if (dev->mt) - dev->mt->unregister_mgr(dev); -} - static int nvm_init(struct nvm_dev *dev) { int ret = -EINVAL; @@ -273,6 +275,7 @@ static int nvm_init(struct nvm_dev *dev) up_write(&nvm_lock); if (ret < 0) goto err; + kref_init(&dev->kref); if (!ret) return 0; @@ -286,12 +289,48 @@ err: return ret; } -static void nvm_exit(struct nvm_dev *dev) +static void nvm_remove_target(struct nvm_target *t) { - if (dev->ppalist_pool) - dev->ops->destroy_dma_pool(dev->ppalist_pool); - nvm_free(dev); + struct nvm_tgt_type *tt = t->type; + struct gendisk *tdisk = t->disk; + struct request_queue *q = tdisk->queue; + lockdep_assert_held(&nvm_lock); + + del_gendisk(tdisk); + if (tt->exit) + tt->exit(tdisk->private_data); + + blk_cleanup_queue(q); + + put_disk(tdisk); + + list_del(&t->list); + kfree(t); +} + +static inline void nvm_remove_targets(struct nvm_dev *dev) +{ + struct nvm_target *t, *n; + + list_for_each_entry_safe(t, n, &dev->online_targets, list) + nvm_remove_target(t); +} + +static void nvm_exit(struct kref *kref) +{ + struct nvm_dev *dev; + + dev = container_of(kref, struct nvm_dev, kref); + if (ppalist_pool(dev)) + dev->ops->destroy_dma_pool(ppalist_pool(dev)); + + if (dev->mt) + dev->mt->unregister_mgr(dev); + + if (dev->ops->dev_remove) + dev->ops->dev_remove(dev->q); + kfree(dev); pr_info("nvm: successfully unloaded\n"); } @@ -354,9 +393,10 @@ void nvm_unregister(char *disk_name) } list_del(&dev->devices); + nvm_remove_targets(dev); + dev->ppalist_pool += NVM_EXITING; up_write(&nvm_lock); - nvm_exit(dev); - kfree(dev); + kref_put(&dev->kref, nvm_exit); } EXPORT_SYMBOL(nvm_unregister); @@ -376,6 +416,10 @@ static int nvm_create_target(struct nvm_dev *dev, int ret = 0; down_write(&nvm_lock); + if (NvmExiting(dev)) { + up_write(&nvm_lock); + return -ENODEV; + } if (!dev->mt) { ret = register_mgr(dev); if (!ret) @@ -438,10 +482,18 @@ static int nvm_create_target(struct nvm_dev *dev, t->disk = tdisk; down_write(&nvm_lock); + if (NvmExiting(dev)) { + up_write(&nvm_lock); + goto err_nvm_exiting; + } list_add_tail(&t->list, &dev->online_targets); up_write(&nvm_lock); return 0; +err_nvm_exiting: + del_gendisk(tdisk); + if (tt->exit) + tt->exit(tdisk->private_data); err_init: put_disk(tdisk); err_queue: @@ -451,62 +503,50 @@ err_t: return -ENOMEM; } -static void nvm_remove_target(struct nvm_target *t) -{ - struct nvm_tgt_type *tt = t->type; - struct gendisk *tdisk = t->disk; - struct request_queue *q = tdisk->queue; - - lockdep_assert_held(&nvm_lock); - - del_gendisk(tdisk); - blk_cleanup_queue(q); - - if (tt->exit) - tt->exit(tdisk->private_data); - - put_disk(tdisk); - - list_del(&t->list); - kfree(t); -} - static int __nvm_configure_create(struct nvm_ioctl_create *create) { struct nvm_dev *dev; struct nvm_ioctl_create_simple *s; + int ret = -EINVAL; + down_write(&nvm_lock); dev = nvm_find_nvm_dev(create->dev); - up_write(&nvm_lock); if (!dev) { pr_err("nvm: device not found\n"); - return -EINVAL; + up_write(&nvm_lock); + goto out; } + kref_get(&dev->kref); + up_write(&nvm_lock); if (create->conf.type != NVM_CONFIG_TYPE_SIMPLE) { pr_err("nvm: config type not valid\n"); - return -EINVAL; + goto out; } s = &create->conf.s; if (s->lun_begin > s->lun_end || s->lun_end > dev->nr_luns) { pr_err("nvm: lun out of bound (%u:%u > %u)\n", s->lun_begin, s->lun_end, dev->nr_luns); - return -EINVAL; + goto out; } - return nvm_create_target(dev, create); + ret = nvm_create_target(dev, create); +out: + if (dev) + kref_put(&dev->kref, nvm_exit); + return ret; } static int __nvm_configure_remove(struct nvm_ioctl_remove *remove) { - struct nvm_target *t = NULL; + struct nvm_target *t, *n; struct nvm_dev *dev; int ret = -1; down_write(&nvm_lock); list_for_each_entry(dev, &nvm_devices, devices) - list_for_each_entry(t, &dev->online_targets, list) { + list_for_each_entry_safe(t, n, &dev->online_targets, list) { if (!strcmp(remove->tgtname, t->disk->disk_name)) { nvm_remove_target(t); ret = 0; diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h index 3db5552..6a365a2 100644 --- a/include/linux/lightnvm.h +++ b/include/linux/lightnvm.h @@ -189,6 +189,7 @@ typedef void (nvm_destroy_dma_pool_fn)(void *); typedef void *(nvm_dev_dma_alloc_fn)(struct request_queue *, void *, gfp_t, dma_addr_t *); typedef void (nvm_dev_dma_free_fn)(void *, void*, dma_addr_t); +typedef void (nvm_dev_remove_fn) (struct request_queue *); struct nvm_dev_ops { nvm_id_fn *identity; @@ -203,6 +204,7 @@ struct nvm_dev_ops { nvm_destroy_dma_pool_fn *destroy_dma_pool; nvm_dev_dma_alloc_fn *dev_dma_alloc; nvm_dev_dma_free_fn *dev_dma_free; + nvm_dev_remove_fn *dev_remove; unsigned int max_phys_sect; }; @@ -238,6 +240,7 @@ struct nvm_dev { /* Media manager */ struct nvmm_type *mt; + struct kref kref; void *mp; /* Device information */