1
0
Fork 0

DAX error handling for 4.7

- Until now, dax has been disabled if media errors were found on
   any device. This enables the use of DAX in the presence of these
   errors by making all sector-aligned zeroing go through the driver.
 - The driver (already) has the ability to clear errors on writes that
   are sent through the block layer using 'DSMs' defined in ACPI 6.1.
 
 Other misc changes:
 
 - When mounting DAX filesystems, check to make sure the partition
   is page aligned. This is a requirement for DAX, and previously, we
   allowed such unaligned mounts to succeed, but subsequent reads/writes
   would fail.
 
 - Misc/cleanup fixes from Jan that remove unused code from DAX related to
   zeroing, writeback, and some size checks.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJXQ4GKAAoJEHr6Yb6juE3/zowP/iclIhgXXXMQJRUHJlePMXC8
 15sGZ32JS1ak9g7vrsmNVEDNynfNtiMYdBxtUyRuj6xqgwdZvFk3F55KOCPtaeA1
 +yADkgeRkTAcwzmHw9WQVEzBCqyzSisdrwtEfH817qdq9FJdH66x2Kos6i+HeAVr
 5Q/e4gs7lKrjf384/QBl+wxNZOndJaQAPd2VRHQqx2A9F33v0ljdwRaUG1r4fjK2
 dtmhcZCqdQyuAGXW3piTnZc5ZFc3DPqO4FkEfqkEK3lFOflK0fd8wMsAZRp/Jd0j
 GJsgnVSWSqG0Dz476djlG0w8t2p5Jv1g9cKChV+ZZEdFLKWHCOUFqXNj8uI8I4k5
 cOEKCHyJ3IwfSHhNQqktEWrQN4T8ZXhWtuc9GuV4UZYuqJqHci6EdR/YsWsJjV+L
 lm/qvK4ipDS1pivxOy8KX/iN0z7Io8J9GXpStDx3g8iWjLlh4YYlbJLWeeRepo/z
 aPlV/QAKcHiGY6jzLExrZIyCWkzwo6O+0p1Kxerv9/7K/32HWbOodZ+tC8eD+N25
 pV69nCGf+u50T2TtIx1+iann4NC1r7zg5yqnT9AgpyZpiwR5joCDzI5sXW+D0rcS
 vPtfM84Ccdeq/e6mvfIpZgR0/npQapKnrmUest0J7P2BFPHiFPji1KzZ7M+1aFOo
 9R6JdrAj0Sc+FBa+cGzH
 =v6Of
 -----END PGP SIGNATURE-----

Merge tag 'dax-misc-for-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm

Pull misc DAX updates from Vishal Verma:
 "DAX error handling for 4.7

   - Until now, dax has been disabled if media errors were found on any
     device.  This enables the use of DAX in the presence of these
     errors by making all sector-aligned zeroing go through the driver.

   - The driver (already) has the ability to clear errors on writes that
     are sent through the block layer using 'DSMs' defined in ACPI 6.1.

  Other misc changes:

   - When mounting DAX filesystems, check to make sure the partition is
     page aligned.  This is a requirement for DAX, and previously, we
     allowed such unaligned mounts to succeed, but subsequent
     reads/writes would fail.

   - Misc/cleanup fixes from Jan that remove unused code from DAX
     related to zeroing, writeback, and some size checks"

* tag 'dax-misc-for-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm:
  dax: fix a comment in dax_zero_page_range and dax_truncate_page
  dax: for truncate/hole-punch, do zeroing through the driver if possible
  dax: export a low-level __dax_zero_page_range helper
  dax: use sb_issue_zerout instead of calling dax_clear_sectors
  dax: enable dax in the presence of known media errors (badblocks)
  dax: fallback from pmd to pte on error
  block: Update blkdev_dax_capable() for consistency
  xfs: Add alignment check for DAX mount
  ext2: Add alignment check for DAX mount
  ext4: Add alignment check for DAX mount
  block: Add bdev_dax_supported() for dax mount checks
  block: Add vfs_msg() interface
  dax: Remove redundant inode size checks
  dax: Remove pointless writeback from dax_do_io()
  dax: Remove zeroing from dax_io()
  dax: Remove dead zeroing code from fault handlers
  ext2: Avoid DAX zeroing to corrupt data
  ext2: Fix block zeroing in ext2_get_blocks() for DAX
  dax: Remove complete_unwritten argument
  DAX: move RADIX_DAX_ definitions to dax.c
hifive-unleashed-5.1
Linus Torvalds 2016-05-26 19:34:26 -07:00
commit 315227f6da
19 changed files with 246 additions and 293 deletions

View File

@ -79,6 +79,38 @@ These filesystems may be used for inspiration:
- ext4: the fourth extended filesystem, see Documentation/filesystems/ext4.txt - ext4: the fourth extended filesystem, see Documentation/filesystems/ext4.txt
Handling Media Errors
---------------------
The libnvdimm subsystem stores a record of known media error locations for
each pmem block device (in gendisk->badblocks). If we fault at such location,
or one with a latent error not yet discovered, the application can expect
to receive a SIGBUS. Libnvdimm also allows clearing of these errors by simply
writing the affected sectors (through the pmem driver, and if the underlying
NVDIMM supports the clear_poison DSM defined by ACPI).
Since DAX IO normally doesn't go through the driver/bio path, applications or
sysadmins have an option to restore the lost data from a prior backup/inbuilt
redundancy in the following ways:
1. Delete the affected file, and restore from a backup (sysadmin route):
This will free the file system blocks that were being used by the file,
and the next time they're allocated, they will be zeroed first, which
happens through the driver, and will clear bad sectors.
2. Truncate or hole-punch the part of the file that has a bad-block (at least
an entire aligned sector has to be hole-punched, but not necessarily an
entire filesystem block).
These are the two basic paths that allow DAX filesystems to continue operating
in the presence of media errors. More robust error recovery mechanisms can be
built on top of this in the future, for example, involving redundancy/mirroring
provided at the block layer through DM, or additionally, at the filesystem
level. These would have to rely on the above two tenets, that error clearing
can happen either by sending an IO through the driver, or zeroing (also through
the driver).
Shortcomings Shortcomings
------------ ------------

View File

@ -143,7 +143,7 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio)
*/ */
static long static long
axon_ram_direct_access(struct block_device *device, sector_t sector, axon_ram_direct_access(struct block_device *device, sector_t sector,
void __pmem **kaddr, pfn_t *pfn) void __pmem **kaddr, pfn_t *pfn, long size)
{ {
struct axon_ram_bank *bank = device->bd_disk->private_data; struct axon_ram_bank *bank = device->bd_disk->private_data;
loff_t offset = (loff_t)sector << AXON_RAM_SECTOR_SHIFT; loff_t offset = (loff_t)sector << AXON_RAM_SECTOR_SHIFT;

View File

@ -4,7 +4,6 @@
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/blkpg.h> #include <linux/blkpg.h>
#include <linux/hdreg.h> #include <linux/hdreg.h>
#include <linux/badblocks.h>
#include <linux/backing-dev.h> #include <linux/backing-dev.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/blktrace_api.h> #include <linux/blktrace_api.h>

View File

@ -381,7 +381,7 @@ static int brd_rw_page(struct block_device *bdev, sector_t sector,
#ifdef CONFIG_BLK_DEV_RAM_DAX #ifdef CONFIG_BLK_DEV_RAM_DAX
static long brd_direct_access(struct block_device *bdev, sector_t sector, static long brd_direct_access(struct block_device *bdev, sector_t sector,
void __pmem **kaddr, pfn_t *pfn) void __pmem **kaddr, pfn_t *pfn, long size)
{ {
struct brd_device *brd = bdev->bd_disk->private_data; struct brd_device *brd = bdev->bd_disk->private_data;
struct page *page; struct page *page;

View File

@ -164,14 +164,22 @@ static int pmem_rw_page(struct block_device *bdev, sector_t sector,
} }
static long pmem_direct_access(struct block_device *bdev, sector_t sector, static long pmem_direct_access(struct block_device *bdev, sector_t sector,
void __pmem **kaddr, pfn_t *pfn) void __pmem **kaddr, pfn_t *pfn, long size)
{ {
struct pmem_device *pmem = bdev->bd_queue->queuedata; struct pmem_device *pmem = bdev->bd_queue->queuedata;
resource_size_t offset = sector * 512 + pmem->data_offset; resource_size_t offset = sector * 512 + pmem->data_offset;
if (unlikely(is_bad_pmem(&pmem->bb, sector, size)))
return -EIO;
*kaddr = pmem->virt_addr + offset; *kaddr = pmem->virt_addr + offset;
*pfn = phys_to_pfn_t(pmem->phys_addr + offset, pmem->pfn_flags); *pfn = phys_to_pfn_t(pmem->phys_addr + offset, pmem->pfn_flags);
/*
* If badblocks are present, limit known good range to the
* requested range.
*/
if (unlikely(pmem->bb.count))
return size;
return pmem->size - pmem->pfn_pad - offset; return pmem->size - pmem->pfn_pad - offset;
} }

View File

@ -31,7 +31,7 @@ static void dcssblk_release(struct gendisk *disk, fmode_t mode);
static blk_qc_t dcssblk_make_request(struct request_queue *q, static blk_qc_t dcssblk_make_request(struct request_queue *q,
struct bio *bio); struct bio *bio);
static long dcssblk_direct_access(struct block_device *bdev, sector_t secnum, static long dcssblk_direct_access(struct block_device *bdev, sector_t secnum,
void __pmem **kaddr, pfn_t *pfn); void __pmem **kaddr, pfn_t *pfn, long size);
static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0"; static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0";
@ -884,7 +884,7 @@ fail:
static long static long
dcssblk_direct_access (struct block_device *bdev, sector_t secnum, dcssblk_direct_access (struct block_device *bdev, sector_t secnum,
void __pmem **kaddr, pfn_t *pfn) void __pmem **kaddr, pfn_t *pfn, long size)
{ {
struct dcssblk_dev_info *dev_info; struct dcssblk_dev_info *dev_info;
unsigned long offset, dev_sz; unsigned long offset, dev_sz;

View File

@ -51,6 +51,18 @@ struct block_device *I_BDEV(struct inode *inode)
} }
EXPORT_SYMBOL(I_BDEV); EXPORT_SYMBOL(I_BDEV);
void __vfs_msg(struct super_block *sb, const char *prefix, const char *fmt, ...)
{
struct va_format vaf;
va_list args;
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
printk_ratelimited("%sVFS (%s): %pV\n", prefix, sb->s_id, &vaf);
va_end(args);
}
static void bdev_write_inode(struct block_device *bdev) static void bdev_write_inode(struct block_device *bdev)
{ {
struct inode *inode = bdev->bd_inode; struct inode *inode = bdev->bd_inode;
@ -489,7 +501,7 @@ long bdev_direct_access(struct block_device *bdev, struct blk_dax_ctl *dax)
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, &dax->addr, &dax->pfn); avail = ops->direct_access(bdev, sector, &dax->addr, &dax->pfn, size);
if (!avail) if (!avail)
return -ERANGE; return -ERANGE;
if (avail > 0 && avail & ~PAGE_MASK) if (avail > 0 && avail & ~PAGE_MASK)
@ -498,6 +510,75 @@ 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);
/**
* 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 blk_dax_ctl dax = {
.sector = 0,
.size = PAGE_SIZE,
};
int err;
if (blocksize != PAGE_SIZE) {
vfs_msg(sb, KERN_ERR, "error: unsupported blocksize for dax");
return -EINVAL;
}
err = bdev_direct_access(sb->s_bdev, &dax);
if (err < 0) {
switch (err) {
case -EOPNOTSUPP:
vfs_msg(sb, KERN_ERR,
"error: device does not support dax");
break;
case -EINVAL:
vfs_msg(sb, KERN_ERR,
"error: unaligned partition for dax");
break;
default:
vfs_msg(sb, KERN_ERR,
"error: dax access failed (%d)", err);
}
return err;
}
return 0;
}
EXPORT_SYMBOL_GPL(bdev_dax_supported);
/**
* bdev_dax_capable() - Return if the raw device is capable for dax
* @bdev: The device for raw block device access
*/
bool bdev_dax_capable(struct block_device *bdev)
{
struct blk_dax_ctl dax = {
.size = PAGE_SIZE,
};
if (!IS_ENABLED(CONFIG_FS_DAX))
return false;
dax.sector = 0;
if (bdev_direct_access(bdev, &dax) < 0)
return false;
dax.sector = bdev->bd_part->nr_sects - (PAGE_SIZE / 512);
if (bdev_direct_access(bdev, &dax) < 0)
return false;
return true;
}
/* /*
* pseudo-fs * pseudo-fs
*/ */
@ -1160,33 +1241,6 @@ void bd_set_size(struct block_device *bdev, loff_t size)
} }
EXPORT_SYMBOL(bd_set_size); EXPORT_SYMBOL(bd_set_size);
static bool blkdev_dax_capable(struct block_device *bdev)
{
struct gendisk *disk = bdev->bd_disk;
if (!disk->fops->direct_access || !IS_ENABLED(CONFIG_FS_DAX))
return false;
/*
* If the partition is not aligned on a page boundary, we can't
* do dax I/O to it.
*/
if ((bdev->bd_part->start_sect % (PAGE_SIZE / 512))
|| (bdev->bd_part->nr_sects % (PAGE_SIZE / 512)))
return false;
/*
* If the device has known bad blocks, force all I/O through the
* driver / page cache.
*
* TODO: support finer grained dax error handling
*/
if (disk->bb && disk->bb->count)
return false;
return true;
}
static void __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part); static void __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part);
/* /*
@ -1266,7 +1320,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
if (!ret) { if (!ret) {
bd_set_size(bdev,(loff_t)get_capacity(disk)<<9); bd_set_size(bdev,(loff_t)get_capacity(disk)<<9);
if (!blkdev_dax_capable(bdev)) if (!bdev_dax_capable(bdev))
bdev->bd_inode->i_flags &= ~S_DAX; bdev->bd_inode->i_flags &= ~S_DAX;
} }
@ -1303,7 +1357,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
goto out_clear; goto out_clear;
} }
bd_set_size(bdev, (loff_t)bdev->bd_part->nr_sects << 9); bd_set_size(bdev, (loff_t)bdev->bd_part->nr_sects << 9);
if (!blkdev_dax_capable(bdev)) if (!bdev_dax_capable(bdev))
bdev->bd_inode->i_flags &= ~S_DAX; bdev->bd_inode->i_flags &= ~S_DAX;
} }
} else { } else {

257
fs/dax.c
View File

@ -87,50 +87,6 @@ struct page *read_dax_sector(struct block_device *bdev, sector_t n)
return page; return page;
} }
/*
* dax_clear_sectors() is called from within transaction context from XFS,
* and hence this means the stack from this point must follow GFP_NOFS
* semantics for all operations.
*/
int dax_clear_sectors(struct block_device *bdev, sector_t _sector, long _size)
{
struct blk_dax_ctl dax = {
.sector = _sector,
.size = _size,
};
might_sleep();
do {
long count, sz;
count = dax_map_atomic(bdev, &dax);
if (count < 0)
return count;
sz = min_t(long, count, SZ_128K);
clear_pmem(dax.addr, sz);
dax.size -= sz;
dax.sector += sz / 512;
dax_unmap_atomic(bdev, &dax);
cond_resched();
} while (dax.size);
wmb_pmem();
return 0;
}
EXPORT_SYMBOL_GPL(dax_clear_sectors);
/* the clear_pmem() calls are ordered by a wmb_pmem() in the caller */
static void dax_new_buf(void __pmem *addr, unsigned size, unsigned first,
loff_t pos, loff_t end)
{
loff_t final = end - pos + first; /* The final byte of the buffer */
if (first > 0)
clear_pmem(addr, first);
if (final < size)
clear_pmem(addr + final, size - final);
}
static bool buffer_written(struct buffer_head *bh) static bool buffer_written(struct buffer_head *bh)
{ {
return buffer_mapped(bh) && !buffer_unwritten(bh); return buffer_mapped(bh) && !buffer_unwritten(bh);
@ -169,6 +125,9 @@ static ssize_t dax_io(struct inode *inode, struct iov_iter *iter,
struct blk_dax_ctl dax = { struct blk_dax_ctl dax = {
.addr = (void __pmem *) ERR_PTR(-EIO), .addr = (void __pmem *) ERR_PTR(-EIO),
}; };
unsigned blkbits = inode->i_blkbits;
sector_t file_blks = (i_size_read(inode) + (1 << blkbits) - 1)
>> blkbits;
if (rw == READ) if (rw == READ)
end = min(end, i_size_read(inode)); end = min(end, i_size_read(inode));
@ -176,7 +135,6 @@ static ssize_t dax_io(struct inode *inode, struct iov_iter *iter,
while (pos < end) { while (pos < end) {
size_t len; size_t len;
if (pos == max) { if (pos == max) {
unsigned blkbits = inode->i_blkbits;
long page = pos >> PAGE_SHIFT; long page = pos >> PAGE_SHIFT;
sector_t block = page << (PAGE_SHIFT - blkbits); sector_t block = page << (PAGE_SHIFT - blkbits);
unsigned first = pos - (block << blkbits); unsigned first = pos - (block << blkbits);
@ -192,6 +150,13 @@ static ssize_t dax_io(struct inode *inode, struct iov_iter *iter,
bh->b_size = 1 << blkbits; bh->b_size = 1 << blkbits;
bh_max = pos - first + bh->b_size; bh_max = pos - first + bh->b_size;
bdev = bh->b_bdev; bdev = bh->b_bdev;
/*
* We allow uninitialized buffers for writes
* beyond EOF as those cannot race with faults
*/
WARN_ON_ONCE(
(buffer_new(bh) && block < file_blks) ||
(rw == WRITE && buffer_unwritten(bh)));
} else { } else {
unsigned done = bh->b_size - unsigned done = bh->b_size -
(bh_max - (pos - first)); (bh_max - (pos - first));
@ -211,11 +176,6 @@ static ssize_t dax_io(struct inode *inode, struct iov_iter *iter,
rc = map_len; rc = map_len;
break; break;
} }
if (buffer_unwritten(bh) || buffer_new(bh)) {
dax_new_buf(dax.addr, map_len, first,
pos, end);
need_wmb = true;
}
dax.addr += first; dax.addr += first;
size = map_len - first; size = map_len - first;
} }
@ -276,15 +236,8 @@ ssize_t dax_do_io(struct kiocb *iocb, struct inode *inode,
memset(&bh, 0, sizeof(bh)); memset(&bh, 0, sizeof(bh));
bh.b_bdev = inode->i_sb->s_bdev; bh.b_bdev = inode->i_sb->s_bdev;
if ((flags & DIO_LOCKING) && iov_iter_rw(iter) == READ) { if ((flags & DIO_LOCKING) && iov_iter_rw(iter) == READ)
struct address_space *mapping = inode->i_mapping;
inode_lock(inode); inode_lock(inode);
retval = filemap_write_and_wait_range(mapping, pos, end - 1);
if (retval) {
inode_unlock(inode);
goto out;
}
}
/* Protects against truncate */ /* Protects against truncate */
if (!(flags & DIO_SKIP_DIO_COUNT)) if (!(flags & DIO_SKIP_DIO_COUNT))
@ -305,7 +258,6 @@ ssize_t dax_do_io(struct kiocb *iocb, struct inode *inode,
if (!(flags & DIO_SKIP_DIO_COUNT)) if (!(flags & DIO_SKIP_DIO_COUNT))
inode_dio_end(inode); inode_dio_end(inode);
out:
return retval; return retval;
} }
EXPORT_SYMBOL_GPL(dax_do_io); EXPORT_SYMBOL_GPL(dax_do_io);
@ -321,20 +273,11 @@ EXPORT_SYMBOL_GPL(dax_do_io);
static int dax_load_hole(struct address_space *mapping, struct page *page, static int dax_load_hole(struct address_space *mapping, struct page *page,
struct vm_fault *vmf) struct vm_fault *vmf)
{ {
unsigned long size;
struct inode *inode = mapping->host;
if (!page) if (!page)
page = find_or_create_page(mapping, vmf->pgoff, page = find_or_create_page(mapping, vmf->pgoff,
GFP_KERNEL | __GFP_ZERO); GFP_KERNEL | __GFP_ZERO);
if (!page) if (!page)
return VM_FAULT_OOM; return VM_FAULT_OOM;
/* Recheck i_size under page lock to avoid truncate race */
size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT;
if (vmf->pgoff >= size) {
unlock_page(page);
put_page(page);
return VM_FAULT_SIGBUS;
}
vmf->page = page; vmf->page = page;
return VM_FAULT_LOCKED; return VM_FAULT_LOCKED;
@ -565,33 +508,14 @@ static int dax_insert_mapping(struct inode *inode, struct buffer_head *bh,
.sector = to_sector(bh, inode), .sector = to_sector(bh, inode),
.size = bh->b_size, .size = bh->b_size,
}; };
pgoff_t size;
int error; int error;
i_mmap_lock_read(mapping); i_mmap_lock_read(mapping);
/*
* Check truncate didn't happen while we were allocating a block.
* If it did, this block may or may not be still allocated to the
* file. We can't tell the filesystem to free it because we can't
* take i_mutex here. In the worst case, the file still has blocks
* allocated past the end of the file.
*/
size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT;
if (unlikely(vmf->pgoff >= size)) {
error = -EIO;
goto out;
}
if (dax_map_atomic(bdev, &dax) < 0) { if (dax_map_atomic(bdev, &dax) < 0) {
error = PTR_ERR(dax.addr); error = PTR_ERR(dax.addr);
goto out; goto out;
} }
if (buffer_unwritten(bh) || buffer_new(bh)) {
clear_pmem(dax.addr, PAGE_SIZE);
wmb_pmem();
}
dax_unmap_atomic(bdev, &dax); dax_unmap_atomic(bdev, &dax);
error = dax_radix_entry(mapping, vmf->pgoff, dax.sector, false, error = dax_radix_entry(mapping, vmf->pgoff, dax.sector, false,
@ -612,19 +536,13 @@ static int dax_insert_mapping(struct inode *inode, struct buffer_head *bh,
* @vma: The virtual memory area where the fault occurred * @vma: The virtual memory area where the fault occurred
* @vmf: The description of the fault * @vmf: The description of the fault
* @get_block: The filesystem method used to translate file offsets to blocks * @get_block: The filesystem method used to translate file offsets to blocks
* @complete_unwritten: The filesystem method used to convert unwritten blocks
* to written so the data written to them is exposed. This is required for
* required by write faults for filesystems that will return unwritten
* extent mappings from @get_block, but it is optional for reads as
* dax_insert_mapping() will always zero unwritten blocks. If the fs does
* not support unwritten extents, the it should pass NULL.
* *
* When a page fault occurs, filesystems may call this helper in their * When a page fault occurs, filesystems may call this helper in their
* fault handler for DAX files. __dax_fault() assumes the caller has done all * fault handler for DAX files. __dax_fault() assumes the caller has done all
* the necessary locking for the page fault to proceed successfully. * the necessary locking for the page fault to proceed successfully.
*/ */
int __dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf, int __dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf,
get_block_t get_block, dax_iodone_t complete_unwritten) get_block_t get_block)
{ {
struct file *file = vma->vm_file; struct file *file = vma->vm_file;
struct address_space *mapping = file->f_mapping; struct address_space *mapping = file->f_mapping;
@ -659,15 +577,6 @@ int __dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf,
put_page(page); put_page(page);
goto repeat; goto repeat;
} }
size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT;
if (unlikely(vmf->pgoff >= size)) {
/*
* We have a struct page covering a hole in the file
* from a read fault and we've raced with a truncate
*/
error = -EIO;
goto unlock_page;
}
} }
error = get_block(inode, block, &bh, 0); error = get_block(inode, block, &bh, 0);
@ -700,17 +609,8 @@ int __dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf,
if (error) if (error)
goto unlock_page; goto unlock_page;
vmf->page = page; vmf->page = page;
if (!page) { if (!page)
i_mmap_lock_read(mapping); i_mmap_lock_read(mapping);
/* Check we didn't race with truncate */
size = (i_size_read(inode) + PAGE_SIZE - 1) >>
PAGE_SHIFT;
if (vmf->pgoff >= size) {
i_mmap_unlock_read(mapping);
error = -EIO;
goto out;
}
}
return VM_FAULT_LOCKED; return VM_FAULT_LOCKED;
} }
@ -727,23 +627,9 @@ int __dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf,
page = NULL; page = NULL;
} }
/* /* Filesystem should not return unwritten buffers to us! */
* If we successfully insert the new mapping over an unwritten extent, WARN_ON_ONCE(buffer_unwritten(&bh) || buffer_new(&bh));
* we need to ensure we convert the unwritten extent. If there is an
* error inserting the mapping, the filesystem needs to leave it as
* unwritten to prevent exposure of the stale underlying data to
* userspace, but we still need to call the completion function so
* the private resources on the mapping buffer can be released. We
* indicate what the callback should do via the uptodate variable, same
* as for normal BH based IO completions.
*/
error = dax_insert_mapping(inode, &bh, vma, vmf); error = dax_insert_mapping(inode, &bh, vma, vmf);
if (buffer_unwritten(&bh)) {
if (complete_unwritten)
complete_unwritten(&bh, !error);
else
WARN_ON_ONCE(!(vmf->flags & FAULT_FLAG_WRITE));
}
out: out:
if (error == -ENOMEM) if (error == -ENOMEM)
@ -772,7 +658,7 @@ EXPORT_SYMBOL(__dax_fault);
* fault handler for DAX files. * fault handler for DAX files.
*/ */
int dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf, int dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf,
get_block_t get_block, dax_iodone_t complete_unwritten) get_block_t get_block)
{ {
int result; int result;
struct super_block *sb = file_inode(vma->vm_file)->i_sb; struct super_block *sb = file_inode(vma->vm_file)->i_sb;
@ -781,7 +667,7 @@ int dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf,
sb_start_pagefault(sb); sb_start_pagefault(sb);
file_update_time(vma->vm_file); file_update_time(vma->vm_file);
} }
result = __dax_fault(vma, vmf, get_block, complete_unwritten); result = __dax_fault(vma, vmf, get_block);
if (vmf->flags & FAULT_FLAG_WRITE) if (vmf->flags & FAULT_FLAG_WRITE)
sb_end_pagefault(sb); sb_end_pagefault(sb);
@ -815,8 +701,7 @@ static void __dax_dbg(struct buffer_head *bh, unsigned long address,
#define dax_pmd_dbg(bh, address, reason) __dax_dbg(bh, address, reason, "dax_pmd") #define dax_pmd_dbg(bh, address, reason) __dax_dbg(bh, address, reason, "dax_pmd")
int __dax_pmd_fault(struct vm_area_struct *vma, unsigned long address, int __dax_pmd_fault(struct vm_area_struct *vma, unsigned long address,
pmd_t *pmd, unsigned int flags, get_block_t get_block, pmd_t *pmd, unsigned int flags, get_block_t get_block)
dax_iodone_t complete_unwritten)
{ {
struct file *file = vma->vm_file; struct file *file = vma->vm_file;
struct address_space *mapping = file->f_mapping; struct address_space *mapping = file->f_mapping;
@ -875,6 +760,7 @@ int __dax_pmd_fault(struct vm_area_struct *vma, unsigned long address,
if (get_block(inode, block, &bh, 1) != 0) if (get_block(inode, block, &bh, 1) != 0)
return VM_FAULT_SIGBUS; return VM_FAULT_SIGBUS;
alloc = true; alloc = true;
WARN_ON_ONCE(buffer_unwritten(&bh) || buffer_new(&bh));
} }
bdev = bh.b_bdev; bdev = bh.b_bdev;
@ -902,23 +788,6 @@ int __dax_pmd_fault(struct vm_area_struct *vma, unsigned long address,
i_mmap_lock_read(mapping); i_mmap_lock_read(mapping);
/*
* If a truncate happened while we were allocating blocks, we may
* leave blocks allocated to the file that are beyond EOF. We can't
* take i_mutex here, so just leave them hanging; they'll be freed
* when the file is deleted.
*/
size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT;
if (pgoff >= size) {
result = VM_FAULT_SIGBUS;
goto out;
}
if ((pgoff | PG_PMD_COLOUR) >= size) {
dax_pmd_dbg(&bh, address,
"offset + huge page size > file size");
goto fallback;
}
if (!write && !buffer_mapped(&bh) && buffer_uptodate(&bh)) { if (!write && !buffer_mapped(&bh) && buffer_uptodate(&bh)) {
spinlock_t *ptl; spinlock_t *ptl;
pmd_t entry; pmd_t entry;
@ -954,8 +823,8 @@ int __dax_pmd_fault(struct vm_area_struct *vma, unsigned long address,
long length = dax_map_atomic(bdev, &dax); long length = dax_map_atomic(bdev, &dax);
if (length < 0) { if (length < 0) {
result = VM_FAULT_SIGBUS; dax_pmd_dbg(&bh, address, "dax-error fallback");
goto out; goto fallback;
} }
if (length < PMD_SIZE) { if (length < PMD_SIZE) {
dax_pmd_dbg(&bh, address, "dax-length too small"); dax_pmd_dbg(&bh, address, "dax-length too small");
@ -973,14 +842,6 @@ int __dax_pmd_fault(struct vm_area_struct *vma, unsigned long address,
dax_pmd_dbg(&bh, address, "pfn not in memmap"); dax_pmd_dbg(&bh, address, "pfn not in memmap");
goto fallback; goto fallback;
} }
if (buffer_unwritten(&bh) || buffer_new(&bh)) {
clear_pmem(dax.addr, PMD_SIZE);
wmb_pmem();
count_vm_event(PGMAJFAULT);
mem_cgroup_count_vm_event(vma->vm_mm, PGMAJFAULT);
result |= VM_FAULT_MAJOR;
}
dax_unmap_atomic(bdev, &dax); dax_unmap_atomic(bdev, &dax);
/* /*
@ -1020,9 +881,6 @@ int __dax_pmd_fault(struct vm_area_struct *vma, unsigned long address,
out: out:
i_mmap_unlock_read(mapping); i_mmap_unlock_read(mapping);
if (buffer_unwritten(&bh))
complete_unwritten(&bh, !(result & VM_FAULT_ERROR));
return result; return result;
fallback: fallback:
@ -1042,8 +900,7 @@ EXPORT_SYMBOL_GPL(__dax_pmd_fault);
* pmd_fault handler for DAX files. * pmd_fault handler for DAX files.
*/ */
int dax_pmd_fault(struct vm_area_struct *vma, unsigned long address, int dax_pmd_fault(struct vm_area_struct *vma, unsigned long address,
pmd_t *pmd, unsigned int flags, get_block_t get_block, pmd_t *pmd, unsigned int flags, get_block_t get_block)
dax_iodone_t complete_unwritten)
{ {
int result; int result;
struct super_block *sb = file_inode(vma->vm_file)->i_sb; struct super_block *sb = file_inode(vma->vm_file)->i_sb;
@ -1052,8 +909,7 @@ int dax_pmd_fault(struct vm_area_struct *vma, unsigned long address,
sb_start_pagefault(sb); sb_start_pagefault(sb);
file_update_time(vma->vm_file); file_update_time(vma->vm_file);
} }
result = __dax_pmd_fault(vma, address, pmd, flags, get_block, result = __dax_pmd_fault(vma, address, pmd, flags, get_block);
complete_unwritten);
if (flags & FAULT_FLAG_WRITE) if (flags & FAULT_FLAG_WRITE)
sb_end_pagefault(sb); sb_end_pagefault(sb);
@ -1091,6 +947,43 @@ int dax_pfn_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
} }
EXPORT_SYMBOL_GPL(dax_pfn_mkwrite); EXPORT_SYMBOL_GPL(dax_pfn_mkwrite);
static bool dax_range_is_aligned(struct block_device *bdev,
unsigned int offset, unsigned int length)
{
unsigned short sector_size = bdev_logical_block_size(bdev);
if (!IS_ALIGNED(offset, sector_size))
return false;
if (!IS_ALIGNED(length, sector_size))
return false;
return true;
}
int __dax_zero_page_range(struct block_device *bdev, sector_t sector,
unsigned int offset, unsigned int length)
{
struct blk_dax_ctl dax = {
.sector = sector,
.size = PAGE_SIZE,
};
if (dax_range_is_aligned(bdev, offset, length)) {
sector_t start_sector = dax.sector + (offset >> 9);
return blkdev_issue_zeroout(bdev, start_sector,
length >> 9, GFP_NOFS, true);
} else {
if (dax_map_atomic(bdev, &dax) < 0)
return PTR_ERR(dax.addr);
clear_pmem(dax.addr + offset, length);
wmb_pmem();
dax_unmap_atomic(bdev, &dax);
}
return 0;
}
EXPORT_SYMBOL_GPL(__dax_zero_page_range);
/** /**
* dax_zero_page_range - zero a range within a page of a DAX file * dax_zero_page_range - zero a range within a page of a DAX file
* @inode: The file being truncated * @inode: The file being truncated
@ -1102,12 +995,6 @@ EXPORT_SYMBOL_GPL(dax_pfn_mkwrite);
* page in a DAX file. This is intended for hole-punch operations. If * page in a DAX file. This is intended for hole-punch operations. If
* you are truncating a file, the helper function dax_truncate_page() may be * you are truncating a file, the helper function dax_truncate_page() may be
* more convenient. * more convenient.
*
* We work in terms of PAGE_SIZE here for commonality with
* block_truncate_page(), but we could go down to PAGE_SIZE if the filesystem
* took care of disposing of the unnecessary blocks. Even if the filesystem
* block size is smaller than PAGE_SIZE, we have to zero the rest of the page
* since the file might be mmapped.
*/ */
int dax_zero_page_range(struct inode *inode, loff_t from, unsigned length, int dax_zero_page_range(struct inode *inode, loff_t from, unsigned length,
get_block_t get_block) get_block_t get_block)
@ -1126,23 +1013,11 @@ int dax_zero_page_range(struct inode *inode, loff_t from, unsigned length,
bh.b_bdev = inode->i_sb->s_bdev; bh.b_bdev = inode->i_sb->s_bdev;
bh.b_size = PAGE_SIZE; bh.b_size = PAGE_SIZE;
err = get_block(inode, index, &bh, 0); err = get_block(inode, index, &bh, 0);
if (err < 0) if (err < 0 || !buffer_written(&bh))
return err; return err;
if (buffer_written(&bh)) {
struct block_device *bdev = bh.b_bdev;
struct blk_dax_ctl dax = {
.sector = to_sector(&bh, inode),
.size = PAGE_SIZE,
};
if (dax_map_atomic(bdev, &dax) < 0) return __dax_zero_page_range(bh.b_bdev, to_sector(&bh, inode),
return PTR_ERR(dax.addr); offset, length);
clear_pmem(dax.addr + offset, length);
wmb_pmem();
dax_unmap_atomic(bdev, &dax);
}
return 0;
} }
EXPORT_SYMBOL_GPL(dax_zero_page_range); EXPORT_SYMBOL_GPL(dax_zero_page_range);
@ -1154,12 +1029,6 @@ EXPORT_SYMBOL_GPL(dax_zero_page_range);
* *
* Similar to block_truncate_page(), this function can be called by a * Similar to block_truncate_page(), this function can be called by a
* filesystem when it is truncating a DAX file to handle the partial page. * filesystem when it is truncating a DAX file to handle the partial page.
*
* We work in terms of PAGE_SIZE here for commonality with
* block_truncate_page(), but we could go down to PAGE_SIZE if the filesystem
* took care of disposing of the unnecessary blocks. Even if the filesystem
* block size is smaller than PAGE_SIZE, we have to zero the rest of the page
* since the file might be mmapped.
*/ */
int dax_truncate_page(struct inode *inode, loff_t from, get_block_t get_block) int dax_truncate_page(struct inode *inode, loff_t from, get_block_t get_block)
{ {

View File

@ -51,7 +51,7 @@ static int ext2_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
} }
down_read(&ei->dax_sem); down_read(&ei->dax_sem);
ret = __dax_fault(vma, vmf, ext2_get_block, NULL); ret = __dax_fault(vma, vmf, ext2_get_block);
up_read(&ei->dax_sem); up_read(&ei->dax_sem);
if (vmf->flags & FAULT_FLAG_WRITE) if (vmf->flags & FAULT_FLAG_WRITE)
@ -72,7 +72,7 @@ static int ext2_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr,
} }
down_read(&ei->dax_sem); down_read(&ei->dax_sem);
ret = __dax_pmd_fault(vma, addr, pmd, flags, ext2_get_block, NULL); ret = __dax_pmd_fault(vma, addr, pmd, flags, ext2_get_block);
up_read(&ei->dax_sem); up_read(&ei->dax_sem);
if (flags & FAULT_FLAG_WRITE) if (flags & FAULT_FLAG_WRITE)

View File

@ -26,6 +26,7 @@
#include <linux/highuid.h> #include <linux/highuid.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/dax.h> #include <linux/dax.h>
#include <linux/blkdev.h>
#include <linux/quotaops.h> #include <linux/quotaops.h>
#include <linux/writeback.h> #include <linux/writeback.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
@ -737,19 +738,18 @@ static int ext2_get_blocks(struct inode *inode,
* so that it's not found by another thread before it's * so that it's not found by another thread before it's
* initialised * initialised
*/ */
err = dax_clear_sectors(inode->i_sb->s_bdev, err = sb_issue_zeroout(inode->i_sb,
le32_to_cpu(chain[depth-1].key) << le32_to_cpu(chain[depth-1].key), count,
(inode->i_blkbits - 9), GFP_NOFS);
1 << inode->i_blkbits);
if (err) { if (err) {
mutex_unlock(&ei->truncate_mutex); mutex_unlock(&ei->truncate_mutex);
goto cleanup; goto cleanup;
} }
} } else
set_buffer_new(bh_result);
ext2_splice_branch(inode, iblock, partial, indirect_blks, count); ext2_splice_branch(inode, iblock, partial, indirect_blks, count);
mutex_unlock(&ei->truncate_mutex); mutex_unlock(&ei->truncate_mutex);
set_buffer_new(bh_result);
got_it: got_it:
map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key)); map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key));
if (count > blocks_to_boundary) if (count > blocks_to_boundary)

View File

@ -922,16 +922,9 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
blocksize = BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size); blocksize = BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size);
if (sbi->s_mount_opt & EXT2_MOUNT_DAX) { if (sbi->s_mount_opt & EXT2_MOUNT_DAX) {
if (blocksize != PAGE_SIZE) { err = bdev_dax_supported(sb, blocksize);
ext2_msg(sb, KERN_ERR, if (err)
"error: unsupported blocksize for dax");
goto failed_mount; goto failed_mount;
}
if (!sb->s_bdev->bd_disk->fops->direct_access) {
ext2_msg(sb, KERN_ERR,
"error: device does not support dax");
goto failed_mount;
}
} }
/* If the blocksize doesn't match, re-read the thing.. */ /* If the blocksize doesn't match, re-read the thing.. */

View File

@ -202,7 +202,7 @@ static int ext4_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
if (IS_ERR(handle)) if (IS_ERR(handle))
result = VM_FAULT_SIGBUS; result = VM_FAULT_SIGBUS;
else else
result = __dax_fault(vma, vmf, ext4_dax_get_block, NULL); result = __dax_fault(vma, vmf, ext4_dax_get_block);
if (write) { if (write) {
if (!IS_ERR(handle)) if (!IS_ERR(handle))
@ -238,7 +238,7 @@ static int ext4_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr,
result = VM_FAULT_SIGBUS; result = VM_FAULT_SIGBUS;
else else
result = __dax_pmd_fault(vma, addr, pmd, flags, result = __dax_pmd_fault(vma, addr, pmd, flags,
ext4_dax_get_block, NULL); ext4_dax_get_block);
if (write) { if (write) {
if (!IS_ERR(handle)) if (!IS_ERR(handle))

View File

@ -3417,16 +3417,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
} }
if (sbi->s_mount_opt & EXT4_MOUNT_DAX) { if (sbi->s_mount_opt & EXT4_MOUNT_DAX) {
if (blocksize != PAGE_SIZE) { err = bdev_dax_supported(sb, blocksize);
ext4_msg(sb, KERN_ERR, if (err)
"error: unsupported blocksize for dax");
goto failed_mount; goto failed_mount;
}
if (!sb->s_bdev->bd_disk->fops->direct_access) {
ext4_msg(sb, KERN_ERR,
"error: device does not support dax");
goto failed_mount;
}
} }
if (ext4_has_feature_encrypt(sb) && es->s_encryption_level) { if (ext4_has_feature_encrypt(sb) && es->s_encryption_level) {

View File

@ -72,18 +72,11 @@ xfs_zero_extent(
struct xfs_mount *mp = ip->i_mount; struct xfs_mount *mp = ip->i_mount;
xfs_daddr_t sector = xfs_fsb_to_db(ip, start_fsb); xfs_daddr_t sector = xfs_fsb_to_db(ip, start_fsb);
sector_t block = XFS_BB_TO_FSBT(mp, sector); sector_t block = XFS_BB_TO_FSBT(mp, sector);
ssize_t size = XFS_FSB_TO_B(mp, count_fsb);
if (IS_DAX(VFS_I(ip)))
return dax_clear_sectors(xfs_find_bdev_for_inode(VFS_I(ip)),
sector, size);
/*
* let the block layer decide on the fastest method of
* implementing the zeroing.
*/
return sb_issue_zeroout(mp->m_super, block, count_fsb, GFP_NOFS);
return blkdev_issue_zeroout(xfs_find_bdev_for_inode(VFS_I(ip)),
block << (mp->m_super->s_blocksize_bits - 9),
count_fsb << (mp->m_super->s_blocksize_bits - 9),
GFP_NOFS, true);
} }
/* /*

View File

@ -1551,7 +1551,7 @@ xfs_filemap_page_mkwrite(
xfs_ilock(XFS_I(inode), XFS_MMAPLOCK_SHARED); xfs_ilock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
if (IS_DAX(inode)) { if (IS_DAX(inode)) {
ret = __dax_mkwrite(vma, vmf, xfs_get_blocks_dax_fault, NULL); ret = __dax_mkwrite(vma, vmf, xfs_get_blocks_dax_fault);
} else { } else {
ret = block_page_mkwrite(vma, vmf, xfs_get_blocks); ret = block_page_mkwrite(vma, vmf, xfs_get_blocks);
ret = block_page_mkwrite_return(ret); ret = block_page_mkwrite_return(ret);
@ -1585,7 +1585,7 @@ xfs_filemap_fault(
* changes to xfs_get_blocks_direct() to map unwritten extent * changes to xfs_get_blocks_direct() to map unwritten extent
* ioend for conversion on read-only mappings. * ioend for conversion on read-only mappings.
*/ */
ret = __dax_fault(vma, vmf, xfs_get_blocks_dax_fault, NULL); ret = __dax_fault(vma, vmf, xfs_get_blocks_dax_fault);
} else } else
ret = filemap_fault(vma, vmf); ret = filemap_fault(vma, vmf);
xfs_iunlock(XFS_I(inode), XFS_MMAPLOCK_SHARED); xfs_iunlock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
@ -1622,8 +1622,7 @@ xfs_filemap_pmd_fault(
} }
xfs_ilock(XFS_I(inode), XFS_MMAPLOCK_SHARED); xfs_ilock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
ret = __dax_pmd_fault(vma, addr, pmd, flags, xfs_get_blocks_dax_fault, ret = __dax_pmd_fault(vma, addr, pmd, flags, xfs_get_blocks_dax_fault);
NULL);
xfs_iunlock(XFS_I(inode), XFS_MMAPLOCK_SHARED); xfs_iunlock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
if (flags & FAULT_FLAG_WRITE) if (flags & FAULT_FLAG_WRITE)

View File

@ -1555,14 +1555,12 @@ xfs_fs_fill_super(
if (mp->m_flags & XFS_MOUNT_DAX) { if (mp->m_flags & XFS_MOUNT_DAX) {
xfs_warn(mp, xfs_warn(mp,
"DAX enabled. Warning: EXPERIMENTAL, use at your own risk"); "DAX enabled. Warning: EXPERIMENTAL, use at your own risk");
if (sb->s_blocksize != PAGE_SIZE) {
error = bdev_dax_supported(sb, sb->s_blocksize);
if (error) {
xfs_alert(mp, xfs_alert(mp,
"Filesystem block size invalid for DAX Turning DAX off."); "DAX unsupported by block device. Turning off DAX.");
mp->m_flags &= ~XFS_MOUNT_DAX;
} else if (!sb->s_bdev->bd_disk->fops->direct_access) {
xfs_alert(mp,
"Block device does not support DAX Turning DAX off.");
mp->m_flags &= ~XFS_MOUNT_DAX; mp->m_flags &= ~XFS_MOUNT_DAX;
} }
} }

View File

@ -768,6 +768,17 @@ static inline void rq_flush_dcache_pages(struct request *rq)
} }
#endif #endif
#ifdef CONFIG_PRINTK
#define vfs_msg(sb, level, fmt, ...) \
__vfs_msg(sb, level, fmt, ##__VA_ARGS__)
#else
#define vfs_msg(sb, level, fmt, ...) \
do { \
no_printk(fmt, ##__VA_ARGS__); \
__vfs_msg(sb, "", " "); \
} while (0)
#endif
extern int blk_register_queue(struct gendisk *disk); extern int blk_register_queue(struct gendisk *disk);
extern void blk_unregister_queue(struct gendisk *disk); extern void blk_unregister_queue(struct gendisk *disk);
extern blk_qc_t generic_make_request(struct bio *bio); extern blk_qc_t generic_make_request(struct bio *bio);
@ -1660,7 +1671,7 @@ struct block_device_operations {
int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long); int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long); int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
long (*direct_access)(struct block_device *, sector_t, void __pmem **, long (*direct_access)(struct block_device *, sector_t, void __pmem **,
pfn_t *); pfn_t *, long);
unsigned int (*check_events) (struct gendisk *disk, unsigned int (*check_events) (struct gendisk *disk,
unsigned int clearing); unsigned int clearing);
/* ->media_changed() is DEPRECATED, use ->check_events() instead */ /* ->media_changed() is DEPRECATED, use ->check_events() instead */
@ -1680,6 +1691,8 @@ 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 *, 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 bool bdev_dax_capable(struct block_device *);
#else /* CONFIG_BLOCK */ #else /* CONFIG_BLOCK */
struct block_device; struct block_device;

View File

@ -7,41 +7,44 @@
ssize_t dax_do_io(struct kiocb *, struct inode *, struct iov_iter *, ssize_t dax_do_io(struct kiocb *, struct inode *, struct iov_iter *,
get_block_t, dio_iodone_t, int flags); get_block_t, dio_iodone_t, int flags);
int dax_clear_sectors(struct block_device *bdev, sector_t _sector, long _size);
int dax_zero_page_range(struct inode *, loff_t from, unsigned len, get_block_t); int dax_zero_page_range(struct inode *, loff_t from, unsigned len, get_block_t);
int dax_truncate_page(struct inode *, loff_t from, get_block_t); int dax_truncate_page(struct inode *, loff_t from, get_block_t);
int dax_fault(struct vm_area_struct *, struct vm_fault *, get_block_t, int dax_fault(struct vm_area_struct *, struct vm_fault *, get_block_t);
dax_iodone_t); int __dax_fault(struct vm_area_struct *, struct vm_fault *, get_block_t);
int __dax_fault(struct vm_area_struct *, struct vm_fault *, get_block_t,
dax_iodone_t);
#ifdef CONFIG_FS_DAX #ifdef CONFIG_FS_DAX
struct page *read_dax_sector(struct block_device *bdev, sector_t n); struct page *read_dax_sector(struct block_device *bdev, sector_t n);
int __dax_zero_page_range(struct block_device *bdev, sector_t sector,
unsigned int offset, unsigned int length);
#else #else
static inline struct page *read_dax_sector(struct block_device *bdev, static inline struct page *read_dax_sector(struct block_device *bdev,
sector_t n) sector_t n)
{ {
return ERR_PTR(-ENXIO); return ERR_PTR(-ENXIO);
} }
static inline int __dax_zero_page_range(struct block_device *bdev,
sector_t sector, unsigned int offset, unsigned int length)
{
return -ENXIO;
}
#endif #endif
#ifdef CONFIG_TRANSPARENT_HUGEPAGE #ifdef CONFIG_TRANSPARENT_HUGEPAGE
int dax_pmd_fault(struct vm_area_struct *, unsigned long addr, pmd_t *, int dax_pmd_fault(struct vm_area_struct *, unsigned long addr, pmd_t *,
unsigned int flags, get_block_t, dax_iodone_t); unsigned int flags, get_block_t);
int __dax_pmd_fault(struct vm_area_struct *, unsigned long addr, pmd_t *, int __dax_pmd_fault(struct vm_area_struct *, unsigned long addr, pmd_t *,
unsigned int flags, get_block_t, dax_iodone_t); unsigned int flags, get_block_t);
#else #else
static inline int dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr, static inline int dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr,
pmd_t *pmd, unsigned int flags, get_block_t gb, pmd_t *pmd, unsigned int flags, get_block_t gb)
dax_iodone_t di)
{ {
return VM_FAULT_FALLBACK; return VM_FAULT_FALLBACK;
} }
#define __dax_pmd_fault dax_pmd_fault #define __dax_pmd_fault dax_pmd_fault
#endif #endif
int dax_pfn_mkwrite(struct vm_area_struct *, struct vm_fault *); int dax_pfn_mkwrite(struct vm_area_struct *, struct vm_fault *);
#define dax_mkwrite(vma, vmf, gb, iod) dax_fault(vma, vmf, gb, iod) #define dax_mkwrite(vma, vmf, gb) dax_fault(vma, vmf, gb)
#define __dax_mkwrite(vma, vmf, gb, iod) __dax_fault(vma, vmf, gb, iod) #define __dax_mkwrite(vma, vmf, gb) __dax_fault(vma, vmf, gb)
static inline bool vma_is_dax(struct vm_area_struct *vma) static inline bool vma_is_dax(struct vm_area_struct *vma)
{ {

View File

@ -74,7 +74,6 @@ typedef int (get_block_t)(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create); struct buffer_head *bh_result, int create);
typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset, typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
ssize_t bytes, void *private); ssize_t bytes, void *private);
typedef void (dax_iodone_t)(struct buffer_head *bh_map, int uptodate);
#define MAY_EXEC 0x00000001 #define MAY_EXEC 0x00000001
#define MAY_WRITE 0x00000002 #define MAY_WRITE 0x00000002