Skip to content

Commit 5fac740

Browse files
committed
mm, fs, dax: handle layout changes to pinned dax mappings
Background: get_user_pages() in the filesystem pins file backed memory pages for access by devices performing dma. However, it only pins the memory pages not the page-to-file offset association. If a file is truncated the pages are mapped out of the file and dma may continue indefinitely into a page that is owned by a device driver. This breaks coherency of the file vs dma, but the assumption is that if userspace wants the file-space truncated it does not matter what data is inbound from the device, it is not relevant anymore. The only expectation is that dma can safely continue while the filesystem reallocates the block(s). Problem: This expectation that dma can safely continue while the filesystem changes the block map is broken by dax. With dax the target dma page *is* the filesystem block. The model of leaving the page pinned for dma, but truncating the file block out of the file, means that the filesytem is free to reallocate a block under active dma to another file and now the expected data-incoherency situation has turned into active data-corruption. Solution: Defer all filesystem operations (fallocate(), truncate()) on a dax mode file while any page/block in the file is under active dma. This solution assumes that dma is transient. Cases where dma operations are known to not be transient, like RDMA, have been explicitly disabled via commits like 5f1d43d "IB/core: disable memory registration of filesystem-dax vmas". The dax_layout_busy_page() routine is called by filesystems with a lock held against mm faults (i_mmap_lock) to find pinned / busy dax pages. The process of looking up a busy page invalidates all mappings to trigger any subsequent get_user_pages() to block on i_mmap_lock. The filesystem continues to call dax_layout_busy_page() until it finally returns no more active pages. This approach assumes that the page pinning is transient, if that assumption is violated the system would have likely hung from the uncompleted I/O. Cc: Jeff Moyer <jmoyer@redhat.com> Cc: Dave Chinner <david@fromorbit.com> Cc: Matthew Wilcox <mawilcox@microsoft.com> Cc: Alexander Viro <viro@zeniv.linux.org.uk> Cc: "Darrick J. Wong" <darrick.wong@oracle.com> Cc: Ross Zwisler <ross.zwisler@linux.intel.com> Cc: Dave Hansen <dave.hansen@linux.intel.com> Cc: Andrew Morton <akpm@linux-foundation.org> Reported-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Jan Kara <jack@suse.cz> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
1 parent a9b6de7 commit 5fac740

File tree

2 files changed

+104
-0
lines changed

2 files changed

+104
-0
lines changed

fs/dax.c

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,19 @@ static void dax_disassociate_entry(void *entry, struct address_space *mapping,
351351
}
352352
}
353353

354+
static struct page *dax_busy_page(void *entry)
355+
{
356+
unsigned long pfn;
357+
358+
for_each_mapped_pfn(entry, pfn) {
359+
struct page *page = pfn_to_page(pfn);
360+
361+
if (page_ref_count(page) > 1)
362+
return page;
363+
}
364+
return NULL;
365+
}
366+
354367
/*
355368
* Find radix tree entry at given index. If it points to an exceptional entry,
356369
* return it with the radix tree entry locked. If the radix tree doesn't
@@ -492,6 +505,90 @@ static void *grab_mapping_entry(struct address_space *mapping, pgoff_t index,
492505
return entry;
493506
}
494507

508+
/**
509+
* dax_layout_busy_page - find first pinned page in @mapping
510+
* @mapping: address space to scan for a page with ref count > 1
511+
*
512+
* DAX requires ZONE_DEVICE mapped pages. These pages are never
513+
* 'onlined' to the page allocator so they are considered idle when
514+
* page->count == 1. A filesystem uses this interface to determine if
515+
* any page in the mapping is busy, i.e. for DMA, or other
516+
* get_user_pages() usages.
517+
*
518+
* It is expected that the filesystem is holding locks to block the
519+
* establishment of new mappings in this address_space. I.e. it expects
520+
* to be able to run unmap_mapping_range() and subsequently not race
521+
* mapping_mapped() becoming true.
522+
*/
523+
struct page *dax_layout_busy_page(struct address_space *mapping)
524+
{
525+
pgoff_t indices[PAGEVEC_SIZE];
526+
struct page *page = NULL;
527+
struct pagevec pvec;
528+
pgoff_t index, end;
529+
unsigned i;
530+
531+
/*
532+
* In the 'limited' case get_user_pages() for dax is disabled.
533+
*/
534+
if (IS_ENABLED(CONFIG_FS_DAX_LIMITED))
535+
return NULL;
536+
537+
if (!dax_mapping(mapping) || !mapping_mapped(mapping))
538+
return NULL;
539+
540+
pagevec_init(&pvec);
541+
index = 0;
542+
end = -1;
543+
544+
/*
545+
* If we race get_user_pages_fast() here either we'll see the
546+
* elevated page count in the pagevec_lookup and wait, or
547+
* get_user_pages_fast() will see that the page it took a reference
548+
* against is no longer mapped in the page tables and bail to the
549+
* get_user_pages() slow path. The slow path is protected by
550+
* pte_lock() and pmd_lock(). New references are not taken without
551+
* holding those locks, and unmap_mapping_range() will not zero the
552+
* pte or pmd without holding the respective lock, so we are
553+
* guaranteed to either see new references or prevent new
554+
* references from being established.
555+
*/
556+
unmap_mapping_range(mapping, 0, 0, 1);
557+
558+
while (index < end && pagevec_lookup_entries(&pvec, mapping, index,
559+
min(end - index, (pgoff_t)PAGEVEC_SIZE),
560+
indices)) {
561+
for (i = 0; i < pagevec_count(&pvec); i++) {
562+
struct page *pvec_ent = pvec.pages[i];
563+
void *entry;
564+
565+
index = indices[i];
566+
if (index >= end)
567+
break;
568+
569+
if (!radix_tree_exceptional_entry(pvec_ent))
570+
continue;
571+
572+
xa_lock_irq(&mapping->i_pages);
573+
entry = get_unlocked_mapping_entry(mapping, index, NULL);
574+
if (entry)
575+
page = dax_busy_page(entry);
576+
put_unlocked_mapping_entry(mapping, index, entry);
577+
xa_unlock_irq(&mapping->i_pages);
578+
if (page)
579+
break;
580+
}
581+
pagevec_remove_exceptionals(&pvec);
582+
pagevec_release(&pvec);
583+
index++;
584+
585+
if (page)
586+
break;
587+
}
588+
return page;
589+
}
590+
EXPORT_SYMBOL_GPL(dax_layout_busy_page);
591+
495592
static int __dax_invalidate_mapping_entry(struct address_space *mapping,
496593
pgoff_t index, bool trunc)
497594
{

include/linux/dax.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ static inline void fs_put_dax(struct dax_device *dax_dev)
8383
struct dax_device *fs_dax_get_by_bdev(struct block_device *bdev);
8484
int dax_writeback_mapping_range(struct address_space *mapping,
8585
struct block_device *bdev, struct writeback_control *wbc);
86+
87+
struct page *dax_layout_busy_page(struct address_space *mapping);
8688
#else
8789
static inline int bdev_dax_supported(struct super_block *sb, int blocksize)
8890
{
@@ -103,6 +105,11 @@ static inline struct dax_device *fs_dax_get_by_bdev(struct block_device *bdev)
103105
return NULL;
104106
}
105107

108+
static inline struct page *dax_layout_busy_page(struct address_space *mapping)
109+
{
110+
return NULL;
111+
}
112+
106113
static inline int dax_writeback_mapping_range(struct address_space *mapping,
107114
struct block_device *bdev, struct writeback_control *wbc)
108115
{

0 commit comments

Comments
 (0)