diff options
Diffstat (limited to 'drivers/dax')
-rw-r--r-- | drivers/dax/bus.c | 21 | ||||
-rw-r--r-- | drivers/dax/dax-private.h | 2 | ||||
-rw-r--r-- | drivers/dax/kmem.c | 46 | ||||
-rw-r--r-- | drivers/dax/super.c | 42 |
4 files changed, 91 insertions, 20 deletions
diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c index 2109cfe80219..8fafbeab510a 100644 --- a/drivers/dax/bus.c +++ b/drivers/dax/bus.c @@ -295,6 +295,22 @@ static ssize_t target_node_show(struct device *dev, } static DEVICE_ATTR_RO(target_node); +static unsigned long long dev_dax_resource(struct dev_dax *dev_dax) +{ + struct dax_region *dax_region = dev_dax->region; + + return dax_region->res.start; +} + +static ssize_t resource_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dev_dax *dev_dax = to_dev_dax(dev); + + return sprintf(buf, "%#llx\n", dev_dax_resource(dev_dax)); +} +static DEVICE_ATTR_RO(resource); + static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -313,6 +329,8 @@ static umode_t dev_dax_visible(struct kobject *kobj, struct attribute *a, int n) if (a == &dev_attr_target_node.attr && dev_dax_target_node(dev_dax) < 0) return 0; + if (a == &dev_attr_resource.attr) + return 0400; return a->mode; } @@ -320,6 +338,7 @@ static struct attribute *dev_dax_attributes[] = { &dev_attr_modalias.attr, &dev_attr_size.attr, &dev_attr_target_node.attr, + &dev_attr_resource.attr, NULL, }; @@ -388,7 +407,7 @@ struct dev_dax *__devm_create_dev_dax(struct dax_region *dax_region, int id, * No 'host' or dax_operations since there is no access to this * device outside of mmap of the resulting character device. */ - dax_dev = alloc_dax(dev_dax, NULL, NULL); + dax_dev = alloc_dax(dev_dax, NULL, NULL, DAXDEV_F_SYNC); if (!dax_dev) goto err; diff --git a/drivers/dax/dax-private.h b/drivers/dax/dax-private.h index c915889d1769..6ccca3b890d6 100644 --- a/drivers/dax/dax-private.h +++ b/drivers/dax/dax-private.h @@ -43,6 +43,7 @@ struct dax_region { * @target_node: effective numa node if dev_dax memory range is onlined * @dev - device core * @pgmap - pgmap for memmap setup / lifetime (driver owned) + * @dax_mem_res: physical address range of hotadded DAX memory */ struct dev_dax { struct dax_region *region; @@ -50,6 +51,7 @@ struct dev_dax { int target_node; struct device dev; struct dev_pagemap pgmap; + struct resource *dax_kmem_res; }; static inline struct dev_dax *to_dev_dax(struct device *dev) diff --git a/drivers/dax/kmem.c b/drivers/dax/kmem.c index a02318c6d28a..3d0a7e702c94 100644 --- a/drivers/dax/kmem.c +++ b/drivers/dax/kmem.c @@ -66,23 +66,59 @@ int dev_dax_kmem_probe(struct device *dev) new_res->name = dev_name(dev); rc = add_memory(numa_node, new_res->start, resource_size(new_res)); - if (rc) + if (rc) { + release_resource(new_res); + kfree(new_res); return rc; + } + dev_dax->dax_kmem_res = new_res; return 0; } +#ifdef CONFIG_MEMORY_HOTREMOVE +static int dev_dax_kmem_remove(struct device *dev) +{ + struct dev_dax *dev_dax = to_dev_dax(dev); + struct resource *res = dev_dax->dax_kmem_res; + resource_size_t kmem_start = res->start; + resource_size_t kmem_size = resource_size(res); + int rc; + + /* + * We have one shot for removing memory, if some memory blocks were not + * offline prior to calling this function remove_memory() will fail, and + * there is no way to hotremove this memory until reboot because device + * unbind will succeed even if we return failure. + */ + rc = remove_memory(dev_dax->target_node, kmem_start, kmem_size); + if (rc) { + dev_err(dev, + "DAX region %pR cannot be hotremoved until the next reboot\n", + res); + return rc; + } + + /* Release and free dax resources */ + release_resource(res); + kfree(res); + dev_dax->dax_kmem_res = NULL; + + return 0; +} +#else static int dev_dax_kmem_remove(struct device *dev) { /* - * Purposely leak the request_mem_region() for the device-dax - * range and return '0' to ->remove() attempts. The removal of - * the device from the driver always succeeds, but the region - * is permanently pinned as reserved by the unreleased + * Without hotremove purposely leak the request_mem_region() for the + * device-dax range and return '0' to ->remove() attempts. The removal + * of the device from the driver always succeeds, but the region is + * permanently pinned as reserved by the unreleased * request_mem_region(). */ return 0; } +#endif /* CONFIG_MEMORY_HOTREMOVE */ static struct dax_device_driver device_dax_kmem_driver = { .drv = { diff --git a/drivers/dax/super.c b/drivers/dax/super.c index 4e5ae7e8b557..26a654dbc69a 100644 --- a/drivers/dax/super.c +++ b/drivers/dax/super.c @@ -5,6 +5,7 @@ #include <linux/pagemap.h> #include <linux/module.h> #include <linux/mount.h> +#include <linux/pseudo_fs.h> #include <linux/magic.h> #include <linux/genhd.h> #include <linux/pfn_t.h> @@ -195,6 +196,8 @@ enum dax_device_flags { DAXDEV_ALIVE, /* gate whether dax_flush() calls the low level flush routine */ DAXDEV_WRITE_CACHE, + /* flag to check if device supports synchronous flush */ + DAXDEV_SYNC, }; /** @@ -372,6 +375,18 @@ bool dax_write_cache_enabled(struct dax_device *dax_dev) } EXPORT_SYMBOL_GPL(dax_write_cache_enabled); +bool __dax_synchronous(struct dax_device *dax_dev) +{ + return test_bit(DAXDEV_SYNC, &dax_dev->flags); +} +EXPORT_SYMBOL_GPL(__dax_synchronous); + +void __set_dax_synchronous(struct dax_device *dax_dev) +{ + set_bit(DAXDEV_SYNC, &dax_dev->flags); +} +EXPORT_SYMBOL_GPL(__set_dax_synchronous); + bool dax_alive(struct dax_device *dax_dev) { lockdep_assert_held(&dax_srcu); @@ -455,16 +470,19 @@ static const struct super_operations dax_sops = { .drop_inode = generic_delete_inode, }; -static struct dentry *dax_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int dax_init_fs_context(struct fs_context *fc) { - return mount_pseudo(fs_type, "dax:", &dax_sops, NULL, DAXFS_MAGIC); + struct pseudo_fs_context *ctx = init_pseudo(fc, DAXFS_MAGIC); + if (!ctx) + return -ENOMEM; + ctx->ops = &dax_sops; + return 0; } static struct file_system_type dax_fs_type = { - .name = "dax", - .mount = dax_mount, - .kill_sb = kill_anon_super, + .name = "dax", + .init_fs_context = dax_init_fs_context, + .kill_sb = kill_anon_super, }; static int dax_test(struct inode *inode, void *data) @@ -526,7 +544,7 @@ static void dax_add_host(struct dax_device *dax_dev, const char *host) } struct dax_device *alloc_dax(void *private, const char *__host, - const struct dax_operations *ops) + const struct dax_operations *ops, unsigned long flags) { struct dax_device *dax_dev; const char *host; @@ -549,6 +567,9 @@ struct dax_device *alloc_dax(void *private, const char *__host, dax_add_host(dax_dev, host); dax_dev->ops = ops; dax_dev->private = private; + if (flags & DAXDEV_F_SYNC) + set_dax_synchronous(dax_dev); + return dax_dev; err_dev: @@ -648,10 +669,6 @@ static int dax_fs_init(void) if (!dax_cache) return -ENOMEM; - rc = register_filesystem(&dax_fs_type); - if (rc) - goto err_register_fs; - dax_mnt = kern_mount(&dax_fs_type); if (IS_ERR(dax_mnt)) { rc = PTR_ERR(dax_mnt); @@ -662,8 +679,6 @@ static int dax_fs_init(void) return 0; err_mount: - unregister_filesystem(&dax_fs_type); - err_register_fs: kmem_cache_destroy(dax_cache); return rc; @@ -672,7 +687,6 @@ static int dax_fs_init(void) static void dax_fs_exit(void) { kern_unmount(dax_mnt); - unregister_filesystem(&dax_fs_type); kmem_cache_destroy(dax_cache); } |