From patchwork Mon Dec 19 23:30:47 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 9480881 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 6776560237 for ; Mon, 19 Dec 2016 23:31:00 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 591F42840E for ; Mon, 19 Dec 2016 23:31:00 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 4E0342841C; Mon, 19 Dec 2016 23:31:00 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 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.wl.linuxfoundation.org (Postfix) with ESMTPS id DE83C28410 for ; Mon, 19 Dec 2016 23:30:49 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id D759382113; Mon, 19 Dec 2016 15:30:49 -0800 (PST) X-Original-To: linux-nvdimm@lists.01.org Delivered-To: linux-nvdimm@lists.01.org Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id C54308210F for ; Mon, 19 Dec 2016 15:30:48 -0800 (PST) Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga104.fm.intel.com with ESMTP; 19 Dec 2016 15:30:48 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos; i="5.33,376,1477983600"; d="scan'208"; a="1101739592" Received: from djiang5-desk3.ch.intel.com ([143.182.137.38]) by fmsmga002.fm.intel.com with ESMTP; 19 Dec 2016 15:30:48 -0800 Subject: [PATCH v2 3/3] dev-dax: add fallocate support to clear poison From: Dave Jiang To: dan.j.williams@intel.com Date: Mon, 19 Dec 2016 16:30:47 -0700 Message-ID: <148219024781.15885.1883996216561314302.stgit@djiang5-desk3.ch.intel.com> In-Reply-To: <148219023506.15885.3919571427691230959.stgit@djiang5-desk3.ch.intel.com> References: <148219023506.15885.3919571427691230959.stgit@djiang5-desk3.ch.intel.com> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-BeenThere: linux-nvdimm@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Linux-nvdimm developer list." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: linux-nvdimm@lists.01.org Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP Adding fallocate support to device-dax. This implements FALLOC_FL_PUNCH_HOLE in order to allow clearing of badblocks/poison list. Signed-off-by: Dave Jiang --- drivers/dax/dax-private.h | 1 + drivers/dax/dax.c | 24 +++++++++++++++- drivers/dax/dax.h | 4 ++- drivers/dax/pmem.c | 68 ++++++++++++++++++++++++++++++++++++++++++++- fs/open.c | 2 + 5 files changed, 95 insertions(+), 4 deletions(-) diff --git a/drivers/dax/dax-private.h b/drivers/dax/dax-private.h index a119ef9..aea927d 100644 --- a/drivers/dax/dax-private.h +++ b/drivers/dax/dax-private.h @@ -38,6 +38,7 @@ struct dax_dev { int num_resources; struct resource res[0]; void *private; + const struct file_operations *fops; }; #endif diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c index f1857e6..b5cd73e 100644 --- a/drivers/dax/dax.c +++ b/drivers/dax/dax.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "dax.h" #include "dax-private.h" @@ -314,6 +315,12 @@ void *dax_dev_get_private(struct device *dev) } EXPORT_SYMBOL_GPL(dax_dev_get_private); +struct device *dax_dev_get_device(struct dax_dev *dax_dev) +{ + return &dax_dev->dev; +} +EXPORT_SYMBOL_GPL(dax_dev_get_device); + void dax_dev_set_private(struct dax_dev *dax_dev, void *priv) { dax_dev->private = priv; @@ -606,6 +613,17 @@ static int dax_release(struct inode *inode, struct file *filp) return 0; } +static long dax_fallocate(struct file *file, int mode, + loff_t offset, loff_t len) +{ + struct dax_dev *dax_dev = file->private_data; + + if (dax_dev->fops) + return dax_dev->fops->fallocate(file, mode, offset, len); + + return -EOPNOTSUPP; +} + static const struct file_operations dax_fops = { .llseek = noop_llseek, .owner = THIS_MODULE, @@ -613,6 +631,7 @@ static const struct file_operations dax_fops = { .release = dax_release, .get_unmapped_area = dax_get_unmapped_area, .mmap = dax_mmap, + .fallocate = dax_fallocate, }; static void dax_dev_release(struct device *dev) @@ -650,7 +669,8 @@ static void unregister_dax_dev(void *dev) struct dax_dev *devm_create_dax_dev(struct dax_region *dax_region, struct resource *res, int count, - const struct attribute_group **groups) + const struct attribute_group **groups, + const struct file_operations *fops) { struct device *parent = dax_region->dev; struct dax_dev *dax_dev; @@ -730,6 +750,8 @@ struct dax_dev *devm_create_dax_dev(struct dax_region *dax_region, if (rc) return ERR_PTR(rc); + dax_dev->fops = fops; + return dax_dev; err_cdev: diff --git a/drivers/dax/dax.h b/drivers/dax/dax.h index c23c7ac..6a31a74 100644 --- a/drivers/dax/dax.h +++ b/drivers/dax/dax.h @@ -24,8 +24,10 @@ struct dax_region *alloc_dax_region(struct device *parent, void *addr, unsigned long flags); struct dax_dev *devm_create_dax_dev(struct dax_region *dax_region, struct resource *res, int count, - const struct attribute_group **groups); + const struct attribute_group **groups, + const struct file_operations *fops); void *dax_dev_get_private(struct device *dev); void dax_dev_set_private(struct dax_dev *dax_dev, void *priv); +struct device *dax_dev_get_device(struct dax_dev *dax_dev); #endif /* __DAX_H__ */ diff --git a/drivers/dax/pmem.c b/drivers/dax/pmem.c index 5ffb2e9..5ab4900 100644 --- a/drivers/dax/pmem.c +++ b/drivers/dax/pmem.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "../nvdimm/pfn.h" #include "../nvdimm/nd.h" #include "dax.h" @@ -24,6 +25,69 @@ struct dax_pmem { struct percpu_ref ref; struct completion cmp; struct badblocks bb; + resource_size_t start; + resource_size_t end; +}; + +static void dax_pmem_clear_poison(struct dax_pmem *dax_pmem, + loff_t offset, loff_t len) +{ + sector_t sector; + long cleared; + + sector = offset >> 9; + cleared = nvdimm_clear_poison(dax_pmem->dev, + dax_pmem->start + offset, len); + + if ((cleared > 0) && (cleared >> 9)) { + dev_dbg(dax_pmem->dev, "%s: %#llx clear %ld sector%s\n", + __func__, (unsigned long long)sector, + cleared >> 9, cleared >> 9 > 1 ? "s" : ""); + badblocks_clear(&dax_pmem->bb, sector, cleared >> 9); + } +} + +static long dax_pmem_fallocate(struct file *file, int mode, + loff_t start, loff_t len) +{ + struct dax_dev *dax_dev = file->private_data; + struct device *dev; + struct dax_pmem *dax_pmem; + loff_t end = start + len - 1; + loff_t res_size; + + dev = dax_dev_get_device(dax_dev); + dax_pmem = dax_dev_get_private(dev); + res_size = dax_pmem->end - dax_pmem->start + 1; + + dev_dbg(dev, "fallocate mode: %#x, start: %#llx, len: %llu\n", + mode, start, len); + dev_dbg(dev, "res start: %#llx end: %#llx size: %llu\n", + dax_pmem->start, dax_pmem->end, res_size); + + /* check size boundares */ + if (start >= dax_pmem->end) + return -EINVAL; + if (end >= res_size) { + if (mode & FALLOC_FL_KEEP_SIZE) + len = res_size - start; + else + return -EINVAL; + } + + switch (mode) { + case FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE: + dax_pmem_clear_poison(dax_pmem, start, len); + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static const struct file_operations pmem_fops = { + .fallocate = dax_pmem_fallocate, }; static ssize_t dax_pmem_badblocks_show(struct device *dev, @@ -158,8 +222,10 @@ static int dax_pmem_probe(struct device *dev) /* TODO: support for subdividing a dax region... */ dax_dev = devm_create_dax_dev(dax_region, &res, 1, - dax_pmem_attribute_groups); + dax_pmem_attribute_groups, &pmem_fops); dax_dev_set_private(dax_dev, dax_pmem); + dax_pmem->start = res.start; + dax_pmem->end = res.end; rc = devm_init_badblocks(dev, &dax_pmem->bb); if (rc) diff --git a/fs/open.c b/fs/open.c index d3ed817..15325fd 100644 --- a/fs/open.c +++ b/fs/open.c @@ -306,7 +306,7 @@ int vfs_fallocate(struct file *file, int mode, loff_t offset, loff_t len) * for directories or not. */ if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode) && - !S_ISBLK(inode->i_mode)) + !S_ISBLK(inode->i_mode) && !S_ISCHR(inode->i_mode)) return -ENODEV; /* Check for wrap through zero too */