From ccdb07f62986968ecd687a71550ed187c8cf875c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sat, 6 Aug 2016 16:05:06 -0700 Subject: [PATCH 01/11] dax: cleanup needlessly global symbol warnings drivers/dax/dax.c:75:6: warning: symbol 'dax_region_put' was not declared. drivers/dax/dax.c:95:19: warning: symbol 'alloc_dax_region' was not declared. drivers/dax/dax.c:173:5: warning: symbol 'devm_create_dax_dev' was not declared. drivers/dax/pmem.c:27:17: warning: symbol 'to_dax_pmem' was not declared. Signed-off-by: Dan Williams --- drivers/dax/dax.c | 1 + drivers/dax/pmem.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c index 803f3953b341..736c03830fd0 100644 --- a/drivers/dax/dax.c +++ b/drivers/dax/dax.c @@ -18,6 +18,7 @@ #include #include #include +#include "dax.h" static int dax_major; static struct class *dax_class; diff --git a/drivers/dax/pmem.c b/drivers/dax/pmem.c index dfb168568af1..59b75c5972bb 100644 --- a/drivers/dax/pmem.c +++ b/drivers/dax/pmem.c @@ -24,7 +24,7 @@ struct dax_pmem { struct completion cmp; }; -struct dax_pmem *to_dax_pmem(struct percpu_ref *ref) +static struct dax_pmem *to_dax_pmem(struct percpu_ref *ref) { return container_of(ref, struct dax_pmem, ref); } From 043a9255021bad498e31365d104d33915b6a6e33 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sun, 7 Aug 2016 08:23:56 -0700 Subject: [PATCH 02/11] dax: reorder dax_fops function definitions In order to convert devm_create_dax_dev() to use cdev, it will need access to dax_fops. Move dax_fops and related function definitions before devm_create_dax_dev(). Signed-off-by: Dan Williams --- drivers/dax/dax.c | 337 +++++++++++++++++++++++----------------------- 1 file changed, 168 insertions(+), 169 deletions(-) diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c index 736c03830fd0..3774fc9709bb 100644 --- a/drivers/dax/dax.c +++ b/drivers/dax/dax.c @@ -145,175 +145,6 @@ static const struct attribute_group *dax_attribute_groups[] = { NULL, }; -static void unregister_dax_dev(void *_dev) -{ - struct device *dev = _dev; - struct dax_dev *dax_dev = dev_get_drvdata(dev); - struct dax_region *dax_region = dax_dev->region; - - dev_dbg(dev, "%s\n", __func__); - - /* - * Note, rcu is not protecting the liveness of dax_dev, rcu is - * ensuring that any fault handlers that might have seen - * dax_dev->alive == true, have completed. Any fault handlers - * that start after synchronize_rcu() has started will abort - * upon seeing dax_dev->alive == false. - */ - dax_dev->alive = false; - synchronize_rcu(); - - get_device(dev); - device_unregister(dev); - ida_simple_remove(&dax_region->ida, dax_dev->id); - ida_simple_remove(&dax_minor_ida, MINOR(dev->devt)); - put_device(dev); - dax_dev_put(dax_dev); -} - -int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res, - int count) -{ - struct device *parent = dax_region->dev; - struct dax_dev *dax_dev; - struct device *dev; - int rc, minor; - dev_t dev_t; - - dax_dev = kzalloc(sizeof(*dax_dev) + sizeof(*res) * count, GFP_KERNEL); - if (!dax_dev) - return -ENOMEM; - memcpy(dax_dev->res, res, sizeof(*res) * count); - dax_dev->num_resources = count; - kref_init(&dax_dev->kref); - dax_dev->alive = true; - dax_dev->region = dax_region; - kref_get(&dax_region->kref); - - dax_dev->id = ida_simple_get(&dax_region->ida, 0, 0, GFP_KERNEL); - if (dax_dev->id < 0) { - rc = dax_dev->id; - goto err_id; - } - - minor = ida_simple_get(&dax_minor_ida, 0, 0, GFP_KERNEL); - if (minor < 0) { - rc = minor; - goto err_minor; - } - - dev_t = MKDEV(dax_major, minor); - dev = device_create_with_groups(dax_class, parent, dev_t, dax_dev, - dax_attribute_groups, "dax%d.%d", dax_region->id, - dax_dev->id); - if (IS_ERR(dev)) { - rc = PTR_ERR(dev); - goto err_create; - } - dax_dev->dev = dev; - - rc = devm_add_action_or_reset(dax_region->dev, unregister_dax_dev, dev); - if (rc) - return rc; - - return 0; - - err_create: - ida_simple_remove(&dax_minor_ida, minor); - err_minor: - ida_simple_remove(&dax_region->ida, dax_dev->id); - err_id: - dax_dev_put(dax_dev); - - return rc; -} -EXPORT_SYMBOL_GPL(devm_create_dax_dev); - -/* return an unmapped area aligned to the dax region specified alignment */ -static unsigned long dax_dev_get_unmapped_area(struct file *filp, - unsigned long addr, unsigned long len, unsigned long pgoff, - unsigned long flags) -{ - unsigned long off, off_end, off_align, len_align, addr_align, align; - struct dax_dev *dax_dev = filp ? filp->private_data : NULL; - struct dax_region *dax_region; - - if (!dax_dev || addr) - goto out; - - dax_region = dax_dev->region; - align = dax_region->align; - off = pgoff << PAGE_SHIFT; - off_end = off + len; - off_align = round_up(off, align); - - if ((off_end <= off_align) || ((off_end - off_align) < align)) - goto out; - - len_align = len + align; - if ((off + len_align) < off) - goto out; - - addr_align = current->mm->get_unmapped_area(filp, addr, len_align, - pgoff, flags); - if (!IS_ERR_VALUE(addr_align)) { - addr_align += (off - addr_align) & (align - 1); - return addr_align; - } - out: - return current->mm->get_unmapped_area(filp, addr, len, pgoff, flags); -} - -static int __match_devt(struct device *dev, const void *data) -{ - const dev_t *devt = data; - - return dev->devt == *devt; -} - -static struct device *dax_dev_find(dev_t dev_t) -{ - return class_find_device(dax_class, NULL, &dev_t, __match_devt); -} - -static int dax_dev_open(struct inode *inode, struct file *filp) -{ - struct dax_dev *dax_dev = NULL; - struct device *dev; - - dev = dax_dev_find(inode->i_rdev); - if (!dev) - return -ENXIO; - - device_lock(dev); - dax_dev = dev_get_drvdata(dev); - if (dax_dev) { - dev_dbg(dev, "%s\n", __func__); - filp->private_data = dax_dev; - kref_get(&dax_dev->kref); - inode->i_flags = S_DAX; - } - device_unlock(dev); - - if (!dax_dev) { - put_device(dev); - return -ENXIO; - } - return 0; -} - -static int dax_dev_release(struct inode *inode, struct file *filp) -{ - struct dax_dev *dax_dev = filp->private_data; - struct device *dev = dax_dev->dev; - - dev_dbg(dax_dev->dev, "%s\n", __func__); - dax_dev_put(dax_dev); - put_device(dev); - - return 0; -} - static int check_vma(struct dax_dev *dax_dev, struct vm_area_struct *vma, const char *func) { @@ -531,7 +362,91 @@ static int dax_dev_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_ops = &dax_dev_vm_ops; vma->vm_flags |= VM_MIXEDMAP | VM_HUGEPAGE; return 0; +} +/* return an unmapped area aligned to the dax region specified alignment */ +static unsigned long dax_dev_get_unmapped_area(struct file *filp, + unsigned long addr, unsigned long len, unsigned long pgoff, + unsigned long flags) +{ + unsigned long off, off_end, off_align, len_align, addr_align, align; + struct dax_dev *dax_dev = filp ? filp->private_data : NULL; + struct dax_region *dax_region; + + if (!dax_dev || addr) + goto out; + + dax_region = dax_dev->region; + align = dax_region->align; + off = pgoff << PAGE_SHIFT; + off_end = off + len; + off_align = round_up(off, align); + + if ((off_end <= off_align) || ((off_end - off_align) < align)) + goto out; + + len_align = len + align; + if ((off + len_align) < off) + goto out; + + addr_align = current->mm->get_unmapped_area(filp, addr, len_align, + pgoff, flags); + if (!IS_ERR_VALUE(addr_align)) { + addr_align += (off - addr_align) & (align - 1); + return addr_align; + } + out: + return current->mm->get_unmapped_area(filp, addr, len, pgoff, flags); +} + +static int __match_devt(struct device *dev, const void *data) +{ + const dev_t *devt = data; + + return dev->devt == *devt; +} + +static struct device *dax_dev_find(dev_t dev_t) +{ + return class_find_device(dax_class, NULL, &dev_t, __match_devt); +} + +static int dax_dev_open(struct inode *inode, struct file *filp) +{ + struct dax_dev *dax_dev = NULL; + struct device *dev; + + dev = dax_dev_find(inode->i_rdev); + if (!dev) + return -ENXIO; + + device_lock(dev); + dax_dev = dev_get_drvdata(dev); + if (dax_dev) { + dev_dbg(dev, "%s\n", __func__); + filp->private_data = dax_dev; + kref_get(&dax_dev->kref); + inode->i_flags = S_DAX; + } + device_unlock(dev); + + if (!dax_dev) { + put_device(dev); + return -ENXIO; + } + return 0; +} + +static int dax_dev_release(struct inode *inode, struct file *filp) +{ + struct dax_dev *dax_dev = filp->private_data; + struct device *dev = dax_dev->dev; + + dev_dbg(dax_dev->dev, "%s\n", __func__); + dax_dev_put(dax_dev); + put_device(dev); + + return 0; } static const struct file_operations dax_fops = { @@ -543,6 +458,90 @@ static const struct file_operations dax_fops = { .mmap = dax_dev_mmap, }; +static void unregister_dax_dev(void *_dev) +{ + struct device *dev = _dev; + struct dax_dev *dax_dev = dev_get_drvdata(dev); + struct dax_region *dax_region = dax_dev->region; + + dev_dbg(dev, "%s\n", __func__); + + /* + * Note, rcu is not protecting the liveness of dax_dev, rcu is + * ensuring that any fault handlers that might have seen + * dax_dev->alive == true, have completed. Any fault handlers + * that start after synchronize_rcu() has started will abort + * upon seeing dax_dev->alive == false. + */ + dax_dev->alive = false; + synchronize_rcu(); + + get_device(dev); + device_unregister(dev); + ida_simple_remove(&dax_region->ida, dax_dev->id); + ida_simple_remove(&dax_minor_ida, MINOR(dev->devt)); + put_device(dev); + dax_dev_put(dax_dev); +} + +int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res, + int count) +{ + struct device *parent = dax_region->dev; + struct dax_dev *dax_dev; + struct device *dev; + int rc, minor; + dev_t dev_t; + + dax_dev = kzalloc(sizeof(*dax_dev) + sizeof(*res) * count, GFP_KERNEL); + if (!dax_dev) + return -ENOMEM; + memcpy(dax_dev->res, res, sizeof(*res) * count); + dax_dev->num_resources = count; + kref_init(&dax_dev->kref); + dax_dev->alive = true; + dax_dev->region = dax_region; + kref_get(&dax_region->kref); + + dax_dev->id = ida_simple_get(&dax_region->ida, 0, 0, GFP_KERNEL); + if (dax_dev->id < 0) { + rc = dax_dev->id; + goto err_id; + } + + minor = ida_simple_get(&dax_minor_ida, 0, 0, GFP_KERNEL); + if (minor < 0) { + rc = minor; + goto err_minor; + } + + dev_t = MKDEV(dax_major, minor); + dev = device_create_with_groups(dax_class, parent, dev_t, dax_dev, + dax_attribute_groups, "dax%d.%d", dax_region->id, + dax_dev->id); + if (IS_ERR(dev)) { + rc = PTR_ERR(dev); + goto err_create; + } + dax_dev->dev = dev; + + rc = devm_add_action_or_reset(dax_region->dev, unregister_dax_dev, dev); + if (rc) + return rc; + + return 0; + + err_create: + ida_simple_remove(&dax_minor_ida, minor); + err_minor: + ida_simple_remove(&dax_region->ida, dax_dev->id); + err_id: + dax_dev_put(dax_dev); + + return rc; +} +EXPORT_SYMBOL_GPL(devm_create_dax_dev); + static int __init dax_init(void) { int rc; From af69f51e506f5ad3625c817ba2449a439bbe68ef Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 11 Aug 2016 00:38:03 -0700 Subject: [PATCH 03/11] dax: rename fops from dax_dev_ to dax_ Shorten the prefix of the file operations to distinguish them from operations on the struct device associated with the dax_dev. Signed-off-by: Dan Williams --- drivers/dax/dax.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c index 3774fc9709bb..994dfa507dfb 100644 --- a/drivers/dax/dax.c +++ b/drivers/dax/dax.c @@ -347,7 +347,7 @@ static const struct vm_operations_struct dax_dev_vm_ops = { .close = dax_dev_vm_close, }; -static int dax_dev_mmap(struct file *filp, struct vm_area_struct *vma) +static int dax_mmap(struct file *filp, struct vm_area_struct *vma) { struct dax_dev *dax_dev = filp->private_data; int rc; @@ -365,7 +365,7 @@ static int dax_dev_mmap(struct file *filp, struct vm_area_struct *vma) } /* return an unmapped area aligned to the dax region specified alignment */ -static unsigned long dax_dev_get_unmapped_area(struct file *filp, +static unsigned long dax_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { @@ -411,7 +411,7 @@ static struct device *dax_dev_find(dev_t dev_t) return class_find_device(dax_class, NULL, &dev_t, __match_devt); } -static int dax_dev_open(struct inode *inode, struct file *filp) +static int dax_open(struct inode *inode, struct file *filp) { struct dax_dev *dax_dev = NULL; struct device *dev; @@ -437,7 +437,7 @@ static int dax_dev_open(struct inode *inode, struct file *filp) return 0; } -static int dax_dev_release(struct inode *inode, struct file *filp) +static int dax_release(struct inode *inode, struct file *filp) { struct dax_dev *dax_dev = filp->private_data; struct device *dev = dax_dev->dev; @@ -452,10 +452,10 @@ static int dax_dev_release(struct inode *inode, struct file *filp) static const struct file_operations dax_fops = { .llseek = noop_llseek, .owner = THIS_MODULE, - .open = dax_dev_open, - .release = dax_dev_release, - .get_unmapped_area = dax_dev_get_unmapped_area, - .mmap = dax_dev_mmap, + .open = dax_open, + .release = dax_release, + .get_unmapped_area = dax_get_unmapped_area, + .mmap = dax_mmap, }; static void unregister_dax_dev(void *_dev) From ebd84d724c85f22037a5c9cb04b9e6631309cb78 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 11 Aug 2016 00:41:51 -0700 Subject: [PATCH 04/11] dax: embed a struct device in dax_dev The kref in dax_dev can be made redundant if the final put_device() on the device associated with the dax_dev frees the dax_dev. This can be accomplished by embedding a struct device in struct dax_dev, open coding device_create() and specifying a custom release method. Signed-off-by: Dan Williams --- drivers/dax/dax.c | 130 ++++++++++++++++------------------------------ 1 file changed, 45 insertions(+), 85 deletions(-) diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c index 994dfa507dfb..181d2a5a21e4 100644 --- a/drivers/dax/dax.c +++ b/drivers/dax/dax.c @@ -49,7 +49,6 @@ struct dax_region { * struct dax_dev - subdivision of a dax region * @region - parent region * @dev - device backing the character device - * @kref - enable this data to be tracked in filp->private_data * @alive - !alive + rcu grace period == no new mappings can be established * @id - child id in the region * @num_resources - number of physical address extents in this device @@ -57,8 +56,7 @@ struct dax_region { */ struct dax_dev { struct dax_region *region; - struct device *dev; - struct kref kref; + struct device dev; bool alive; int id; int num_resources; @@ -79,20 +77,6 @@ void dax_region_put(struct dax_region *dax_region) } EXPORT_SYMBOL_GPL(dax_region_put); -static void dax_dev_free(struct kref *kref) -{ - struct dax_dev *dax_dev; - - dax_dev = container_of(kref, struct dax_dev, kref); - dax_region_put(dax_dev->region); - kfree(dax_dev); -} - -static void dax_dev_put(struct dax_dev *dax_dev) -{ - kref_put(&dax_dev->kref, dax_dev_free); -} - struct dax_region *alloc_dax_region(struct device *parent, int region_id, struct resource *res, unsigned int align, void *addr, unsigned long pfn_flags) @@ -117,10 +101,15 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id, } EXPORT_SYMBOL_GPL(alloc_dax_region); +static struct dax_dev *to_dax_dev(struct device *dev) +{ + return container_of(dev, struct dax_dev, dev); +} + static ssize_t size_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct dax_dev *dax_dev = dev_get_drvdata(dev); + struct dax_dev *dax_dev = to_dax_dev(dev); unsigned long long size = 0; int i; @@ -149,7 +138,7 @@ static int check_vma(struct dax_dev *dax_dev, struct vm_area_struct *vma, const char *func) { struct dax_region *dax_region = dax_dev->region; - struct device *dev = dax_dev->dev; + struct device *dev = &dax_dev->dev; unsigned long mask; if (!dax_dev->alive) @@ -214,7 +203,7 @@ static int __dax_dev_fault(struct dax_dev *dax_dev, struct vm_area_struct *vma, struct vm_fault *vmf) { unsigned long vaddr = (unsigned long) vmf->virtual_address; - struct device *dev = dax_dev->dev; + struct device *dev = &dax_dev->dev; struct dax_region *dax_region; int rc = VM_FAULT_SIGBUS; phys_addr_t phys; @@ -254,7 +243,7 @@ static int dax_dev_fault(struct vm_area_struct *vma, struct vm_fault *vmf) struct file *filp = vma->vm_file; struct dax_dev *dax_dev = filp->private_data; - dev_dbg(dax_dev->dev, "%s: %s: %s (%#lx - %#lx)\n", __func__, + dev_dbg(&dax_dev->dev, "%s: %s: %s (%#lx - %#lx)\n", __func__, current->comm, (vmf->flags & FAULT_FLAG_WRITE) ? "write" : "read", vma->vm_start, vma->vm_end); rcu_read_lock(); @@ -269,7 +258,7 @@ static int __dax_dev_pmd_fault(struct dax_dev *dax_dev, unsigned int flags) { unsigned long pmd_addr = addr & PMD_MASK; - struct device *dev = dax_dev->dev; + struct device *dev = &dax_dev->dev; struct dax_region *dax_region; phys_addr_t phys; pgoff_t pgoff; @@ -311,7 +300,7 @@ static int dax_dev_pmd_fault(struct vm_area_struct *vma, unsigned long addr, struct file *filp = vma->vm_file; struct dax_dev *dax_dev = filp->private_data; - dev_dbg(dax_dev->dev, "%s: %s: %s (%#lx - %#lx)\n", __func__, + dev_dbg(&dax_dev->dev, "%s: %s: %s (%#lx - %#lx)\n", __func__, current->comm, (flags & FAULT_FLAG_WRITE) ? "write" : "read", vma->vm_start, vma->vm_end); @@ -322,29 +311,9 @@ static int dax_dev_pmd_fault(struct vm_area_struct *vma, unsigned long addr, return rc; } -static void dax_dev_vm_open(struct vm_area_struct *vma) -{ - struct file *filp = vma->vm_file; - struct dax_dev *dax_dev = filp->private_data; - - dev_dbg(dax_dev->dev, "%s\n", __func__); - kref_get(&dax_dev->kref); -} - -static void dax_dev_vm_close(struct vm_area_struct *vma) -{ - struct file *filp = vma->vm_file; - struct dax_dev *dax_dev = filp->private_data; - - dev_dbg(dax_dev->dev, "%s\n", __func__); - dax_dev_put(dax_dev); -} - static const struct vm_operations_struct dax_dev_vm_ops = { .fault = dax_dev_fault, .pmd_fault = dax_dev_pmd_fault, - .open = dax_dev_vm_open, - .close = dax_dev_vm_close, }; static int dax_mmap(struct file *filp, struct vm_area_struct *vma) @@ -352,13 +321,12 @@ static int dax_mmap(struct file *filp, struct vm_area_struct *vma) struct dax_dev *dax_dev = filp->private_data; int rc; - dev_dbg(dax_dev->dev, "%s\n", __func__); + dev_dbg(&dax_dev->dev, "%s\n", __func__); rc = check_vma(dax_dev, vma, __func__); if (rc) return rc; - kref_get(&dax_dev->kref); vma->vm_ops = &dax_dev_vm_ops; vma->vm_flags |= VM_MIXEDMAP | VM_HUGEPAGE; return 0; @@ -420,30 +388,20 @@ static int dax_open(struct inode *inode, struct file *filp) if (!dev) return -ENXIO; - device_lock(dev); - dax_dev = dev_get_drvdata(dev); - if (dax_dev) { - dev_dbg(dev, "%s\n", __func__); - filp->private_data = dax_dev; - kref_get(&dax_dev->kref); - inode->i_flags = S_DAX; - } - device_unlock(dev); + dax_dev = to_dax_dev(dev); + dev_dbg(dev, "%s\n", __func__); + filp->private_data = dax_dev; + inode->i_flags = S_DAX; - if (!dax_dev) { - put_device(dev); - return -ENXIO; - } return 0; } static int dax_release(struct inode *inode, struct file *filp) { struct dax_dev *dax_dev = filp->private_data; - struct device *dev = dax_dev->dev; + struct device *dev = &dax_dev->dev; - dev_dbg(dax_dev->dev, "%s\n", __func__); - dax_dev_put(dax_dev); + dev_dbg(dev, "%s\n", __func__); put_device(dev); return 0; @@ -458,12 +416,21 @@ static const struct file_operations dax_fops = { .mmap = dax_mmap, }; -static void unregister_dax_dev(void *_dev) +static void dax_dev_release(struct device *dev) { - struct device *dev = _dev; - struct dax_dev *dax_dev = dev_get_drvdata(dev); + struct dax_dev *dax_dev = to_dax_dev(dev); struct dax_region *dax_region = dax_dev->region; + ida_simple_remove(&dax_region->ida, dax_dev->id); + ida_simple_remove(&dax_minor_ida, MINOR(dev->devt)); + dax_region_put(dax_region); + kfree(dax_dev); +} + +static void unregister_dax_dev(void *dev) +{ + struct dax_dev *dax_dev = to_dax_dev(dev); + dev_dbg(dev, "%s\n", __func__); /* @@ -475,13 +442,7 @@ static void unregister_dax_dev(void *_dev) */ dax_dev->alive = false; synchronize_rcu(); - - get_device(dev); device_unregister(dev); - ida_simple_remove(&dax_region->ida, dax_dev->id); - ida_simple_remove(&dax_minor_ida, MINOR(dev->devt)); - put_device(dev); - dax_dev_put(dax_dev); } int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res, @@ -498,7 +459,6 @@ int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res, return -ENOMEM; memcpy(dax_dev->res, res, sizeof(*res) * count); dax_dev->num_resources = count; - kref_init(&dax_dev->kref); dax_dev->alive = true; dax_dev->region = dax_region; kref_get(&dax_region->kref); @@ -516,27 +476,27 @@ int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res, } dev_t = MKDEV(dax_major, minor); - dev = device_create_with_groups(dax_class, parent, dev_t, dax_dev, - dax_attribute_groups, "dax%d.%d", dax_region->id, - dax_dev->id); - if (IS_ERR(dev)) { - rc = PTR_ERR(dev); - goto err_create; - } - dax_dev->dev = dev; - rc = devm_add_action_or_reset(dax_region->dev, unregister_dax_dev, dev); - if (rc) + dev = &dax_dev->dev; + device_initialize(dev); + dev->devt = dev_t; + dev->class = dax_class; + dev->parent = parent; + dev->groups = dax_attribute_groups; + dev->release = dax_dev_release; + dev_set_name(dev, "dax%d.%d", dax_region->id, dax_dev->id); + rc = device_add(dev); + if (rc) { + put_device(dev); return rc; + } - return 0; + return devm_add_action_or_reset(dax_region->dev, unregister_dax_dev, dev); - err_create: - ida_simple_remove(&dax_minor_ida, minor); err_minor: ida_simple_remove(&dax_region->ida, dax_dev->id); err_id: - dax_dev_put(dax_dev); + kfree(dax_dev); return rc; } From ba09c01d2fa866f22e42ac2af405fe386f491879 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sun, 24 Jul 2016 15:55:42 -0700 Subject: [PATCH 05/11] dax: convert to the cdev api A goal of the device-DAX interface is to be able to support many exclusive allocations (partitions) of performance / feature differentiated memory. This count may exceed the default minors limit of 256. As a result of switching to an embedded cdev the inode-to-dax_dev conversion is simplified, as well as reference counting which can switch to the cdev kobject lifetime. Cc: Al Viro Signed-off-by: Dan Williams --- drivers/dax/Kconfig | 5 +++ drivers/dax/dax.c | 82 ++++++++++++++++++++++----------------------- 2 files changed, 46 insertions(+), 41 deletions(-) diff --git a/drivers/dax/Kconfig b/drivers/dax/Kconfig index cedab7572de3..daadd20aa936 100644 --- a/drivers/dax/Kconfig +++ b/drivers/dax/Kconfig @@ -23,4 +23,9 @@ config DEV_DAX_PMEM Say Y if unsure +config NR_DEV_DAX + int "Maximum number of Device-DAX instances" + default 32768 + range 256 2147483647 + endif diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c index 181d2a5a21e4..17715773c097 100644 --- a/drivers/dax/dax.c +++ b/drivers/dax/dax.c @@ -14,15 +14,19 @@ #include #include #include +#include #include #include #include #include #include "dax.h" -static int dax_major; +static dev_t dax_devt; static struct class *dax_class; static DEFINE_IDA(dax_minor_ida); +static int nr_dax = CONFIG_NR_DEV_DAX; +module_param(nr_dax, int, S_IRUGO); +MODULE_PARM_DESC(nr_dax, "max number of device-dax instances"); /** * struct dax_region - mapping infrastructure for dax devices @@ -49,6 +53,7 @@ struct dax_region { * struct dax_dev - subdivision of a dax region * @region - parent region * @dev - device backing the character device + * @cdev - core chardev data * @alive - !alive + rcu grace period == no new mappings can be established * @id - child id in the region * @num_resources - number of physical address extents in this device @@ -57,6 +62,7 @@ struct dax_region { struct dax_dev { struct dax_region *region; struct device dev; + struct cdev cdev; bool alive; int id; int num_resources; @@ -367,29 +373,12 @@ static unsigned long dax_get_unmapped_area(struct file *filp, return current->mm->get_unmapped_area(filp, addr, len, pgoff, flags); } -static int __match_devt(struct device *dev, const void *data) -{ - const dev_t *devt = data; - - return dev->devt == *devt; -} - -static struct device *dax_dev_find(dev_t dev_t) -{ - return class_find_device(dax_class, NULL, &dev_t, __match_devt); -} - static int dax_open(struct inode *inode, struct file *filp) { - struct dax_dev *dax_dev = NULL; - struct device *dev; + struct dax_dev *dax_dev; - dev = dax_dev_find(inode->i_rdev); - if (!dev) - return -ENXIO; - - dax_dev = to_dax_dev(dev); - dev_dbg(dev, "%s\n", __func__); + dax_dev = container_of(inode->i_cdev, struct dax_dev, cdev); + dev_dbg(&dax_dev->dev, "%s\n", __func__); filp->private_data = dax_dev; inode->i_flags = S_DAX; @@ -399,11 +388,8 @@ static int dax_open(struct inode *inode, struct file *filp) static int dax_release(struct inode *inode, struct file *filp) { struct dax_dev *dax_dev = filp->private_data; - struct device *dev = &dax_dev->dev; - - dev_dbg(dev, "%s\n", __func__); - put_device(dev); + dev_dbg(&dax_dev->dev, "%s\n", __func__); return 0; } @@ -430,6 +416,7 @@ static void dax_dev_release(struct device *dev) static void unregister_dax_dev(void *dev) { struct dax_dev *dax_dev = to_dax_dev(dev); + struct cdev *cdev = &dax_dev->cdev; dev_dbg(dev, "%s\n", __func__); @@ -442,6 +429,7 @@ static void unregister_dax_dev(void *dev) */ dax_dev->alive = false; synchronize_rcu(); + cdev_del(cdev); device_unregister(dev); } @@ -451,17 +439,13 @@ int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res, struct device *parent = dax_region->dev; struct dax_dev *dax_dev; struct device *dev; + struct cdev *cdev; int rc, minor; dev_t dev_t; dax_dev = kzalloc(sizeof(*dax_dev) + sizeof(*res) * count, GFP_KERNEL); if (!dax_dev) return -ENOMEM; - memcpy(dax_dev->res, res, sizeof(*res) * count); - dax_dev->num_resources = count; - dax_dev->alive = true; - dax_dev->region = dax_region; - kref_get(&dax_region->kref); dax_dev->id = ida_simple_get(&dax_region->ida, 0, 0, GFP_KERNEL); if (dax_dev->id < 0) { @@ -475,10 +459,26 @@ int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res, goto err_minor; } - dev_t = MKDEV(dax_major, minor); - + /* device_initialize() so cdev can reference kobj parent */ + dev_t = MKDEV(MAJOR(dax_devt), minor); dev = &dax_dev->dev; device_initialize(dev); + + cdev = &dax_dev->cdev; + cdev_init(cdev, &dax_fops); + cdev->owner = parent->driver->owner; + cdev->kobj.parent = &dev->kobj; + rc = cdev_add(&dax_dev->cdev, dev_t, 1); + if (rc) + goto err_cdev; + + /* from here on we're committed to teardown via dax_dev_release() */ + memcpy(dax_dev->res, res, sizeof(*res) * count); + dax_dev->num_resources = count; + dax_dev->alive = true; + dax_dev->region = dax_region; + kref_get(&dax_region->kref); + dev->devt = dev_t; dev->class = dax_class; dev->parent = parent; @@ -493,6 +493,8 @@ int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res, return devm_add_action_or_reset(dax_region->dev, unregister_dax_dev, dev); + err_cdev: + ida_simple_remove(&dax_minor_ida, minor); err_minor: ida_simple_remove(&dax_region->ida, dax_dev->id); err_id: @@ -506,24 +508,22 @@ static int __init dax_init(void) { int rc; - rc = register_chrdev(0, "dax", &dax_fops); - if (rc < 0) + nr_dax = max(nr_dax, 256); + rc = alloc_chrdev_region(&dax_devt, 0, nr_dax, "dax"); + if (rc) return rc; - dax_major = rc; dax_class = class_create(THIS_MODULE, "dax"); - if (IS_ERR(dax_class)) { - unregister_chrdev(dax_major, "dax"); - return PTR_ERR(dax_class); - } + if (IS_ERR(dax_class)) + unregister_chrdev_region(dax_devt, nr_dax); - return 0; + return PTR_ERR_OR_ZERO(dax_class); } static void __exit dax_exit(void) { class_destroy(dax_class); - unregister_chrdev(dax_major, "dax"); + unregister_chrdev_region(dax_devt, nr_dax); ida_destroy(&dax_minor_ida); } From 3bc52c45bac26bf7ed1dc8d287ad1aeaed1250b6 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sun, 24 Jul 2016 21:55:45 -0700 Subject: [PATCH 06/11] dax: define a unified inode/address_space for device-dax mappings In support of enabling resize / truncate of device-dax instances, define a pseudo-fs to provide a unified inode/address space for vm operations. Cc: Al Viro Signed-off-by: Dan Williams --- drivers/dax/dax.c | 154 +++++++++++++++++++++++++++++++++++-- fs/char_dev.c | 1 + include/uapi/linux/magic.h | 1 + 3 files changed, 150 insertions(+), 6 deletions(-) diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c index 17715773c097..e8b9319aeadb 100644 --- a/drivers/dax/dax.c +++ b/drivers/dax/dax.c @@ -13,7 +13,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -26,6 +28,9 @@ static struct class *dax_class; static DEFINE_IDA(dax_minor_ida); static int nr_dax = CONFIG_NR_DEV_DAX; module_param(nr_dax, int, S_IRUGO); +static struct vfsmount *dax_mnt; +static struct kmem_cache *dax_cache __read_mostly; +static struct super_block *dax_superblock __read_mostly; MODULE_PARM_DESC(nr_dax, "max number of device-dax instances"); /** @@ -61,6 +66,7 @@ struct dax_region { */ struct dax_dev { struct dax_region *region; + struct inode *inode; struct device dev; struct cdev cdev; bool alive; @@ -69,6 +75,117 @@ struct dax_dev { struct resource res[0]; }; +static struct inode *dax_alloc_inode(struct super_block *sb) +{ + return kmem_cache_alloc(dax_cache, GFP_KERNEL); +} + +static void dax_i_callback(struct rcu_head *head) +{ + struct inode *inode = container_of(head, struct inode, i_rcu); + + kmem_cache_free(dax_cache, inode); +} + +static void dax_destroy_inode(struct inode *inode) +{ + call_rcu(&inode->i_rcu, dax_i_callback); +} + +static const struct super_operations dax_sops = { + .statfs = simple_statfs, + .alloc_inode = dax_alloc_inode, + .destroy_inode = dax_destroy_inode, + .drop_inode = generic_delete_inode, +}; + +static struct dentry *dax_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) +{ + return mount_pseudo(fs_type, "dax:", &dax_sops, NULL, DAXFS_MAGIC); +} + +static struct file_system_type dax_type = { + .name = "dax", + .mount = dax_mount, + .kill_sb = kill_anon_super, +}; + +static int dax_test(struct inode *inode, void *data) +{ + return inode->i_cdev == data; +} + +static int dax_set(struct inode *inode, void *data) +{ + inode->i_cdev = data; + return 0; +} + +static struct inode *dax_inode_get(struct cdev *cdev, dev_t devt) +{ + struct inode *inode; + + inode = iget5_locked(dax_superblock, hash_32(devt + DAXFS_MAGIC, 31), + dax_test, dax_set, cdev); + + if (!inode) + return NULL; + + if (inode->i_state & I_NEW) { + inode->i_mode = S_IFCHR; + inode->i_flags = S_DAX; + inode->i_rdev = devt; + mapping_set_gfp_mask(&inode->i_data, GFP_USER); + unlock_new_inode(inode); + } + return inode; +} + +static void init_once(void *inode) +{ + inode_init_once(inode); +} + +static int dax_inode_init(void) +{ + int rc; + + dax_cache = kmem_cache_create("dax_cache", sizeof(struct inode), 0, + (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| + SLAB_MEM_SPREAD|SLAB_ACCOUNT), + init_once); + if (!dax_cache) + return -ENOMEM; + + rc = register_filesystem(&dax_type); + if (rc) + goto err_register_fs; + + dax_mnt = kern_mount(&dax_type); + if (IS_ERR(dax_mnt)) { + rc = PTR_ERR(dax_mnt); + goto err_mount; + } + dax_superblock = dax_mnt->mnt_sb; + + return 0; + + err_mount: + unregister_filesystem(&dax_type); + err_register_fs: + kmem_cache_destroy(dax_cache); + + return rc; +} + +static void dax_inode_exit(void) +{ + kern_unmount(dax_mnt); + unregister_filesystem(&dax_type); + kmem_cache_destroy(dax_cache); +} + static void dax_region_free(struct kref *kref) { struct dax_region *dax_region; @@ -379,6 +496,9 @@ static int dax_open(struct inode *inode, struct file *filp) dax_dev = container_of(inode->i_cdev, struct dax_dev, cdev); dev_dbg(&dax_dev->dev, "%s\n", __func__); + inode->i_mapping = dax_dev->inode->i_mapping; + inode->i_mapping->host = dax_dev->inode; + filp->f_mapping = inode->i_mapping; filp->private_data = dax_dev; inode->i_flags = S_DAX; @@ -410,6 +530,7 @@ static void dax_dev_release(struct device *dev) ida_simple_remove(&dax_region->ida, dax_dev->id); ida_simple_remove(&dax_minor_ida, MINOR(dev->devt)); dax_region_put(dax_region); + iput(dax_dev->inode); kfree(dax_dev); } @@ -459,6 +580,12 @@ int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res, goto err_minor; } + dax_dev->inode = dax_inode_get(&dax_dev->cdev, dev_t); + if (!dax_dev->inode) { + rc = -ENOMEM; + goto err_inode; + } + /* device_initialize() so cdev can reference kobj parent */ dev_t = MKDEV(MAJOR(dax_devt), minor); dev = &dax_dev->dev; @@ -494,6 +621,8 @@ int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res, return devm_add_action_or_reset(dax_region->dev, unregister_dax_dev, dev); err_cdev: + iput(dax_dev->inode); + err_inode: ida_simple_remove(&dax_minor_ida, minor); err_minor: ida_simple_remove(&dax_region->ida, dax_dev->id); @@ -508,16 +637,28 @@ static int __init dax_init(void) { int rc; - nr_dax = max(nr_dax, 256); - rc = alloc_chrdev_region(&dax_devt, 0, nr_dax, "dax"); + rc = dax_inode_init(); if (rc) return rc; - dax_class = class_create(THIS_MODULE, "dax"); - if (IS_ERR(dax_class)) - unregister_chrdev_region(dax_devt, nr_dax); + nr_dax = max(nr_dax, 256); + rc = alloc_chrdev_region(&dax_devt, 0, nr_dax, "dax"); + if (rc) + goto err_chrdev; - return PTR_ERR_OR_ZERO(dax_class); + dax_class = class_create(THIS_MODULE, "dax"); + if (IS_ERR(dax_class)) { + rc = PTR_ERR(dax_class); + goto err_class; + } + + return 0; + + err_class: + unregister_chrdev_region(dax_devt, nr_dax); + err_chrdev: + dax_inode_exit(); + return rc; } static void __exit dax_exit(void) @@ -525,6 +666,7 @@ static void __exit dax_exit(void) class_destroy(dax_class); unregister_chrdev_region(dax_devt, nr_dax); ida_destroy(&dax_minor_ida); + dax_inode_exit(); } MODULE_AUTHOR("Intel Corporation"); diff --git a/fs/char_dev.c b/fs/char_dev.c index 6edd825231c5..44a240c4bb65 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c @@ -406,6 +406,7 @@ void cd_forget(struct inode *inode) spin_lock(&cdev_lock); list_del_init(&inode->i_devices); inode->i_cdev = NULL; + inode->i_mapping = &inode->i_data; spin_unlock(&cdev_lock); } diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h index e398beac67b8..9bd559472c92 100644 --- a/include/uapi/linux/magic.h +++ b/include/uapi/linux/magic.h @@ -65,6 +65,7 @@ #define V9FS_MAGIC 0x01021997 #define BDEVFS_MAGIC 0x62646576 +#define DAXFS_MAGIC 0x64646178 #define BINFMTFS_MAGIC 0x42494e4d #define DEVPTS_SUPER_MAGIC 0x1cd1 #define FUTEXFS_SUPER_MAGIC 0xBAD1DEA From 9dc1e4927bfabaf654738c9ecca3a4926a0aaeb5 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 4 Aug 2016 16:53:50 -0700 Subject: [PATCH 07/11] dax: unmap/truncate on device shutdown Invalidate all mappings of a device-dax instance when the device is unregistered. Signed-off-by: Dan Williams --- drivers/dax/dax.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c index e8b9319aeadb..0a7899d5c65c 100644 --- a/drivers/dax/dax.c +++ b/drivers/dax/dax.c @@ -550,6 +550,7 @@ static void unregister_dax_dev(void *dev) */ dax_dev->alive = false; synchronize_rcu(); + unmap_mapping_range(dax_dev->inode->i_mapping, 0, 0, 1); cdev_del(cdev); device_unregister(dev); } From 9d2d01a031a945075d4609b1c4d3c73f10ba61e7 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 19 Jul 2016 16:17:58 -0700 Subject: [PATCH 08/11] dax: check resource alignment at dax region/device create All the extents of a dax-device must match the alignment of the region. Otherwise, we are unable to guarantee fault semantics of a given page size. The region must be self-consistent itself as well. Signed-off-by: Dan Williams --- drivers/dax/dax.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c index 0a7899d5c65c..03bb54f7f58f 100644 --- a/drivers/dax/dax.c +++ b/drivers/dax/dax.c @@ -206,8 +206,11 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id, { struct dax_region *dax_region; - dax_region = kzalloc(sizeof(*dax_region), GFP_KERNEL); + if (!IS_ALIGNED(res->start, align) + || !IS_ALIGNED(resource_size(res), align)) + return NULL; + dax_region = kzalloc(sizeof(*dax_region), GFP_KERNEL); if (!dax_region) return NULL; @@ -560,15 +563,29 @@ int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res, { struct device *parent = dax_region->dev; struct dax_dev *dax_dev; + int rc = 0, minor, i; struct device *dev; struct cdev *cdev; - int rc, minor; dev_t dev_t; dax_dev = kzalloc(sizeof(*dax_dev) + sizeof(*res) * count, GFP_KERNEL); if (!dax_dev) return -ENOMEM; + for (i = 0; i < count; i++) { + if (!IS_ALIGNED(res[i].start, dax_region->align) + || !IS_ALIGNED(resource_size(&res[i]), + dax_region->align)) { + rc = -EINVAL; + break; + } + dax_dev->res[i].start = res[i].start; + dax_dev->res[i].end = res[i].end; + } + + if (i < count) + goto err_id; + dax_dev->id = ida_simple_get(&dax_region->ida, 0, 0, GFP_KERNEL); if (dax_dev->id < 0) { rc = dax_dev->id; @@ -601,7 +618,6 @@ int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res, goto err_cdev; /* from here on we're committed to teardown via dax_dev_release() */ - memcpy(dax_dev->res, res, sizeof(*res) * count); dax_dev->num_resources = count; dax_dev->alive = true; dax_dev->region = dax_region; From d76911ee933a64c9dfc453e580e7ad612b394e83 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 19 Jul 2016 17:51:40 -0700 Subject: [PATCH 09/11] dax: convert devm_create_dax_dev to PTR_ERR For sub-division support we need access to the dax_dev created by devm_create_dax_dev(). Signed-off-by: Dan Williams --- drivers/dax/dax.c | 16 ++++++++++------ drivers/dax/dax.h | 5 +++-- drivers/dax/pmem.c | 5 +++-- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c index 03bb54f7f58f..e7d8a3902437 100644 --- a/drivers/dax/dax.c +++ b/drivers/dax/dax.c @@ -558,8 +558,8 @@ static void unregister_dax_dev(void *dev) device_unregister(dev); } -int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res, - int count) +struct dax_dev *devm_create_dax_dev(struct dax_region *dax_region, + struct resource *res, int count) { struct device *parent = dax_region->dev; struct dax_dev *dax_dev; @@ -570,7 +570,7 @@ int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res, dax_dev = kzalloc(sizeof(*dax_dev) + sizeof(*res) * count, GFP_KERNEL); if (!dax_dev) - return -ENOMEM; + return ERR_PTR(-ENOMEM); for (i = 0; i < count; i++) { if (!IS_ALIGNED(res[i].start, dax_region->align) @@ -632,10 +632,14 @@ int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res, rc = device_add(dev); if (rc) { put_device(dev); - return rc; + return ERR_PTR(rc); } - return devm_add_action_or_reset(dax_region->dev, unregister_dax_dev, dev); + rc = devm_add_action_or_reset(dax_region->dev, unregister_dax_dev, dev); + if (rc) + return ERR_PTR(rc); + + return dax_dev; err_cdev: iput(dax_dev->inode); @@ -646,7 +650,7 @@ int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res, err_id: kfree(dax_dev); - return rc; + return ERR_PTR(rc); } EXPORT_SYMBOL_GPL(devm_create_dax_dev); diff --git a/drivers/dax/dax.h b/drivers/dax/dax.h index d8b8f1f25054..ddd829ab58c0 100644 --- a/drivers/dax/dax.h +++ b/drivers/dax/dax.h @@ -13,12 +13,13 @@ #ifndef __DAX_H__ #define __DAX_H__ struct device; +struct dax_dev; struct resource; struct dax_region; void dax_region_put(struct dax_region *dax_region); struct dax_region *alloc_dax_region(struct device *parent, int region_id, struct resource *res, unsigned int align, void *addr, unsigned long flags); -int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res, - int count); +struct dax_dev *devm_create_dax_dev(struct dax_region *dax_region, + struct resource *res, int count); #endif /* __DAX_H__ */ diff --git a/drivers/dax/pmem.c b/drivers/dax/pmem.c index 59b75c5972bb..c24d32ec9ce6 100644 --- a/drivers/dax/pmem.c +++ b/drivers/dax/pmem.c @@ -61,6 +61,7 @@ static int dax_pmem_probe(struct device *dev) int rc; void *addr; struct resource res; + struct dax_dev *dax_dev; struct nd_pfn_sb *pfn_sb; struct dax_pmem *dax_pmem; struct nd_region *nd_region; @@ -123,12 +124,12 @@ static int dax_pmem_probe(struct device *dev) return -ENOMEM; /* TODO: support for subdividing a dax region... */ - rc = devm_create_dax_dev(dax_region, &res, 1); + dax_dev = devm_create_dax_dev(dax_region, &res, 1); /* child dax_dev instances now own the lifetime of the dax_region */ dax_region_put(dax_region); - return rc; + return PTR_ERR_OR_ZERO(dax_dev); } static struct nd_device_driver dax_pmem_driver = { From bc0a0fe94f33dd15edf2ed555bfc4d6dbb5e1995 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 8 Sep 2016 15:53:28 +0200 Subject: [PATCH 10/11] dax: use correct dev_t value The dev_t variable in devm_create_dax_dev() is used before it's first set: drivers/dax/dax.c: In function 'devm_create_dax_dev': drivers/dax/dax.c:205:39: error: 'dev_t' may be used uninitialized in this function [-Werror=maybe-uninitialized] inode = iget5_locked(dax_superblock, hash_32(devt + DAXFS_MAGIC, 31), ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/dax/dax.c:688:8: note: 'dev_t' was declared here This reorders the code to how it looks correct to me. Signed-off-by: Arnd Bergmann Fixes: 3bc52c45bac2 ("dax: define a unified inode/address_space for device-dax mappings") Signed-off-by: Dan Williams --- drivers/dax/dax.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c index e7d8a3902437..b917e4d66ad0 100644 --- a/drivers/dax/dax.c +++ b/drivers/dax/dax.c @@ -598,6 +598,8 @@ struct dax_dev *devm_create_dax_dev(struct dax_region *dax_region, goto err_minor; } + dev_t = MKDEV(MAJOR(dax_devt), minor); + dev = &dax_dev->dev; dax_dev->inode = dax_inode_get(&dax_dev->cdev, dev_t); if (!dax_dev->inode) { rc = -ENOMEM; @@ -605,8 +607,6 @@ struct dax_dev *devm_create_dax_dev(struct dax_region *dax_region, } /* device_initialize() so cdev can reference kobj parent */ - dev_t = MKDEV(MAJOR(dax_devt), minor); - dev = &dax_dev->dev; device_initialize(dev); cdev = &dax_dev->cdev; From 4e65e9381c7ac211ec2133e473fcbdd8656c779a Mon Sep 17 00:00:00 2001 From: Ross Zwisler Date: Mon, 12 Sep 2016 10:15:07 -0600 Subject: [PATCH 11/11] /dev/dax: fix Kconfig dependency build breakage The function dax_pmem_probe() in drivers/dax/pmem.c is compiled under the CONFIG_DEV_DAX_PMEM tri-state config option. This config option currently only depends on CONFIG_NVDIMM_DAX, a bool, which means that the following configuration is possible: CONFIG_LIBNVDIMM=m ... CONFIG_NVDIMM_DAX=y CONFIG_DEV_DAX=y CONFIG_DEV_DAX_PMEM=y With this config LIBNVDIMM is compiled as a module with NVDIMM_DAX=y just meaning that we will compile drivers/nvdimm/dax_devs.c into that module. However, dax_pmem_probe() depends on several symbols defined in drivers/nvdimm/dax_devs.c, which results in the following build errors: drivers/built-in.o: In function `dax_pmem_probe': linux/drivers/dax/pmem.c:70: undefined reference to `to_nd_dax' linux/drivers/dax/pmem.c:74: undefined reference to `nvdimm_namespace_common_probe' linux/drivers/dax/pmem.c:80: undefined reference to `devm_nsio_enable' linux/drivers/dax/pmem.c:81: undefined reference to `nvdimm_setup_pfn' linux/drivers/dax/pmem.c:84: undefined reference to `devm_nsio_disable' linux/drivers/dax/pmem.c:122: undefined reference to `to_nd_region' drivers/built-in.o: In function `dax_pmem_init': linux/drivers/dax/pmem.c:147: undefined reference to `__nd_driver_register' Fix this by making NVDIMM_DAX a tristate. DEV_DAX_PMEM depends on NVDIMM_DAX which depends on LIBNVDIMM. Since they are all now tristates, if LIBNVDIMM is built as a kernel module DEV_DAX_PMEM will be as well. This prevents dax_devs.c from being built as a built-in while its dependencies are in the libnvdimm.ko module. Signed-off-by: Ross Zwisler Signed-off-by: Dan Williams --- drivers/nvdimm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nvdimm/Kconfig b/drivers/nvdimm/Kconfig index 124c2432ac9c..8b2b740d6679 100644 --- a/drivers/nvdimm/Kconfig +++ b/drivers/nvdimm/Kconfig @@ -89,7 +89,7 @@ config NVDIMM_PFN Select Y if unsure config NVDIMM_DAX - bool "NVDIMM DAX: Raw access to persistent memory" + tristate "NVDIMM DAX: Raw access to persistent memory" default LIBNVDIMM depends on NVDIMM_PFN help