From patchwork Thu Feb 4 11:34:45 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wenwei Tao X-Patchwork-Id: 8220121 Return-Path: X-Original-To: patchwork-linux-block@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id E5DD99F3CD for ; Thu, 4 Feb 2016 11:38:58 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id C985B20390 for ; Thu, 4 Feb 2016 11:38:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 869542038E for ; Thu, 4 Feb 2016 11:38:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752327AbcBDLid (ORCPT ); Thu, 4 Feb 2016 06:38:33 -0500 Received: from mail-pf0-f194.google.com ([209.85.192.194]:35442 "EHLO mail-pf0-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756718AbcBDLfz (ORCPT ); Thu, 4 Feb 2016 06:35:55 -0500 Received: by mail-pf0-f194.google.com with SMTP id 66so3245823pfe.2; Thu, 04 Feb 2016 03:35:55 -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; bh=9DW8gLWH4rJV5rKvllJKGxqb2bUxQh/WkZelNtGcBBE=; b=bPlWXIacuTWms4gkAKKhDrYNg904eruC5PNAZrU4FWTXCXB01qu0VGeHAzIbMBVzUY NKW3O7KHz6+d9C3cEKqfZXBXTDLD45kY+GHSHUxkX+AWS0jT39W1CZJbWVVc1nViSX0F Yojg57eNkw1XeuzA9GYeDKkoPkGMqlBXKXxNzCHwTzrZbcogOK39ptB8U4IS87Kwp12K DODG110Zj9+6IWuJBXcRC+xQom5XsQv/pC4a1uKTzTylG+H1RQish8H6fUsiHZ3aqTBh GhXBhynn4iO/l5cJUaOgsMRHaxIotRGkptLYRe2YLIj8Gbx+Hlyg3kuu+zLbfCRAMXx3 WjIg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=9DW8gLWH4rJV5rKvllJKGxqb2bUxQh/WkZelNtGcBBE=; b=SNVZlse7vDOoYWZX6QvZvUbsNoSAZbgsN+zezbLgAu4wF8SlIi6HupDToAk6x1gLDt AQ0Is1eUxzjTlEj4x9zyQWvug6ticJ2Jx3Ft/gGLzJr3zcAG1P6NVp/Tsog56zDxe6uZ PPi6JMW1lOUp86r1xKMWXeOzGj1hW/nLa9L0/NWRHDCrCcRX/dK/135MYq7v5sANi5Vw Usnw4IGGNwWjmE+eK2JGIPoUJWpGMJ7gDeDCGqSirBbrvEDkfRwOXLG1TzPJGZ+zg4Fs 54MNi9U3V+SgaAGTMIpIt0rKCOQdmNUICc/cJyRyzyJY/Ib2b8/pNy983Lr2l+y2jV3T JDVw== X-Gm-Message-State: AG10YOSjtbgJAGYe06Lthc/Ub34N/E9MMXvL+VWCHvUEePgE7HC9dBbSxKBG/FPPR3wHvQ== X-Received: by 10.98.75.22 with SMTP id y22mr10259801pfa.147.1454585755299; Thu, 04 Feb 2016 03:35:55 -0800 (PST) Received: from localhost.localdomain ([2002:6fc4:c08a::6fc4:c08a]) by smtp.gmail.com with ESMTPSA id cf6sm16474990pad.41.2016.02.04.03.35.50 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 04 Feb 2016 03:35:54 -0800 (PST) From: Wenwei Tao To: mb@lightnvm.io Cc: linux-kernel@vger.kernel.org, linux-block@vger.kernel.org Subject: [PATCH v3 1/3] lightnvm: specify target's logical address area Date: Thu, 4 Feb 2016 19:34:45 +0800 Message-Id: <1454585687-4720-1-git-send-email-ww.tao0320@gmail.com> X-Mailer: git-send-email 2.5.1.windows.1 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.2 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 We can create more than one target on a lightnvm device by specifying its begin lun and end lun. But only specify the physical address area is not enough, we need to get the corresponding non- intersection logical address area division from the backend device's logcial address space. Otherwise the targets on the device might use the same logical addresses cause incorrect information in the device's l2p table. Signed-off-by: Wenwei Tao --- Changes since v2: -rebase on for-next branch -make the list increase by area->begin Changes since v1: -rename some variables -add parentheses for clarify -make gennvm_get_area return int, and add one more sector_t* parameter to pass the begin sector of the corresponding target -rebase to v4.5-rc1 drivers/lightnvm/core.c | 1 + drivers/lightnvm/gennvm.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/lightnvm/gennvm.h | 6 +++++ drivers/lightnvm/rrpc.c | 36 +++++++++++++++++++++++--- drivers/lightnvm/rrpc.h | 1 + include/linux/lightnvm.h | 8 ++++++ 6 files changed, 114 insertions(+), 3 deletions(-) diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index 5471cc5..93c035b 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -466,6 +466,7 @@ static int nvm_core_init(struct nvm_dev *dev) dev->total_secs = dev->nr_luns * dev->sec_per_lun; INIT_LIST_HEAD(&dev->online_targets); mutex_init(&dev->mlock); + spin_lock_init(&dev->lock); return 0; } diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c index d65ec36..fba3fbd 100644 --- a/drivers/lightnvm/gennvm.c +++ b/drivers/lightnvm/gennvm.c @@ -20,6 +20,66 @@ #include "gennvm.h" +static int gennvm_get_area(struct nvm_dev *dev, sector_t *begin_sect, + sector_t size) +{ + struct gen_nvm *gn = dev->mp; + struct gennvm_area *area, *prev, *next; + sector_t begin = 0; + sector_t max_sectors = (dev->sec_size * dev->total_secs) >> 9; + + if (size > max_sectors) + return -EINVAL; + area = kmalloc(sizeof(struct gennvm_area), GFP_KERNEL); + if (!area) + return -ENOMEM; + + prev = NULL; + + spin_lock(&dev->lock); + list_for_each_entry(next, &gn->area_list, list) { + if (begin + size > next->begin) { + begin = next->end; + prev = next; + continue; + } + break; + } + + if ((begin + size) > max_sectors) { + spin_unlock(&dev->lock); + kfree(area); + return -EINVAL; + } + + area->begin = *begin_sect = begin; + area->end = begin + size; + if (prev) + list_add(&area->list, &prev->list); + else + list_add(&area->list, &gn->area_list); + spin_unlock(&dev->lock); + return 0; +} + +static void gennvm_put_area(struct nvm_dev *dev, sector_t begin) +{ + struct gen_nvm *gn = dev->mp; + struct gennvm_area *area; + + spin_lock(&dev->lock); + list_for_each_entry(area, &gn->area_list, list) { + if (area->begin != begin) + continue; + + list_del(&area->list); + spin_unlock(&dev->lock); + kfree(area); + return; + } + spin_unlock(&dev->lock); +} + static void gennvm_blocks_free(struct nvm_dev *dev) { struct gen_nvm *gn = dev->mp; @@ -229,6 +289,7 @@ static int gennvm_register(struct nvm_dev *dev) gn->dev = dev; gn->nr_luns = dev->nr_luns; + INIT_LIST_HEAD(&gn->area_list); dev->mp = gn; ret = gennvm_luns_init(dev, gn); @@ -465,6 +526,10 @@ static struct nvmm_type gennvm = { .get_lun = gennvm_get_lun, .lun_info_print = gennvm_lun_info_print, + + .get_area = gennvm_get_area, + .put_area = gennvm_put_area, + }; static int __init gennvm_module_init(void) diff --git a/drivers/lightnvm/gennvm.h b/drivers/lightnvm/gennvm.h index 9c24b5b..04d7c23 100644 --- a/drivers/lightnvm/gennvm.h +++ b/drivers/lightnvm/gennvm.h @@ -39,8 +39,14 @@ struct gen_nvm { int nr_luns; struct gen_lun *luns; + struct list_head area_list; }; +struct gennvm_area { + struct list_head list; + sector_t begin; + sector_t end; /* end is excluded */ +}; #define gennvm_for_each_lun(bm, lun, i) \ for ((i) = 0, lun = &(bm)->luns[0]; \ (i) < (bm)->nr_luns; (i)++, lun = &(bm)->luns[(i)]) diff --git a/drivers/lightnvm/rrpc.c b/drivers/lightnvm/rrpc.c index c4d0b04..6ce5f73 100644 --- a/drivers/lightnvm/rrpc.c +++ b/drivers/lightnvm/rrpc.c @@ -1038,8 +1038,11 @@ static int rrpc_map_init(struct rrpc *rrpc) { struct nvm_dev *dev = rrpc->dev; sector_t i; + u64 slba; int ret; + slba = rrpc->soffset >> (ilog2(dev->sec_size) - 9); + rrpc->trans_map = vzalloc(sizeof(struct rrpc_addr) * rrpc->nr_sects); if (!rrpc->trans_map) return -ENOMEM; @@ -1061,8 +1064,8 @@ static int rrpc_map_init(struct rrpc *rrpc) return 0; /* Bring up the mapping table from device */ - ret = dev->ops->get_l2p_tbl(dev, 0, dev->total_secs, rrpc_l2p_update, - rrpc); + ret = dev->ops->get_l2p_tbl(dev, slba, rrpc->nr_sects, + rrpc_l2p_update, rrpc); if (ret) { pr_err("nvm: rrpc: could not read L2P table.\n"); return -EINVAL; @@ -1071,7 +1074,6 @@ static int rrpc_map_init(struct rrpc *rrpc) return 0; } - /* Minimum pages needed within a lun */ #define PAGE_POOL_SIZE 16 #define ADDR_POOL_SIZE 64 @@ -1185,12 +1187,32 @@ err: return -ENOMEM; } +/* returns 0 on success and stores the beginning address in *begin */ +static int rrpc_area_init(struct rrpc *rrpc, sector_t *begin) +{ + struct nvm_dev *dev = rrpc->dev; + struct nvmm_type *mt = dev->mt; + sector_t size = rrpc->nr_sects * dev->sec_size; + + size >>= 9; + return mt->get_area(dev, begin, size); +} + +static void rrpc_area_free(struct rrpc *rrpc) +{ + struct nvm_dev *dev = rrpc->dev; + struct nvmm_type *mt = dev->mt; + + mt->put_area(dev, rrpc->soffset); +} + static void rrpc_free(struct rrpc *rrpc) { rrpc_gc_free(rrpc); rrpc_map_free(rrpc); rrpc_core_free(rrpc); rrpc_luns_free(rrpc); + rrpc_area_free(rrpc); kfree(rrpc); } @@ -1311,6 +1333,7 @@ static void *rrpc_init(struct nvm_dev *dev, struct gendisk *tdisk, struct request_queue *bqueue = dev->q; struct request_queue *tqueue = tdisk->queue; struct rrpc *rrpc; + sector_t soffset; int ret; if (!(dev->identity.dom & NVM_RSP_L2P)) { @@ -1336,6 +1359,13 @@ static void *rrpc_init(struct nvm_dev *dev, struct gendisk *tdisk, /* simple round-robin strategy */ atomic_set(&rrpc->next_lun, -1); + ret = rrpc_area_init(rrpc, &soffset); + if (ret < 0) { + pr_err("nvm: rrpc: could not initialize area\n"); + return ERR_PTR(ret); + } + rrpc->soffset = soffset; + ret = rrpc_luns_init(rrpc, lun_begin, lun_end); if (ret) { pr_err("nvm: rrpc: could not initialize luns\n"); diff --git a/drivers/lightnvm/rrpc.h b/drivers/lightnvm/rrpc.h index dfca5c4..6148b14 100644 --- a/drivers/lightnvm/rrpc.h +++ b/drivers/lightnvm/rrpc.h @@ -97,6 +97,7 @@ struct rrpc { struct nvm_dev *dev; struct gendisk *disk; + sector_t soffset; /* logical sector offset */ u64 poffset; /* physical page offset */ int lun_offset; diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h index b94f2d5..ce58ad5 100644 --- a/include/linux/lightnvm.h +++ b/include/linux/lightnvm.h @@ -351,6 +351,7 @@ struct nvm_dev { char name[DISK_NAME_LEN]; struct mutex mlock; + spinlock_t lock; }; static inline struct ppa_addr generic_to_dev_addr(struct nvm_dev *dev, @@ -463,6 +464,9 @@ typedef int (nvmm_erase_blk_fn)(struct nvm_dev *, struct nvm_block *, typedef struct nvm_lun *(nvmm_get_lun_fn)(struct nvm_dev *, int); typedef void (nvmm_lun_info_print_fn)(struct nvm_dev *); +typedef int (nvmm_get_area_fn)(struct nvm_dev *, sector_t *, sector_t); +typedef void (nvmm_put_area_fn)(struct nvm_dev *, sector_t); + struct nvmm_type { const char *name; unsigned int version[3]; @@ -487,6 +491,10 @@ struct nvmm_type { /* Statistics */ nvmm_lun_info_print_fn *lun_info_print; + + nvmm_get_area_fn *get_area; + nvmm_put_area_fn *put_area; + struct list_head list; };