diff options
| author | Dan Williams <dan.j.williams@intel.com> | 2016-07-25 00:55:45 -0400 |
|---|---|---|
| committer | Dan Williams <dan.j.williams@intel.com> | 2016-08-24 01:58:51 -0400 |
| commit | 3bc52c45bac26bf7ed1dc8d287ad1aeaed1250b6 (patch) | |
| tree | 3ac261a353583b2490ce2b65a4da4941085308ea /drivers/dax | |
| parent | ba09c01d2fa866f22e42ac2af405fe386f491879 (diff) | |
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 <viro@zeniv.linux.org.uk>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/dax')
| -rw-r--r-- | drivers/dax/dax.c | 150 |
1 files changed, 146 insertions, 4 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 @@ | |||
| 13 | #include <linux/pagemap.h> | 13 | #include <linux/pagemap.h> |
| 14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
| 15 | #include <linux/device.h> | 15 | #include <linux/device.h> |
| 16 | #include <linux/mount.h> | ||
| 16 | #include <linux/pfn_t.h> | 17 | #include <linux/pfn_t.h> |
| 18 | #include <linux/hash.h> | ||
| 17 | #include <linux/cdev.h> | 19 | #include <linux/cdev.h> |
| 18 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
| 19 | #include <linux/dax.h> | 21 | #include <linux/dax.h> |
| @@ -26,6 +28,9 @@ static struct class *dax_class; | |||
| 26 | static DEFINE_IDA(dax_minor_ida); | 28 | static DEFINE_IDA(dax_minor_ida); |
| 27 | static int nr_dax = CONFIG_NR_DEV_DAX; | 29 | static int nr_dax = CONFIG_NR_DEV_DAX; |
| 28 | module_param(nr_dax, int, S_IRUGO); | 30 | module_param(nr_dax, int, S_IRUGO); |
| 31 | static struct vfsmount *dax_mnt; | ||
| 32 | static struct kmem_cache *dax_cache __read_mostly; | ||
| 33 | static struct super_block *dax_superblock __read_mostly; | ||
| 29 | MODULE_PARM_DESC(nr_dax, "max number of device-dax instances"); | 34 | MODULE_PARM_DESC(nr_dax, "max number of device-dax instances"); |
| 30 | 35 | ||
| 31 | /** | 36 | /** |
| @@ -61,6 +66,7 @@ struct dax_region { | |||
| 61 | */ | 66 | */ |
| 62 | struct dax_dev { | 67 | struct dax_dev { |
| 63 | struct dax_region *region; | 68 | struct dax_region *region; |
| 69 | struct inode *inode; | ||
| 64 | struct device dev; | 70 | struct device dev; |
| 65 | struct cdev cdev; | 71 | struct cdev cdev; |
| 66 | bool alive; | 72 | bool alive; |
| @@ -69,6 +75,117 @@ struct dax_dev { | |||
| 69 | struct resource res[0]; | 75 | struct resource res[0]; |
| 70 | }; | 76 | }; |
| 71 | 77 | ||
| 78 | static struct inode *dax_alloc_inode(struct super_block *sb) | ||
| 79 | { | ||
| 80 | return kmem_cache_alloc(dax_cache, GFP_KERNEL); | ||
| 81 | } | ||
| 82 | |||
| 83 | static void dax_i_callback(struct rcu_head *head) | ||
| 84 | { | ||
| 85 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
| 86 | |||
| 87 | kmem_cache_free(dax_cache, inode); | ||
| 88 | } | ||
| 89 | |||
| 90 | static void dax_destroy_inode(struct inode *inode) | ||
| 91 | { | ||
| 92 | call_rcu(&inode->i_rcu, dax_i_callback); | ||
| 93 | } | ||
| 94 | |||
| 95 | static const struct super_operations dax_sops = { | ||
| 96 | .statfs = simple_statfs, | ||
| 97 | .alloc_inode = dax_alloc_inode, | ||
| 98 | .destroy_inode = dax_destroy_inode, | ||
| 99 | .drop_inode = generic_delete_inode, | ||
| 100 | }; | ||
| 101 | |||
| 102 | static struct dentry *dax_mount(struct file_system_type *fs_type, | ||
| 103 | int flags, const char *dev_name, void *data) | ||
| 104 | { | ||
| 105 | return mount_pseudo(fs_type, "dax:", &dax_sops, NULL, DAXFS_MAGIC); | ||
| 106 | } | ||
| 107 | |||
| 108 | static struct file_system_type dax_type = { | ||
| 109 | .name = "dax", | ||
| 110 | .mount = dax_mount, | ||
| 111 | .kill_sb = kill_anon_super, | ||
| 112 | }; | ||
| 113 | |||
| 114 | static int dax_test(struct inode *inode, void *data) | ||
| 115 | { | ||
| 116 | return inode->i_cdev == data; | ||
| 117 | } | ||
| 118 | |||
| 119 | static int dax_set(struct inode *inode, void *data) | ||
| 120 | { | ||
| 121 | inode->i_cdev = data; | ||
| 122 | return 0; | ||
| 123 | } | ||
| 124 | |||
| 125 | static struct inode *dax_inode_get(struct cdev *cdev, dev_t devt) | ||
| 126 | { | ||
| 127 | struct inode *inode; | ||
| 128 | |||
| 129 | inode = iget5_locked(dax_superblock, hash_32(devt + DAXFS_MAGIC, 31), | ||
| 130 | dax_test, dax_set, cdev); | ||
| 131 | |||
| 132 | if (!inode) | ||
| 133 | return NULL; | ||
| 134 | |||
| 135 | if (inode->i_state & I_NEW) { | ||
| 136 | inode->i_mode = S_IFCHR; | ||
| 137 | inode->i_flags = S_DAX; | ||
| 138 | inode->i_rdev = devt; | ||
| 139 | mapping_set_gfp_mask(&inode->i_data, GFP_USER); | ||
| 140 | unlock_new_inode(inode); | ||
| 141 | } | ||
| 142 | return inode; | ||
| 143 | } | ||
| 144 | |||
| 145 | static void init_once(void *inode) | ||
| 146 | { | ||
| 147 | inode_init_once(inode); | ||
| 148 | } | ||
| 149 | |||
| 150 | static int dax_inode_init(void) | ||
| 151 | { | ||
| 152 | int rc; | ||
| 153 | |||
| 154 | dax_cache = kmem_cache_create("dax_cache", sizeof(struct inode), 0, | ||
| 155 | (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| | ||
| 156 | SLAB_MEM_SPREAD|SLAB_ACCOUNT), | ||
| 157 | init_once); | ||
| 158 | if (!dax_cache) | ||
| 159 | return -ENOMEM; | ||
| 160 | |||
| 161 | rc = register_filesystem(&dax_type); | ||
| 162 | if (rc) | ||
| 163 | goto err_register_fs; | ||
| 164 | |||
| 165 | dax_mnt = kern_mount(&dax_type); | ||
| 166 | if (IS_ERR(dax_mnt)) { | ||
| 167 | rc = PTR_ERR(dax_mnt); | ||
| 168 | goto err_mount; | ||
| 169 | } | ||
| 170 | dax_superblock = dax_mnt->mnt_sb; | ||
| 171 | |||
| 172 | return 0; | ||
| 173 | |||
| 174 | err_mount: | ||
| 175 | unregister_filesystem(&dax_type); | ||
| 176 | err_register_fs: | ||
| 177 | kmem_cache_destroy(dax_cache); | ||
| 178 | |||
| 179 | return rc; | ||
| 180 | } | ||
| 181 | |||
| 182 | static void dax_inode_exit(void) | ||
| 183 | { | ||
| 184 | kern_unmount(dax_mnt); | ||
| 185 | unregister_filesystem(&dax_type); | ||
| 186 | kmem_cache_destroy(dax_cache); | ||
| 187 | } | ||
| 188 | |||
| 72 | static void dax_region_free(struct kref *kref) | 189 | static void dax_region_free(struct kref *kref) |
| 73 | { | 190 | { |
| 74 | struct dax_region *dax_region; | 191 | struct dax_region *dax_region; |
| @@ -379,6 +496,9 @@ static int dax_open(struct inode *inode, struct file *filp) | |||
| 379 | 496 | ||
| 380 | dax_dev = container_of(inode->i_cdev, struct dax_dev, cdev); | 497 | dax_dev = container_of(inode->i_cdev, struct dax_dev, cdev); |
| 381 | dev_dbg(&dax_dev->dev, "%s\n", __func__); | 498 | dev_dbg(&dax_dev->dev, "%s\n", __func__); |
| 499 | inode->i_mapping = dax_dev->inode->i_mapping; | ||
| 500 | inode->i_mapping->host = dax_dev->inode; | ||
| 501 | filp->f_mapping = inode->i_mapping; | ||
| 382 | filp->private_data = dax_dev; | 502 | filp->private_data = dax_dev; |
| 383 | inode->i_flags = S_DAX; | 503 | inode->i_flags = S_DAX; |
| 384 | 504 | ||
| @@ -410,6 +530,7 @@ static void dax_dev_release(struct device *dev) | |||
| 410 | ida_simple_remove(&dax_region->ida, dax_dev->id); | 530 | ida_simple_remove(&dax_region->ida, dax_dev->id); |
| 411 | ida_simple_remove(&dax_minor_ida, MINOR(dev->devt)); | 531 | ida_simple_remove(&dax_minor_ida, MINOR(dev->devt)); |
| 412 | dax_region_put(dax_region); | 532 | dax_region_put(dax_region); |
| 533 | iput(dax_dev->inode); | ||
| 413 | kfree(dax_dev); | 534 | kfree(dax_dev); |
| 414 | } | 535 | } |
| 415 | 536 | ||
| @@ -459,6 +580,12 @@ int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res, | |||
| 459 | goto err_minor; | 580 | goto err_minor; |
| 460 | } | 581 | } |
| 461 | 582 | ||
| 583 | dax_dev->inode = dax_inode_get(&dax_dev->cdev, dev_t); | ||
| 584 | if (!dax_dev->inode) { | ||
| 585 | rc = -ENOMEM; | ||
| 586 | goto err_inode; | ||
| 587 | } | ||
| 588 | |||
| 462 | /* device_initialize() so cdev can reference kobj parent */ | 589 | /* device_initialize() so cdev can reference kobj parent */ |
| 463 | dev_t = MKDEV(MAJOR(dax_devt), minor); | 590 | dev_t = MKDEV(MAJOR(dax_devt), minor); |
| 464 | dev = &dax_dev->dev; | 591 | dev = &dax_dev->dev; |
| @@ -494,6 +621,8 @@ int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res, | |||
| 494 | return devm_add_action_or_reset(dax_region->dev, unregister_dax_dev, dev); | 621 | return devm_add_action_or_reset(dax_region->dev, unregister_dax_dev, dev); |
| 495 | 622 | ||
| 496 | err_cdev: | 623 | err_cdev: |
| 624 | iput(dax_dev->inode); | ||
| 625 | err_inode: | ||
| 497 | ida_simple_remove(&dax_minor_ida, minor); | 626 | ida_simple_remove(&dax_minor_ida, minor); |
| 498 | err_minor: | 627 | err_minor: |
| 499 | ida_simple_remove(&dax_region->ida, dax_dev->id); | 628 | ida_simple_remove(&dax_region->ida, dax_dev->id); |
| @@ -508,16 +637,28 @@ static int __init dax_init(void) | |||
| 508 | { | 637 | { |
| 509 | int rc; | 638 | int rc; |
| 510 | 639 | ||
| 640 | rc = dax_inode_init(); | ||
| 641 | if (rc) | ||
| 642 | return rc; | ||
| 643 | |||
| 511 | nr_dax = max(nr_dax, 256); | 644 | nr_dax = max(nr_dax, 256); |
| 512 | rc = alloc_chrdev_region(&dax_devt, 0, nr_dax, "dax"); | 645 | rc = alloc_chrdev_region(&dax_devt, 0, nr_dax, "dax"); |
| 513 | if (rc) | 646 | if (rc) |
| 514 | return rc; | 647 | goto err_chrdev; |
| 515 | 648 | ||
| 516 | dax_class = class_create(THIS_MODULE, "dax"); | 649 | dax_class = class_create(THIS_MODULE, "dax"); |
| 517 | if (IS_ERR(dax_class)) | 650 | if (IS_ERR(dax_class)) { |
| 518 | unregister_chrdev_region(dax_devt, nr_dax); | 651 | rc = PTR_ERR(dax_class); |
| 652 | goto err_class; | ||
| 653 | } | ||
| 519 | 654 | ||
| 520 | return PTR_ERR_OR_ZERO(dax_class); | 655 | return 0; |
| 656 | |||
| 657 | err_class: | ||
| 658 | unregister_chrdev_region(dax_devt, nr_dax); | ||
| 659 | err_chrdev: | ||
| 660 | dax_inode_exit(); | ||
| 661 | return rc; | ||
| 521 | } | 662 | } |
| 522 | 663 | ||
| 523 | static void __exit dax_exit(void) | 664 | static void __exit dax_exit(void) |
| @@ -525,6 +666,7 @@ static void __exit dax_exit(void) | |||
| 525 | class_destroy(dax_class); | 666 | class_destroy(dax_class); |
| 526 | unregister_chrdev_region(dax_devt, nr_dax); | 667 | unregister_chrdev_region(dax_devt, nr_dax); |
| 527 | ida_destroy(&dax_minor_ida); | 668 | ida_destroy(&dax_minor_ida); |
| 669 | dax_inode_exit(); | ||
| 528 | } | 670 | } |
| 529 | 671 | ||
| 530 | MODULE_AUTHOR("Intel Corporation"); | 672 | MODULE_AUTHOR("Intel Corporation"); |
