Commit b0686260 authored by Dan Williams's avatar Dan Williams

dax: introduce dax_direct_access()

Replace bdev_direct_access() with dax_direct_access() that uses
dax_device and dax_operations instead of a block_device and
block_device_operations for dax. Once all consumers of the old api have
been converted bdev_direct_access() will be deleted.

Given that block device partitioning decisions can cause dax page
alignment constraints to be violated this also introduces the
bdev_dax_pgoff() helper. It handles calculating a logical pgoff relative
to the dax_device and also checks for page alignment.
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent d8f07aee
...@@ -6,6 +6,7 @@ menuconfig BLOCK ...@@ -6,6 +6,7 @@ menuconfig BLOCK
default y default y
select SBITMAP select SBITMAP
select SRCU select SRCU
select DAX
help help
Provide block layer support for the kernel. Provide block layer support for the kernel.
......
...@@ -65,6 +65,45 @@ struct dax_device { ...@@ -65,6 +65,45 @@ struct dax_device {
const struct dax_operations *ops; const struct dax_operations *ops;
}; };
/**
* dax_direct_access() - translate a device pgoff to an absolute pfn
* @dax_dev: a dax_device instance representing the logical memory range
* @pgoff: offset in pages from the start of the device to translate
* @nr_pages: number of consecutive pages caller can handle relative to @pfn
* @kaddr: output parameter that returns a virtual address mapping of pfn
* @pfn: output parameter that returns an absolute pfn translation of @pgoff
*
* Return: negative errno if an error occurs, otherwise the number of
* pages accessible at the device relative @pgoff.
*/
long dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff, long nr_pages,
void **kaddr, pfn_t *pfn)
{
long avail;
/*
* The device driver is allowed to sleep, in order to make the
* memory directly accessible.
*/
might_sleep();
if (!dax_dev)
return -EOPNOTSUPP;
if (!dax_alive(dax_dev))
return -ENXIO;
if (nr_pages < 0)
return nr_pages;
avail = dax_dev->ops->direct_access(dax_dev, pgoff, nr_pages,
kaddr, pfn);
if (!avail)
return -ERANGE;
return min(avail, nr_pages);
}
EXPORT_SYMBOL_GPL(dax_direct_access);
bool dax_alive(struct dax_device *dax_dev) bool dax_alive(struct dax_device *dax_dev)
{ {
lockdep_assert_held(&dax_srcu); lockdep_assert_held(&dax_srcu);
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/blkpg.h> #include <linux/blkpg.h>
#include <linux/magic.h> #include <linux/magic.h>
#include <linux/dax.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/pagevec.h> #include <linux/pagevec.h>
...@@ -762,6 +763,19 @@ long bdev_direct_access(struct block_device *bdev, struct blk_dax_ctl *dax) ...@@ -762,6 +763,19 @@ long bdev_direct_access(struct block_device *bdev, struct blk_dax_ctl *dax)
} }
EXPORT_SYMBOL_GPL(bdev_direct_access); EXPORT_SYMBOL_GPL(bdev_direct_access);
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 * bdev_dax_supported() - Check if the device supports dax for filesystem
* @sb: The superblock of the device * @sb: The superblock of the device
......
...@@ -1958,6 +1958,7 @@ extern int bdev_write_page(struct block_device *, sector_t, struct page *, ...@@ -1958,6 +1958,7 @@ extern int bdev_write_page(struct block_device *, sector_t, struct page *,
struct writeback_control *); struct writeback_control *);
extern long bdev_direct_access(struct block_device *, struct blk_dax_ctl *); extern long bdev_direct_access(struct block_device *, struct blk_dax_ctl *);
extern int bdev_dax_supported(struct super_block *, int); extern int bdev_dax_supported(struct super_block *, int);
int bdev_dax_pgoff(struct block_device *, sector_t, size_t, pgoff_t *pgoff);
#else /* CONFIG_BLOCK */ #else /* CONFIG_BLOCK */
struct block_device; struct block_device;
......
...@@ -27,6 +27,8 @@ void put_dax(struct dax_device *dax_dev); ...@@ -27,6 +27,8 @@ void put_dax(struct dax_device *dax_dev);
bool dax_alive(struct dax_device *dax_dev); bool dax_alive(struct dax_device *dax_dev);
void kill_dax(struct dax_device *dax_dev); void kill_dax(struct dax_device *dax_dev);
void *dax_get_private(struct dax_device *dax_dev); void *dax_get_private(struct dax_device *dax_dev);
long dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff, long nr_pages,
void **kaddr, pfn_t *pfn);
/* /*
* We use lowest available bit in exceptional entry for locking, one bit for * We use lowest available bit in exceptional entry for locking, one bit for
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment