Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

device-dax: Add /sys/class/dax backwards compatibility

On the expectation that some environments may not upgrade libdaxctl
(userspace component that depends on the /sys/class/dax hierarchy),
provide a default / legacy dax_pmem_compat driver. The dax_pmem_compat
driver implements the original /sys/class/dax sysfs layout rather than
/sys/bus/dax. When userspace is upgraded it can blacklist this module
and switch to the dax_pmem driver going forward.

CONFIG_DEV_DAX_PMEM_COMPAT and supporting code will be deleted according
to the dax_pmem entry in Documentation/ABI/obsolete/.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+229 -50
+22
Documentation/ABI/obsolete/sysfs-class-dax
··· 1 + What: /sys/class/dax/ 2 + Date: May, 2016 3 + KernelVersion: v4.7 4 + Contact: linux-nvdimm@lists.01.org 5 + Description: Device DAX is the device-centric analogue of Filesystem 6 + DAX (CONFIG_FS_DAX). It allows memory ranges to be 7 + allocated and mapped without need of an intervening file 8 + system. Device DAX is strict, precise and predictable. 9 + Specifically this interface: 10 + 11 + 1/ Guarantees fault granularity with respect to a given 12 + page size (pte, pmd, or pud) set at configuration time. 13 + 14 + 2/ Enforces deterministic behavior by being strict about 15 + what fault scenarios are supported. 16 + 17 + The /sys/class/dax/ interface enumerates all the 18 + device-dax instances in the system. The ABI is 19 + deprecated and will be removed after 2020. It is 20 + replaced with the DAX bus interface /sys/bus/dax/ where 21 + device-dax instances can be found under 22 + /sys/bus/dax/devices/
+11 -1
drivers/dax/Kconfig
··· 23 23 config DEV_DAX_PMEM 24 24 tristate "PMEM DAX: direct access to persistent memory" 25 25 depends on LIBNVDIMM && NVDIMM_DAX && DEV_DAX 26 + depends on m # until we can kill DEV_DAX_PMEM_COMPAT 26 27 default DEV_DAX 27 28 help 28 29 Support raw access to persistent memory. Note that this 29 30 driver consumes memory ranges allocated and exported by the 30 31 libnvdimm sub-system. 31 32 32 - Say Y if unsure 33 + Say M if unsure 34 + 35 + config DEV_DAX_PMEM_COMPAT 36 + tristate "PMEM DAX: support the deprecated /sys/class/dax interface" 37 + depends on DEV_DAX_PMEM 38 + default DEV_DAX_PMEM 39 + help 40 + Older versions of the libdaxctl library expect to find all 41 + device-dax instances under /sys/class/dax. If libdaxctl in 42 + your distribution is older than v58 say M, otherwise say N. 33 43 34 44 endif
+2 -2
drivers/dax/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 obj-$(CONFIG_DAX) += dax.o 3 3 obj-$(CONFIG_DEV_DAX) += device_dax.o 4 - obj-$(CONFIG_DEV_DAX_PMEM) += dax_pmem.o 5 4 6 5 dax-y := super.o 7 6 dax-y += bus.o 8 - dax_pmem-y := pmem.o 9 7 device_dax-y := device.o 8 + 9 + obj-y += pmem/
+24 -5
drivers/dax/bus.c
··· 9 9 #include "dax-private.h" 10 10 #include "bus.h" 11 11 12 + static struct class *dax_class; 13 + 12 14 static DEFINE_MUTEX(dax_bus_lock); 13 15 14 16 #define DAX_NAME_LEN 30 ··· 312 310 put_device(dev); 313 311 } 314 312 315 - struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id, 316 - struct dev_pagemap *pgmap) 313 + struct dev_dax *__devm_create_dev_dax(struct dax_region *dax_region, int id, 314 + struct dev_pagemap *pgmap, enum dev_dax_subsys subsys) 317 315 { 318 316 struct device *parent = dax_region->dev; 319 317 struct dax_device *dax_dev; ··· 352 350 353 351 inode = dax_inode(dax_dev); 354 352 dev->devt = inode->i_rdev; 355 - dev->bus = &dax_bus_type; 353 + if (subsys == DEV_DAX_BUS) 354 + dev->bus = &dax_bus_type; 355 + else 356 + dev->class = dax_class; 356 357 dev->parent = parent; 357 358 dev->groups = dax_attribute_groups; 358 359 dev->release = dev_dax_release; ··· 379 374 380 375 return ERR_PTR(rc); 381 376 } 382 - EXPORT_SYMBOL_GPL(devm_create_dev_dax); 377 + EXPORT_SYMBOL_GPL(__devm_create_dev_dax); 383 378 384 379 static int match_always_count; 385 380 ··· 412 407 413 408 void dax_driver_unregister(struct dax_device_driver *dax_drv) 414 409 { 410 + struct device_driver *drv = &dax_drv->drv; 415 411 struct dax_id *dax_id, *_id; 416 412 417 413 mutex_lock(&dax_bus_lock); ··· 422 416 kfree(dax_id); 423 417 } 424 418 mutex_unlock(&dax_bus_lock); 419 + driver_unregister(drv); 425 420 } 426 421 EXPORT_SYMBOL_GPL(dax_driver_unregister); 427 422 428 423 int __init dax_bus_init(void) 429 424 { 430 - return bus_register(&dax_bus_type); 425 + int rc; 426 + 427 + if (IS_ENABLED(CONFIG_DEV_DAX_PMEM_COMPAT)) { 428 + dax_class = class_create(THIS_MODULE, "dax"); 429 + if (IS_ERR(dax_class)) 430 + return PTR_ERR(dax_class); 431 + } 432 + 433 + rc = bus_register(&dax_bus_type); 434 + if (rc) 435 + class_destroy(dax_class); 436 + return rc; 431 437 } 432 438 433 439 void __exit dax_bus_exit(void) 434 440 { 435 441 bus_unregister(&dax_bus_type); 442 + class_destroy(dax_class); 436 443 }
+23 -3
drivers/dax/bus.h
··· 2 2 /* Copyright(c) 2016 - 2018 Intel Corporation. All rights reserved. */ 3 3 #ifndef __DAX_BUS_H__ 4 4 #define __DAX_BUS_H__ 5 - struct device; 5 + #include <linux/device.h> 6 + 6 7 struct dev_dax; 7 8 struct resource; 8 9 struct dax_device; ··· 11 10 void dax_region_put(struct dax_region *dax_region); 12 11 struct dax_region *alloc_dax_region(struct device *parent, int region_id, 13 12 struct resource *res, unsigned int align, unsigned long flags); 14 - struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id, 15 - struct dev_pagemap *pgmap); 13 + 14 + enum dev_dax_subsys { 15 + DEV_DAX_BUS, 16 + DEV_DAX_CLASS, 17 + }; 18 + 19 + struct dev_dax *__devm_create_dev_dax(struct dax_region *dax_region, int id, 20 + struct dev_pagemap *pgmap, enum dev_dax_subsys subsys); 21 + 22 + static inline struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, 23 + int id, struct dev_pagemap *pgmap) 24 + { 25 + return __devm_create_dev_dax(dax_region, id, pgmap, DEV_DAX_BUS); 26 + } 27 + 28 + /* to be deleted when DEV_DAX_CLASS is removed */ 29 + struct dev_dax *__dax_pmem_probe(struct device *dev, enum dev_dax_subsys subsys); 16 30 17 31 struct dax_device_driver { 18 32 struct device_driver drv; ··· 41 25 __dax_driver_register(driver, THIS_MODULE, KBUILD_MODNAME) 42 26 void dax_driver_unregister(struct dax_device_driver *dax_drv); 43 27 void kill_dev_dax(struct dev_dax *dev_dax); 28 + 29 + #if IS_ENABLED(CONFIG_DEV_DAX_PMEM_COMPAT) 30 + int dev_dax_probe(struct device *dev); 31 + #endif 44 32 45 33 /* 46 34 * While run_dax() is potentially a generic operation that could be
+7 -2
drivers/dax/device.c
··· 445 445 kill_dev_dax(dev_dax); 446 446 } 447 447 448 - static int dev_dax_probe(struct device *dev) 448 + int dev_dax_probe(struct device *dev) 449 449 { 450 450 struct dev_dax *dev_dax = to_dev_dax(dev); 451 451 struct dax_device *dax_dev = dev_dax->dax_dev; ··· 484 484 inode = dax_inode(dax_dev); 485 485 cdev = inode->i_cdev; 486 486 cdev_init(cdev, &dax_fops); 487 - cdev->owner = dev->driver->owner; 487 + if (dev->class) { 488 + /* for the CONFIG_DEV_DAX_PMEM_COMPAT case */ 489 + cdev->owner = dev->parent->driver->owner; 490 + } else 491 + cdev->owner = dev->driver->owner; 488 492 cdev_set_parent(cdev, &dev->kobj); 489 493 rc = cdev_add(cdev, dev->devt, 1); 490 494 if (rc) ··· 501 497 run_dax(dax_dev); 502 498 return devm_add_action_or_reset(dev, dev_dax_kill, dev_dax); 503 499 } 500 + EXPORT_SYMBOL_GPL(dev_dax_probe); 504 501 505 502 static int dev_dax_remove(struct device *dev) 506 503 {
+15 -36
drivers/dax/pmem.c drivers/dax/pmem/core.c
··· 1 - /* 2 - * Copyright(c) 2016 Intel Corporation. All rights reserved. 3 - * 4 - * This program is free software; you can redistribute it and/or modify 5 - * it under the terms of version 2 of the GNU General Public License as 6 - * published by the Free Software Foundation. 7 - * 8 - * This program is distributed in the hope that it will be useful, but 9 - * WITHOUT ANY WARRANTY; without even the implied warranty of 10 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 - * General Public License for more details. 12 - */ 13 - #include <linux/percpu-refcount.h> 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright(c) 2016 - 2018 Intel Corporation. All rights reserved. */ 14 3 #include <linux/memremap.h> 15 4 #include <linux/module.h> 16 5 #include <linux/pfn_t.h> 17 - #include "../nvdimm/pfn.h" 18 - #include "../nvdimm/nd.h" 19 - #include "bus.h" 6 + #include "../../nvdimm/pfn.h" 7 + #include "../../nvdimm/nd.h" 8 + #include "../bus.h" 20 9 21 - static int dax_pmem_probe(struct device *dev) 10 + struct dev_dax *__dax_pmem_probe(struct device *dev, enum dev_dax_subsys subsys) 22 11 { 23 12 struct resource res; 24 13 int rc, id, region_id; ··· 23 34 24 35 ndns = nvdimm_namespace_common_probe(dev); 25 36 if (IS_ERR(ndns)) 26 - return PTR_ERR(ndns); 37 + return ERR_CAST(ndns); 27 38 nsio = to_nd_namespace_io(&ndns->dev); 28 39 29 40 /* parse the 'pfn' info block via ->rw_bytes */ 30 41 rc = devm_nsio_enable(dev, nsio); 31 42 if (rc) 32 - return rc; 43 + return ERR_PTR(rc); 33 44 rc = nvdimm_setup_pfn(nd_pfn, &pgmap); 34 45 if (rc) 35 - return rc; 46 + return ERR_PTR(rc); 36 47 devm_nsio_disable(dev, nsio); 37 48 38 49 /* reserve the metadata area, device-dax will reserve the data */ ··· 41 52 if (!devm_request_mem_region(dev, nsio->res.start, offset, 42 53 dev_name(&ndns->dev))) { 43 54 dev_warn(dev, "could not reserve metadata\n"); 44 - return -EBUSY; 55 + return ERR_PTR(-EBUSY); 45 56 } 46 57 47 58 rc = sscanf(dev_name(&ndns->dev), "namespace%d.%d", &region_id, &id); 48 59 if (rc != 2) 49 - return -EINVAL; 60 + return ERR_PTR(-EINVAL); 50 61 51 62 /* adjust the dax_region resource to the start of data */ 52 63 memcpy(&res, &pgmap.res, sizeof(res)); ··· 54 65 dax_region = alloc_dax_region(dev, region_id, &res, 55 66 le32_to_cpu(pfn_sb->align), PFN_DEV|PFN_MAP); 56 67 if (!dax_region) 57 - return -ENOMEM; 68 + return ERR_PTR(-ENOMEM); 58 69 59 - dev_dax = devm_create_dev_dax(dax_region, id, &pgmap); 70 + dev_dax = __devm_create_dev_dax(dax_region, id, &pgmap, subsys); 60 71 61 72 /* child dev_dax instances now own the lifetime of the dax_region */ 62 73 dax_region_put(dax_region); 63 74 64 - return PTR_ERR_OR_ZERO(dev_dax); 75 + return dev_dax; 65 76 } 66 - 67 - static struct nd_device_driver dax_pmem_driver = { 68 - .probe = dax_pmem_probe, 69 - .drv = { 70 - .name = "dax_pmem", 71 - }, 72 - .type = ND_DRIVER_DAX_PMEM, 73 - }; 74 - 75 - module_nd_driver(dax_pmem_driver); 77 + EXPORT_SYMBOL_GPL(__dax_pmem_probe); 76 78 77 79 MODULE_LICENSE("GPL v2"); 78 80 MODULE_AUTHOR("Intel Corporation"); 79 - MODULE_ALIAS_ND_DEVICE(ND_DEVICE_DAX_PMEM);
+7
drivers/dax/pmem/Makefile
··· 1 + obj-$(CONFIG_DEV_DAX_PMEM) += dax_pmem.o 2 + obj-$(CONFIG_DEV_DAX_PMEM) += dax_pmem_core.o 3 + obj-$(CONFIG_DEV_DAX_PMEM_COMPAT) += dax_pmem_compat.o 4 + 5 + dax_pmem-y := pmem.o 6 + dax_pmem_core-y := core.o 7 + dax_pmem_compat-y := compat.o
+73
drivers/dax/pmem/compat.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright(c) 2016 - 2018 Intel Corporation. All rights reserved. */ 3 + #include <linux/percpu-refcount.h> 4 + #include <linux/memremap.h> 5 + #include <linux/module.h> 6 + #include <linux/pfn_t.h> 7 + #include <linux/nd.h> 8 + #include "../bus.h" 9 + 10 + /* we need the private definitions to implement compat suport */ 11 + #include "../dax-private.h" 12 + 13 + static int dax_pmem_compat_probe(struct device *dev) 14 + { 15 + struct dev_dax *dev_dax = __dax_pmem_probe(dev, DEV_DAX_CLASS); 16 + int rc; 17 + 18 + if (IS_ERR(dev_dax)) 19 + return PTR_ERR(dev_dax); 20 + 21 + if (!devres_open_group(&dev_dax->dev, dev_dax, GFP_KERNEL)) 22 + return -ENOMEM; 23 + 24 + device_lock(&dev_dax->dev); 25 + rc = dev_dax_probe(&dev_dax->dev); 26 + device_unlock(&dev_dax->dev); 27 + 28 + devres_close_group(&dev_dax->dev, dev_dax); 29 + if (rc) 30 + devres_release_group(&dev_dax->dev, dev_dax); 31 + 32 + return rc; 33 + } 34 + 35 + static int dax_pmem_compat_release(struct device *dev, void *data) 36 + { 37 + device_lock(dev); 38 + devres_release_group(dev, to_dev_dax(dev)); 39 + device_unlock(dev); 40 + 41 + return 0; 42 + } 43 + 44 + static int dax_pmem_compat_remove(struct device *dev) 45 + { 46 + device_for_each_child(dev, NULL, dax_pmem_compat_release); 47 + return 0; 48 + } 49 + 50 + static struct nd_device_driver dax_pmem_compat_driver = { 51 + .probe = dax_pmem_compat_probe, 52 + .remove = dax_pmem_compat_remove, 53 + .drv = { 54 + .name = "dax_pmem_compat", 55 + }, 56 + .type = ND_DRIVER_DAX_PMEM, 57 + }; 58 + 59 + static int __init dax_pmem_compat_init(void) 60 + { 61 + return nd_driver_register(&dax_pmem_compat_driver); 62 + } 63 + module_init(dax_pmem_compat_init); 64 + 65 + static void __exit dax_pmem_compat_exit(void) 66 + { 67 + driver_unregister(&dax_pmem_compat_driver.drv); 68 + } 69 + module_exit(dax_pmem_compat_exit); 70 + 71 + MODULE_LICENSE("GPL v2"); 72 + MODULE_AUTHOR("Intel Corporation"); 73 + MODULE_ALIAS_ND_DEVICE(ND_DEVICE_DAX_PMEM);
+40
drivers/dax/pmem/pmem.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright(c) 2016 - 2018 Intel Corporation. All rights reserved. */ 3 + #include <linux/percpu-refcount.h> 4 + #include <linux/memremap.h> 5 + #include <linux/module.h> 6 + #include <linux/pfn_t.h> 7 + #include <linux/nd.h> 8 + #include "../bus.h" 9 + 10 + static int dax_pmem_probe(struct device *dev) 11 + { 12 + return PTR_ERR_OR_ZERO(__dax_pmem_probe(dev, DEV_DAX_BUS)); 13 + } 14 + 15 + static struct nd_device_driver dax_pmem_driver = { 16 + .probe = dax_pmem_probe, 17 + .drv = { 18 + .name = "dax_pmem", 19 + }, 20 + .type = ND_DRIVER_DAX_PMEM, 21 + }; 22 + 23 + static int __init dax_pmem_init(void) 24 + { 25 + return nd_driver_register(&dax_pmem_driver); 26 + } 27 + module_init(dax_pmem_init); 28 + 29 + static void __exit dax_pmem_exit(void) 30 + { 31 + driver_unregister(&dax_pmem_driver.drv); 32 + } 33 + module_exit(dax_pmem_exit); 34 + 35 + MODULE_LICENSE("GPL v2"); 36 + MODULE_AUTHOR("Intel Corporation"); 37 + #if !IS_ENABLED(CONFIG_DEV_DAX_PMEM_COMPAT) 38 + /* For compat builds, don't load this module by default */ 39 + MODULE_ALIAS_ND_DEVICE(ND_DEVICE_DAX_PMEM); 40 + #endif
+5 -1
tools/testing/nvdimm/Kbuild
··· 35 35 endif 36 36 obj-$(CONFIG_DEV_DAX) += device_dax.o 37 37 obj-$(CONFIG_DEV_DAX_PMEM) += dax_pmem.o 38 + obj-$(CONFIG_DEV_DAX_PMEM) += dax_pmem_core.o 39 + obj-$(CONFIG_DEV_DAX_PMEM_COMPAT) += dax_pmem_compat.o 38 40 39 41 nfit-y := $(ACPI_SRC)/core.o 40 42 nfit-y += $(ACPI_SRC)/intel.o ··· 67 65 device_dax-y += device_dax_test.o 68 66 device_dax-y += config_check.o 69 67 70 - dax_pmem-y := $(DAX_SRC)/pmem.o 68 + dax_pmem-y := $(DAX_SRC)/pmem/pmem.o 69 + dax_pmem_core-y := $(DAX_SRC)/pmem/core.o 70 + dax_pmem_compat-y := $(DAX_SRC)/pmem/compat.o 71 71 dax_pmem-y += config_check.o 72 72 73 73 libnvdimm-y := $(NVDIMM_SRC)/core.o