From patchwork Sun Dec 20 09:18:42 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vishal Verma X-Patchwork-Id: 7891471 Return-Path: X-Original-To: patchwork-linux-nvdimm@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 D6707BEEE5 for ; Sun, 20 Dec 2015 09:19:29 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id DA0652041A for ; Sun, 20 Dec 2015 09:19:28 +0000 (UTC) Received: from ml01.01.org (ml01.01.org [198.145.21.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 2121720481 for ; Sun, 20 Dec 2015 09:19:27 +0000 (UTC) Received: from ml01.vlan14.01.org (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 176611A1FD0; Sun, 20 Dec 2015 01:19:27 -0800 (PST) X-Original-To: linux-nvdimm@lists.01.org Delivered-To: linux-nvdimm@lists.01.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by ml01.01.org (Postfix) with ESMTP id 8AF0E1A1F7D for ; Sun, 20 Dec 2015 01:19:25 -0800 (PST) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id BDDB02041D; Sun, 20 Dec 2015 09:19:24 +0000 (UTC) Received: from gamestarV3L.home. (71-212-131-94.hlrn.qwest.net [71.212.131.94]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 406952047D; Sun, 20 Dec 2015 09:19:23 +0000 (UTC) From: vishal@kernel.org To: linux-nvdimm@lists.01.org Subject: [PATCH 3/3] pmem: Use the poison list to expose badblocks Date: Sun, 20 Dec 2015 02:18:42 -0700 Message-Id: <1450603122-7205-4-git-send-email-vishal@kernel.org> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1450603122-7205-1-git-send-email-vishal@kernel.org> References: <1450603122-7205-1-git-send-email-vishal@kernel.org> X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW, RP_MATCHES_RCVD, 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 Cc: linux-acpi@vger.kernel.org, linux-fsdevel@vger.kernel.org X-BeenThere: linux-nvdimm@lists.01.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: "Linux-nvdimm developer list." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP From: Vishal Verma Enable the gendisk badblocks feature for pmem namespaces. If the pmem namespace being created has any known poison associated with its physical address space, convert the poison ranges to bad sectors exposed using the badblocks interface. Signed-off-by: Vishal Verma --- drivers/nvdimm/pmem.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index 8ee7989..462570f 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -19,14 +19,18 @@ #include #include #include +#include #include #include #include #include +#include #include +#include #include #include #include +#include "nd-core.h" #include "pfn.h" #include "nd.h" @@ -163,11 +167,122 @@ static void pmem_detach_disk(struct pmem_device *pmem) blk_cleanup_queue(pmem->pmem_queue); } +/** + * pmem_add_badblock_range() - Convert a physical address range to bad sectors + * @disk: the disk associated with the pmem namespace + * @start: start of the physical address range + * @length: number of bytes of poison to be added + * + * This assumes that the range provided with (start, length) is already within + * the bounds of physical addresses for this namespace, i.e. lies in the + * interval [pmem->phys_addr, pmem->phys_addr + pmem->size) + */ +static int pmem_add_badblock_range(struct gendisk *disk, u64 start, u64 length) +{ + unsigned int sector_size = queue_logical_block_size(disk->queue); + struct pmem_device *pmem = disk->private_data; + sector_t start_sector; + u64 num_sectors; + u32 rem; + + start_sector = div_u64(start - pmem->phys_addr, sector_size); + num_sectors = div_u64_rem(length, sector_size, &rem); + if (rem) + num_sectors++; + + if (unlikely(num_sectors > (u64)INT_MAX)) { + u64 remaining = num_sectors; + sector_t s = start_sector; + int rc; + + while (remaining) { + int done = min_t(u64, remaining, INT_MAX); + + rc = disk_set_badblocks(disk, s, done); + if (rc) + return rc; + remaining -= done; + s += done; + } + return 0; + } else + return disk_set_badblocks(disk, start_sector, num_sectors); +} + +/* + * The poison list generated during NFIT initialization may contain multiple, + * possibly overlapping ranges in the SPA (System Physical Address) space. + * Compare each of these ranges to the pmem namespace currently being + * initialized, and add badblocks for the sub-ranges that match + */ +static int pmem_add_poison(struct gendisk *disk, struct nvdimm_bus *nvdimm_bus) +{ + struct pmem_device *pmem = disk->private_data; + struct list_head *poison_list; + struct nd_poison *pl; + int rc; + + poison_list = nvdimm_bus_get_poison_list(nvdimm_bus); + if (list_empty(poison_list)) + return 0; + + list_for_each_entry(pl, poison_list, list) { + u64 pl_end = pl->start + pl->length - 1; + u64 pmem_end = pmem->phys_addr + pmem->size - 1; + + /* Discard intervals with no intersection */ + if (pl_end < pmem->phys_addr) + continue; + if (pl->start > pmem_end) + continue; + /* Deal with any overlap after start of the pmem range */ + if (pl->start >= pmem->phys_addr) { + u64 start = pl->start; + u64 len; + + if (pl_end <= pmem_end) + len = pl->length; + else + len = pmem->phys_addr + pmem->size - pl->start; + + rc = pmem_add_badblock_range(disk, start, len); + if (rc) + return rc; + dev_info(&nvdimm_bus->dev, + "Found a poison range (0x%llx, 0x%llx)\n", + start, len); + continue; + } + /* Deal with overlap for poison starting before pmem range */ + if (pl->start < pmem->phys_addr) { + u64 start = pmem->phys_addr; + u64 len; + + if (pl_end < pmem_end) + len = pl->start + pl->length - pmem->phys_addr; + else + len = pmem->size; + + rc = pmem_add_badblock_range(disk, start, len); + if (rc) + return rc; + dev_info(&nvdimm_bus->dev, + "Found a poison range (0x%llx, 0x%llx)\n", + start, len); + } + } + + return 0; +} + static int pmem_attach_disk(struct device *dev, struct nd_namespace_common *ndns, struct pmem_device *pmem) { + struct nd_region *nd_region = to_nd_region(dev->parent); + struct nvdimm_bus *nvdimm_bus; int nid = dev_to_node(dev); struct gendisk *disk; + int ret; pmem->pmem_queue = blk_alloc_queue_node(GFP_KERNEL, nid); if (!pmem->pmem_queue) @@ -196,6 +311,15 @@ static int pmem_attach_disk(struct device *dev, set_capacity(disk, (pmem->size - pmem->data_offset) / 512); pmem->pmem_disk = disk; + ret = disk_alloc_badblocks(disk); + if (ret) + return ret; + + nvdimm_bus = to_nvdimm_bus(nd_region->dev.parent); + ret = pmem_add_poison(disk, nvdimm_bus); + if (ret) + return ret; + add_disk(disk); revalidate_disk(disk);