Commit b2e0d162 authored by Dan Williams's avatar Dan Williams Committed by Linus Torvalds

dax: fix lifetime of in-kernel dax mappings with dax_map_atomic()

The DAX implementation needs to protect new calls to ->direct_access()
and usage of its return value against the driver for the underlying
block device being disabled.  Use blk_queue_enter()/blk_queue_exit() to
hold off blk_cleanup_queue() from proceeding, or otherwise fail new
mapping requests if the request_queue is being torn down.

This also introduces blk_dax_ctl to simplify the interface from fs/dax.c
through dax_map_atomic() to bdev_direct_access().

[willy@linux.intel.com: fix read() of a hole]
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
Reviewed-by: default avatarJeff Moyer <jmoyer@redhat.com>
Cc: Jan Kara <jack@suse.com>
Cc: Jens Axboe <axboe@fb.com>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Ross Zwisler <ross.zwisler@linux.intel.com>
Cc: Matthew Wilcox <willy@linux.intel.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent fe683ada
...@@ -455,10 +455,7 @@ EXPORT_SYMBOL_GPL(bdev_write_page); ...@@ -455,10 +455,7 @@ EXPORT_SYMBOL_GPL(bdev_write_page);
/** /**
* bdev_direct_access() - Get the address for directly-accessibly memory * bdev_direct_access() - Get the address for directly-accessibly memory
* @bdev: The device containing the memory * @bdev: The device containing the memory
* @sector: The offset within the device * @dax: control and output parameters for ->direct_access
* @addr: Where to put the address of the memory
* @pfn: The Page Frame Number for the memory
* @size: The number of bytes requested
* *
* If a block device is made up of directly addressable memory, this function * If a block device is made up of directly addressable memory, this function
* will tell the caller the PFN and the address of the memory. The address * will tell the caller the PFN and the address of the memory. The address
...@@ -469,10 +466,10 @@ EXPORT_SYMBOL_GPL(bdev_write_page); ...@@ -469,10 +466,10 @@ EXPORT_SYMBOL_GPL(bdev_write_page);
* Return: negative errno if an error occurs, otherwise the number of bytes * Return: negative errno if an error occurs, otherwise the number of bytes
* accessible at this address. * accessible at this address.
*/ */
long bdev_direct_access(struct block_device *bdev, sector_t sector, long bdev_direct_access(struct block_device *bdev, struct blk_dax_ctl *dax)
void __pmem **addr, unsigned long *pfn, long size)
{ {
long avail; sector_t sector = dax->sector;
long avail, size = dax->size;
const struct block_device_operations *ops = bdev->bd_disk->fops; const struct block_device_operations *ops = bdev->bd_disk->fops;
/* /*
...@@ -491,7 +488,7 @@ long bdev_direct_access(struct block_device *bdev, sector_t sector, ...@@ -491,7 +488,7 @@ long bdev_direct_access(struct block_device *bdev, sector_t sector,
sector += get_start_sect(bdev); sector += get_start_sect(bdev);
if (sector % (PAGE_SIZE / 512)) if (sector % (PAGE_SIZE / 512))
return -EINVAL; return -EINVAL;
avail = ops->direct_access(bdev, sector, addr, pfn); avail = ops->direct_access(bdev, sector, &dax->addr, &dax->pfn);
if (!avail) if (!avail)
return -ERANGE; return -ERANGE;
if (avail > 0 && avail & ~PAGE_MASK) if (avail > 0 && avail & ~PAGE_MASK)
......
This diff is collapsed.
...@@ -1617,6 +1617,20 @@ static inline bool integrity_req_gap_front_merge(struct request *req, ...@@ -1617,6 +1617,20 @@ static inline bool integrity_req_gap_front_merge(struct request *req,
#endif /* CONFIG_BLK_DEV_INTEGRITY */ #endif /* CONFIG_BLK_DEV_INTEGRITY */
/**
* struct blk_dax_ctl - control and output parameters for ->direct_access
* @sector: (input) offset relative to a block_device
* @addr: (output) kernel virtual address for @sector populated by driver
* @pfn: (output) page frame number for @addr populated by driver
* @size: (input) number of bytes requested
*/
struct blk_dax_ctl {
sector_t sector;
void __pmem *addr;
long size;
unsigned long pfn;
};
struct block_device_operations { struct block_device_operations {
int (*open) (struct block_device *, fmode_t); int (*open) (struct block_device *, fmode_t);
void (*release) (struct gendisk *, fmode_t); void (*release) (struct gendisk *, fmode_t);
...@@ -1643,8 +1657,7 @@ extern int __blkdev_driver_ioctl(struct block_device *, fmode_t, unsigned int, ...@@ -1643,8 +1657,7 @@ extern int __blkdev_driver_ioctl(struct block_device *, fmode_t, unsigned int,
extern int bdev_read_page(struct block_device *, sector_t, struct page *); extern int bdev_read_page(struct block_device *, sector_t, struct page *);
extern int bdev_write_page(struct block_device *, sector_t, struct page *, 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 *, sector_t, extern long bdev_direct_access(struct block_device *, struct blk_dax_ctl *);
void __pmem **addr, unsigned long *pfn, long size);
#else /* CONFIG_BLOCK */ #else /* CONFIG_BLOCK */
struct block_device; struct block_device;
......
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