mirror of
https://github.com/Fishwaldo/linux-bl808.git
synced 2025-06-05 22:25:16 +00:00
dax: store pfns in the radix
In preparation for examining the busy state of dax pages in the truncate path, switch from sectors to pfns in the radix. Cc: Jeff Moyer <jmoyer@redhat.com> Cc: Christoph Hellwig <hch@lst.de> Cc: Matthew Wilcox <mawilcox@microsoft.com> Cc: Ross Zwisler <ross.zwisler@linux.intel.com> Reviewed-by: Jan Kara <jack@suse.cz> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
parent
6b2bb7265f
commit
3fe0791c29
2 changed files with 43 additions and 55 deletions
|
@ -124,10 +124,19 @@ int __bdev_dax_supported(struct super_block *sb, int blocksize)
|
||||||
return len < 0 ? len : -EIO;
|
return len < 0 ? len : -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((IS_ENABLED(CONFIG_FS_DAX_LIMITED) && pfn_t_special(pfn))
|
if (IS_ENABLED(CONFIG_FS_DAX_LIMITED) && pfn_t_special(pfn)) {
|
||||||
|| pfn_t_devmap(pfn))
|
/*
|
||||||
|
* An arch that has enabled the pmem api should also
|
||||||
|
* have its drivers support pfn_t_devmap()
|
||||||
|
*
|
||||||
|
* This is a developer warning and should not trigger in
|
||||||
|
* production. dax_flush() will crash since it depends
|
||||||
|
* on being able to do (page_address(pfn_to_page())).
|
||||||
|
*/
|
||||||
|
WARN_ON(IS_ENABLED(CONFIG_ARCH_HAS_PMEM_API));
|
||||||
|
} else if (pfn_t_devmap(pfn)) {
|
||||||
/* pass */;
|
/* pass */;
|
||||||
else {
|
} else {
|
||||||
pr_debug("VFS (%s): error: dax support not enabled\n",
|
pr_debug("VFS (%s): error: dax support not enabled\n",
|
||||||
sb->s_id);
|
sb->s_id);
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
83
fs/dax.c
83
fs/dax.c
|
@ -73,16 +73,15 @@ fs_initcall(init_dax_wait_table);
|
||||||
#define RADIX_DAX_ZERO_PAGE (1 << (RADIX_TREE_EXCEPTIONAL_SHIFT + 2))
|
#define RADIX_DAX_ZERO_PAGE (1 << (RADIX_TREE_EXCEPTIONAL_SHIFT + 2))
|
||||||
#define RADIX_DAX_EMPTY (1 << (RADIX_TREE_EXCEPTIONAL_SHIFT + 3))
|
#define RADIX_DAX_EMPTY (1 << (RADIX_TREE_EXCEPTIONAL_SHIFT + 3))
|
||||||
|
|
||||||
static unsigned long dax_radix_sector(void *entry)
|
static unsigned long dax_radix_pfn(void *entry)
|
||||||
{
|
{
|
||||||
return (unsigned long)entry >> RADIX_DAX_SHIFT;
|
return (unsigned long)entry >> RADIX_DAX_SHIFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *dax_radix_locked_entry(sector_t sector, unsigned long flags)
|
static void *dax_radix_locked_entry(unsigned long pfn, unsigned long flags)
|
||||||
{
|
{
|
||||||
return (void *)(RADIX_TREE_EXCEPTIONAL_ENTRY | flags |
|
return (void *)(RADIX_TREE_EXCEPTIONAL_ENTRY | flags |
|
||||||
((unsigned long)sector << RADIX_DAX_SHIFT) |
|
(pfn << RADIX_DAX_SHIFT) | RADIX_DAX_ENTRY_LOCK);
|
||||||
RADIX_DAX_ENTRY_LOCK);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int dax_radix_order(void *entry)
|
static unsigned int dax_radix_order(void *entry)
|
||||||
|
@ -526,12 +525,13 @@ static int copy_user_dax(struct block_device *bdev, struct dax_device *dax_dev,
|
||||||
*/
|
*/
|
||||||
static void *dax_insert_mapping_entry(struct address_space *mapping,
|
static void *dax_insert_mapping_entry(struct address_space *mapping,
|
||||||
struct vm_fault *vmf,
|
struct vm_fault *vmf,
|
||||||
void *entry, sector_t sector,
|
void *entry, pfn_t pfn_t,
|
||||||
unsigned long flags, bool dirty)
|
unsigned long flags, bool dirty)
|
||||||
{
|
{
|
||||||
struct radix_tree_root *page_tree = &mapping->page_tree;
|
struct radix_tree_root *page_tree = &mapping->page_tree;
|
||||||
void *new_entry;
|
unsigned long pfn = pfn_t_to_pfn(pfn_t);
|
||||||
pgoff_t index = vmf->pgoff;
|
pgoff_t index = vmf->pgoff;
|
||||||
|
void *new_entry;
|
||||||
|
|
||||||
if (dirty)
|
if (dirty)
|
||||||
__mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
|
__mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
|
||||||
|
@ -546,7 +546,7 @@ static void *dax_insert_mapping_entry(struct address_space *mapping,
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irq(&mapping->tree_lock);
|
spin_lock_irq(&mapping->tree_lock);
|
||||||
new_entry = dax_radix_locked_entry(sector, flags);
|
new_entry = dax_radix_locked_entry(pfn, flags);
|
||||||
|
|
||||||
if (dax_is_zero_entry(entry) || dax_is_empty_entry(entry)) {
|
if (dax_is_zero_entry(entry) || dax_is_empty_entry(entry)) {
|
||||||
/*
|
/*
|
||||||
|
@ -657,17 +657,14 @@ unlock_pte:
|
||||||
i_mmap_unlock_read(mapping);
|
i_mmap_unlock_read(mapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dax_writeback_one(struct block_device *bdev,
|
static int dax_writeback_one(struct dax_device *dax_dev,
|
||||||
struct dax_device *dax_dev, struct address_space *mapping,
|
struct address_space *mapping, pgoff_t index, void *entry)
|
||||||
pgoff_t index, void *entry)
|
|
||||||
{
|
{
|
||||||
struct radix_tree_root *page_tree = &mapping->page_tree;
|
struct radix_tree_root *page_tree = &mapping->page_tree;
|
||||||
void *entry2, **slot, *kaddr;
|
void *entry2, **slot;
|
||||||
long ret = 0, id;
|
unsigned long pfn;
|
||||||
sector_t sector;
|
long ret = 0;
|
||||||
pgoff_t pgoff;
|
|
||||||
size_t size;
|
size_t size;
|
||||||
pfn_t pfn;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A page got tagged dirty in DAX mapping? Something is seriously
|
* A page got tagged dirty in DAX mapping? Something is seriously
|
||||||
|
@ -683,10 +680,10 @@ static int dax_writeback_one(struct block_device *bdev,
|
||||||
goto put_unlocked;
|
goto put_unlocked;
|
||||||
/*
|
/*
|
||||||
* Entry got reallocated elsewhere? No need to writeback. We have to
|
* Entry got reallocated elsewhere? No need to writeback. We have to
|
||||||
* compare sectors as we must not bail out due to difference in lockbit
|
* compare pfns as we must not bail out due to difference in lockbit
|
||||||
* or entry type.
|
* or entry type.
|
||||||
*/
|
*/
|
||||||
if (dax_radix_sector(entry2) != dax_radix_sector(entry))
|
if (dax_radix_pfn(entry2) != dax_radix_pfn(entry))
|
||||||
goto put_unlocked;
|
goto put_unlocked;
|
||||||
if (WARN_ON_ONCE(dax_is_empty_entry(entry) ||
|
if (WARN_ON_ONCE(dax_is_empty_entry(entry) ||
|
||||||
dax_is_zero_entry(entry))) {
|
dax_is_zero_entry(entry))) {
|
||||||
|
@ -712,33 +709,15 @@ static int dax_writeback_one(struct block_device *bdev,
|
||||||
/*
|
/*
|
||||||
* Even if dax_writeback_mapping_range() was given a wbc->range_start
|
* Even if dax_writeback_mapping_range() was given a wbc->range_start
|
||||||
* in the middle of a PMD, the 'index' we are given will be aligned to
|
* in the middle of a PMD, the 'index' we are given will be aligned to
|
||||||
* the start index of the PMD, as will the sector we pull from
|
* the start index of the PMD, as will the pfn we pull from 'entry'.
|
||||||
* 'entry'. This allows us to flush for PMD_SIZE and not have to
|
* This allows us to flush for PMD_SIZE and not have to worry about
|
||||||
* worry about partial PMD writebacks.
|
* partial PMD writebacks.
|
||||||
*/
|
*/
|
||||||
sector = dax_radix_sector(entry);
|
pfn = dax_radix_pfn(entry);
|
||||||
size = PAGE_SIZE << dax_radix_order(entry);
|
size = PAGE_SIZE << dax_radix_order(entry);
|
||||||
|
|
||||||
id = dax_read_lock();
|
dax_mapping_entry_mkclean(mapping, index, pfn);
|
||||||
ret = bdev_dax_pgoff(bdev, sector, size, &pgoff);
|
dax_flush(dax_dev, page_address(pfn_to_page(pfn)), size);
|
||||||
if (ret)
|
|
||||||
goto dax_unlock;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* dax_direct_access() may sleep, so cannot hold tree_lock over
|
|
||||||
* its invocation.
|
|
||||||
*/
|
|
||||||
ret = dax_direct_access(dax_dev, pgoff, size / PAGE_SIZE, &kaddr, &pfn);
|
|
||||||
if (ret < 0)
|
|
||||||
goto dax_unlock;
|
|
||||||
|
|
||||||
if (WARN_ON_ONCE(ret < size / PAGE_SIZE)) {
|
|
||||||
ret = -EIO;
|
|
||||||
goto dax_unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
dax_mapping_entry_mkclean(mapping, index, pfn_t_to_pfn(pfn));
|
|
||||||
dax_flush(dax_dev, kaddr, size);
|
|
||||||
/*
|
/*
|
||||||
* After we have flushed the cache, we can clear the dirty tag. There
|
* After we have flushed the cache, we can clear the dirty tag. There
|
||||||
* cannot be new dirty data in the pfn after the flush has completed as
|
* cannot be new dirty data in the pfn after the flush has completed as
|
||||||
|
@ -749,8 +728,6 @@ static int dax_writeback_one(struct block_device *bdev,
|
||||||
radix_tree_tag_clear(page_tree, index, PAGECACHE_TAG_DIRTY);
|
radix_tree_tag_clear(page_tree, index, PAGECACHE_TAG_DIRTY);
|
||||||
spin_unlock_irq(&mapping->tree_lock);
|
spin_unlock_irq(&mapping->tree_lock);
|
||||||
trace_dax_writeback_one(mapping->host, index, size >> PAGE_SHIFT);
|
trace_dax_writeback_one(mapping->host, index, size >> PAGE_SHIFT);
|
||||||
dax_unlock:
|
|
||||||
dax_read_unlock(id);
|
|
||||||
put_locked_mapping_entry(mapping, index);
|
put_locked_mapping_entry(mapping, index);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -808,8 +785,8 @@ int dax_writeback_mapping_range(struct address_space *mapping,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = dax_writeback_one(bdev, dax_dev, mapping,
|
ret = dax_writeback_one(dax_dev, mapping, indices[i],
|
||||||
indices[i], pvec.pages[i]);
|
pvec.pages[i]);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
mapping_set_error(mapping, ret);
|
mapping_set_error(mapping, ret);
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -877,6 +854,7 @@ static int dax_load_hole(struct address_space *mapping, void *entry,
|
||||||
int ret = VM_FAULT_NOPAGE;
|
int ret = VM_FAULT_NOPAGE;
|
||||||
struct page *zero_page;
|
struct page *zero_page;
|
||||||
void *entry2;
|
void *entry2;
|
||||||
|
pfn_t pfn;
|
||||||
|
|
||||||
zero_page = ZERO_PAGE(0);
|
zero_page = ZERO_PAGE(0);
|
||||||
if (unlikely(!zero_page)) {
|
if (unlikely(!zero_page)) {
|
||||||
|
@ -884,14 +862,15 @@ static int dax_load_hole(struct address_space *mapping, void *entry,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry2 = dax_insert_mapping_entry(mapping, vmf, entry, 0,
|
pfn = page_to_pfn_t(zero_page);
|
||||||
|
entry2 = dax_insert_mapping_entry(mapping, vmf, entry, pfn,
|
||||||
RADIX_DAX_ZERO_PAGE, false);
|
RADIX_DAX_ZERO_PAGE, false);
|
||||||
if (IS_ERR(entry2)) {
|
if (IS_ERR(entry2)) {
|
||||||
ret = VM_FAULT_SIGBUS;
|
ret = VM_FAULT_SIGBUS;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
vm_insert_mixed(vmf->vma, vaddr, page_to_pfn_t(zero_page));
|
vm_insert_mixed(vmf->vma, vaddr, pfn);
|
||||||
out:
|
out:
|
||||||
trace_dax_load_hole(inode, vmf, ret);
|
trace_dax_load_hole(inode, vmf, ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1200,8 +1179,7 @@ static int dax_iomap_pte_fault(struct vm_fault *vmf, pfn_t *pfnp,
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
goto error_finish_iomap;
|
goto error_finish_iomap;
|
||||||
|
|
||||||
entry = dax_insert_mapping_entry(mapping, vmf, entry,
|
entry = dax_insert_mapping_entry(mapping, vmf, entry, pfn,
|
||||||
dax_iomap_sector(&iomap, pos),
|
|
||||||
0, write && !sync);
|
0, write && !sync);
|
||||||
if (IS_ERR(entry)) {
|
if (IS_ERR(entry)) {
|
||||||
error = PTR_ERR(entry);
|
error = PTR_ERR(entry);
|
||||||
|
@ -1280,13 +1258,15 @@ static int dax_pmd_load_hole(struct vm_fault *vmf, struct iomap *iomap,
|
||||||
void *ret = NULL;
|
void *ret = NULL;
|
||||||
spinlock_t *ptl;
|
spinlock_t *ptl;
|
||||||
pmd_t pmd_entry;
|
pmd_t pmd_entry;
|
||||||
|
pfn_t pfn;
|
||||||
|
|
||||||
zero_page = mm_get_huge_zero_page(vmf->vma->vm_mm);
|
zero_page = mm_get_huge_zero_page(vmf->vma->vm_mm);
|
||||||
|
|
||||||
if (unlikely(!zero_page))
|
if (unlikely(!zero_page))
|
||||||
goto fallback;
|
goto fallback;
|
||||||
|
|
||||||
ret = dax_insert_mapping_entry(mapping, vmf, entry, 0,
|
pfn = page_to_pfn_t(zero_page);
|
||||||
|
ret = dax_insert_mapping_entry(mapping, vmf, entry, pfn,
|
||||||
RADIX_DAX_PMD | RADIX_DAX_ZERO_PAGE, false);
|
RADIX_DAX_PMD | RADIX_DAX_ZERO_PAGE, false);
|
||||||
if (IS_ERR(ret))
|
if (IS_ERR(ret))
|
||||||
goto fallback;
|
goto fallback;
|
||||||
|
@ -1409,8 +1389,7 @@ static int dax_iomap_pmd_fault(struct vm_fault *vmf, pfn_t *pfnp,
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
goto finish_iomap;
|
goto finish_iomap;
|
||||||
|
|
||||||
entry = dax_insert_mapping_entry(mapping, vmf, entry,
|
entry = dax_insert_mapping_entry(mapping, vmf, entry, pfn,
|
||||||
dax_iomap_sector(&iomap, pos),
|
|
||||||
RADIX_DAX_PMD, write && !sync);
|
RADIX_DAX_PMD, write && !sync);
|
||||||
if (IS_ERR(entry))
|
if (IS_ERR(entry))
|
||||||
goto finish_iomap;
|
goto finish_iomap;
|
||||||
|
|
Loading…
Add table
Reference in a new issue