diff options
Diffstat (limited to 'drivers/dax/super.c')
| -rw-r--r-- | drivers/dax/super.c | 92 | 
1 files changed, 82 insertions, 10 deletions
diff --git a/drivers/dax/super.c b/drivers/dax/super.c index 465dcd7317d5..922d0823f8ec 100644 --- a/drivers/dax/super.c +++ b/drivers/dax/super.c @@ -14,16 +14,13 @@  #include <linux/module.h>  #include <linux/mount.h>  #include <linux/magic.h> +#include <linux/genhd.h>  #include <linux/cdev.h>  #include <linux/hash.h>  #include <linux/slab.h>  #include <linux/dax.h>  #include <linux/fs.h> -static int nr_dax = CONFIG_NR_DEV_DAX; -module_param(nr_dax, int, S_IRUGO); -MODULE_PARM_DESC(nr_dax, "max number of dax device instances"); -  static dev_t dax_devt;  DEFINE_STATIC_SRCU(dax_srcu);  static struct vfsmount *dax_mnt; @@ -47,6 +44,77 @@ void dax_read_unlock(int id)  }  EXPORT_SYMBOL_GPL(dax_read_unlock); +#ifdef CONFIG_BLOCK +int bdev_dax_pgoff(struct block_device *bdev, sector_t sector, size_t size, +		pgoff_t *pgoff) +{ +	phys_addr_t phys_off = (get_start_sect(bdev) + sector) * 512; + +	if (pgoff) +		*pgoff = PHYS_PFN(phys_off); +	if (phys_off % PAGE_SIZE || size % PAGE_SIZE) +		return -EINVAL; +	return 0; +} +EXPORT_SYMBOL(bdev_dax_pgoff); + +/** + * __bdev_dax_supported() - Check if the device supports dax for filesystem + * @sb: The superblock of the device + * @blocksize: The block size of the device + * + * This is a library function for filesystems to check if the block device + * can be mounted with dax option. + * + * Return: negative errno if unsupported, 0 if supported. + */ +int __bdev_dax_supported(struct super_block *sb, int blocksize) +{ +	struct block_device *bdev = sb->s_bdev; +	struct dax_device *dax_dev; +	pgoff_t pgoff; +	int err, id; +	void *kaddr; +	pfn_t pfn; +	long len; + +	if (blocksize != PAGE_SIZE) { +		pr_err("VFS (%s): error: unsupported blocksize for dax\n", +				sb->s_id); +		return -EINVAL; +	} + +	err = bdev_dax_pgoff(bdev, 0, PAGE_SIZE, &pgoff); +	if (err) { +		pr_err("VFS (%s): error: unaligned partition for dax\n", +				sb->s_id); +		return err; +	} + +	dax_dev = dax_get_by_host(bdev->bd_disk->disk_name); +	if (!dax_dev) { +		pr_err("VFS (%s): error: device does not support dax\n", +				sb->s_id); +		return -EOPNOTSUPP; +	} + +	id = dax_read_lock(); +	len = dax_direct_access(dax_dev, pgoff, 1, &kaddr, &pfn); +	dax_read_unlock(id); + +	put_dax(dax_dev); + +	if (len < 1) { +		pr_err("VFS (%s): error: dax access failed (%ld)", +				sb->s_id, len); +		return len < 0 ? len : -EIO; +	} + +	return 0; +} +EXPORT_SYMBOL_GPL(__bdev_dax_supported); +#endif +  /**   * struct dax_device - anchor object for dax services   * @inode: core vfs @@ -142,9 +210,12 @@ EXPORT_SYMBOL_GPL(kill_dax);  static struct inode *dax_alloc_inode(struct super_block *sb)  {  	struct dax_device *dax_dev; +	struct inode *inode;  	dax_dev = kmem_cache_alloc(dax_cache, GFP_KERNEL); -	return &dax_dev->inode; +	inode = &dax_dev->inode; +	inode->i_rdev = 0; +	return inode;  }  static struct dax_device *to_dax_dev(struct inode *inode) @@ -159,7 +230,8 @@ static void dax_i_callback(struct rcu_head *head)  	kfree(dax_dev->host);  	dax_dev->host = NULL; -	ida_simple_remove(&dax_minor_ida, MINOR(inode->i_rdev)); +	if (inode->i_rdev) +		ida_simple_remove(&dax_minor_ida, MINOR(inode->i_rdev));  	kmem_cache_free(dax_cache, dax_dev);  } @@ -261,7 +333,7 @@ struct dax_device *alloc_dax(void *private, const char *__host,  	if (__host && !host)  		return NULL; -	minor = ida_simple_get(&dax_minor_ida, 0, nr_dax, GFP_KERNEL); +	minor = ida_simple_get(&dax_minor_ida, 0, MINORMASK+1, GFP_KERNEL);  	if (minor < 0)  		goto err_minor; @@ -355,6 +427,7 @@ static void init_once(void *_dax_dev)  	struct dax_device *dax_dev = _dax_dev;  	struct inode *inode = &dax_dev->inode; +	memset(dax_dev, 0, sizeof(*dax_dev));  	inode_init_once(inode);  } @@ -405,8 +478,7 @@ static int __init dax_fs_init(void)  	if (rc)  		return rc; -	nr_dax = max(nr_dax, 256); -	rc = alloc_chrdev_region(&dax_devt, 0, nr_dax, "dax"); +	rc = alloc_chrdev_region(&dax_devt, 0, MINORMASK+1, "dax");  	if (rc)  		__dax_fs_exit();  	return rc; @@ -414,7 +486,7 @@ static int __init dax_fs_init(void)  static void __exit dax_fs_exit(void)  { -	unregister_chrdev_region(dax_devt, nr_dax); +	unregister_chrdev_region(dax_devt, MINORMASK+1);  	ida_destroy(&dax_minor_ida);  	__dax_fs_exit();  }  |