On 11/16/21 16:38, Joao Martins wrote:
> On 11/15/21 17:49, Jason Gunthorpe wrote:
>> On Mon, Nov 15, 2021 at 01:11:32PM +0100, Joao Martins wrote:
>>> On 11/12/21 16:34, Jason Gunthorpe wrote:
>>>> On Fri, Nov 12, 2021 at 04:08:24PM +0100, Joao Martins wrote:
>>>>> diff --git a/drivers/dax/device.c b/drivers/dax/device.c
>>>>> index a65c67ab5ee0..0c2ac97d397d 100644
>>>>> +++ b/drivers/dax/device.c
>>>>> @@ -192,6 +192,42 @@ static vm_fault_t __dev_dax_pud_fault(struct dev_dax
>>>>> *dev_dax,
>>>>> }
>>>>> #endif /* !CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */
>>>>>
>>>>> +static void set_page_mapping(struct vm_fault *vmf, pfn_t pfn,
>>>>> + unsigned long fault_size,
>>>>> + struct address_space *f_mapping)
>>>>> +{
>>>>> + unsigned long i;
>>>>> + pgoff_t pgoff;
>>>>> +
>>>>> + pgoff = linear_page_index(vmf->vma, ALIGN(vmf->address, fault_size));
>>>>> +
>>>>> + for (i = 0; i < fault_size / PAGE_SIZE; i++) {
>>>>> + struct page *page;
>>>>> +
>>>>> + page = pfn_to_page(pfn_t_to_pfn(pfn) + i);
>>>>> + if (page->mapping)
>>>>> + continue;
>>>>> + page->mapping = f_mapping;
>>>>> + page->index = pgoff + i;
>>>>> + }
>>>>> +}
>>>>> +
>>>>> +static void set_compound_mapping(struct vm_fault *vmf, pfn_t pfn,
>>>>> + unsigned long fault_size,
>>>>> + struct address_space *f_mapping)
>>>>> +{
>>>>> + struct page *head;
>>>>> +
>>>>> + head = pfn_to_page(pfn_t_to_pfn(pfn));
>>>>> + head = compound_head(head);
>>>>> + if (head->mapping)
>>>>> + return;
>>>>> +
>>>>> + head->mapping = f_mapping;
>>>>> + head->index = linear_page_index(vmf->vma,
>>>>> + ALIGN(vmf->address, fault_size));
>>>>> +}
>>>>
>>>> Should this stuff be setup before doing vmf_insert_pfn_XX?
>>>>
>>>
>>> Interestingly filesystem-dax does this, but not device-dax.
>>
>> I think it may be a bug ?
>>
> Possibly.
>
> Dan, any thoughts (see also below) ? You probably hold all that
> history since its inception on commit 2232c6382a4 ("device-dax: Enable
> page_mapping()")
> and commit 35de299547d1 ("device-dax: Set page->index").
>
Below is what I have staged so far as a percursor patch (see below scissors
mark).
It also lets me simplify compound page case for __dax_set_mapping() in this
patch,
like below diff.
But I still wonder whether this ordering adjustment of @mapping setting is best
placed
as a percursor patch whenever pgmap/page refcount changes happen. Anyways it's
just a
thought.
diff --git a/drivers/dax/device.c b/drivers/dax/device.c
index 80824e460fbf..35706214778e 100644
--- a/drivers/dax/device.c
+++ b/drivers/dax/device.c
@@ -78,15 +78,21 @@ static void __dax_set_mapping(struct vm_fault *vmf, pfn_t
pfn,
struct address_space *f_mapping)
{
struct address_space *c_mapping = vmf->vma->vm_file->f_mapping;
+ struct dev_dax *dev_dax = vmf->vma->vm_file->private_data;
unsigned long i, nr_pages = fault_size / PAGE_SIZE;
pgoff_t pgoff;
+ /* mapping is only set on the head */
+ if (dev_dax->pgmap->vmemmap_shift)
+ nr_pages = 1;
+
pgoff = linear_page_index(vmf->vma,
ALIGN(vmf->address, fault_size));
for (i = 0; i < nr_pages; i++) {
struct page *page = pfn_to_page(pfn_t_to_pfn(pfn) + i);
+ page = compound_head(page);
if (page->mapping &&
(!f_mapping && page->mapping != c_mapping))
continue;
@@ -473,6 +479,9 @@ int dev_dax_probe(struct dev_dax *dev_dax)
}
pgmap->type = MEMORY_DEVICE_GENERIC;
+ if (dev_dax->align > PAGE_SIZE)
+ pgmap->vmemmap_shift =
+ order_base_2(dev_dax->align >> PAGE_SHIFT);
addr = devm_memremap_pages(dev, pgmap);
if (IS_ERR(addr))
return PTR_ERR(addr);
(
----------------------------------->8-------------------------------------
From: Joao Martins <[email protected]>
Subject: [PATCH] device-dax: set mapping prior to vmf_insert_pfn{,_pmd,pud}()
Normally, the @page mapping is set prior to inserting the page into a
page table entry. Make device-dax adhere to the same ordering, rather
than setting mapping after the PTE is inserted.
Care is taken to clear the mapping on a vmf_insert_pfn* failure (rc !=
VM_FAULT_NOPAGE). Thus mapping is cleared when we have a valid @pfn
which is right before we call vmf_insert_pfn*() and it is only cleared
if the one set on the page is the mapping recorded in the fault handler
data (@vmf).
Suggested-by: Jason Gunthorpe <[email protected]>
Signed-off-by: Joao Martins <[email protected]>
---
drivers/dax/device.c | 79 +++++++++++++++++++++++++++++++-------------
1 file changed, 56 insertions(+), 23 deletions(-)
diff --git a/drivers/dax/device.c b/drivers/dax/device.c
index 630de5a795b0..80824e460fbf 100644
--- a/drivers/dax/device.c
+++ b/drivers/dax/device.c
@@ -73,6 +73,43 @@ __weak phys_addr_t dax_pgoff_to_phys(struct dev_dax
*dev_dax, pgoff_t
pgoff,
return -1;
}
+static void __dax_set_mapping(struct vm_fault *vmf, pfn_t pfn,
+ unsigned long fault_size,
+ struct address_space *f_mapping)
+{
+ struct address_space *c_mapping = vmf->vma->vm_file->f_mapping;
+ unsigned long i, nr_pages = fault_size / PAGE_SIZE;
+ pgoff_t pgoff;
+
+ pgoff = linear_page_index(vmf->vma,
+ ALIGN(vmf->address, fault_size));
+
+ for (i = 0; i < nr_pages; i++) {
+ struct page *page = pfn_to_page(pfn_t_to_pfn(pfn) + i);
+
+ if (page->mapping &&
+ (!f_mapping && page->mapping != c_mapping))
+ continue;
+
+ page->mapping = f_mapping;
+ page->index = pgoff + i;
+ }
+}
+
+static void dax_set_mapping(struct vm_fault *vmf, pfn_t pfn,
+ unsigned long fault_size)
+{
+ struct address_space *c_mapping = vmf->vma->vm_file->f_mapping;
+
+ __dax_set_mapping(vmf, pfn, fault_size, c_mapping);
+}
+
+static void dax_clear_mapping(struct vm_fault *vmf, pfn_t pfn,
+ unsigned long fault_size)
+{
+ __dax_set_mapping(vmf, pfn, fault_size, NULL);
+}
+
static vm_fault_t __dev_dax_pte_fault(struct dev_dax *dev_dax,
struct vm_fault *vmf, pfn_t *pfn)
{
@@ -100,6 +137,8 @@ static vm_fault_t __dev_dax_pte_fault(struct dev_dax
*dev_dax,
*pfn = phys_to_pfn_t(phys, PFN_DEV|PFN_MAP);
+ dax_set_mapping(vmf, *pfn, fault_size);
+
return vmf_insert_mixed(vmf->vma, vmf->address, *pfn);
}
@@ -140,6 +179,8 @@ static vm_fault_t __dev_dax_pmd_fault(struct dev_dax
*dev_dax,
*pfn = phys_to_pfn_t(phys, PFN_DEV|PFN_MAP);
+ dax_set_mapping(vmf, *pfn, fault_size);
+
return vmf_insert_pfn_pmd(vmf, *pfn, vmf->flags & FAULT_FLAG_WRITE);
}
@@ -182,6 +223,8 @@ static vm_fault_t __dev_dax_pud_fault(struct dev_dax
*dev_dax,
*pfn = phys_to_pfn_t(phys, PFN_DEV|PFN_MAP);
+ dax_set_mapping(vmf, *pfn, fault_size);
+
return vmf_insert_pfn_pud(vmf, *pfn, vmf->flags & FAULT_FLAG_WRITE);
}
#else
@@ -199,7 +242,7 @@ static vm_fault_t dev_dax_huge_fault(struct vm_fault *vmf,
unsigned long fault_size;
vm_fault_t rc = VM_FAULT_SIGBUS;
int id;
- pfn_t pfn;
+ pfn_t pfn = { .val = 0 };
struct dev_dax *dev_dax = filp->private_data;
dev_dbg(&dev_dax->dev, "%s: %s (%#lx - %#lx) size = %d\n",
current->comm,
@@ -224,28 +267,18 @@ static vm_fault_t dev_dax_huge_fault(struct vm_fault *vmf,
rc = VM_FAULT_SIGBUS;
}
- if (rc == VM_FAULT_NOPAGE) {
- unsigned long i;
- pgoff_t pgoff;
-
- /*
- * In the device-dax case the only possibility for a
- * VM_FAULT_NOPAGE result is when device-dax capacity is
- * mapped. No need to consider the zero page, or racing
- * conflicting mappings.
- */
- pgoff = linear_page_index(vmf->vma,
- ALIGN(vmf->address, fault_size));
- for (i = 0; i < fault_size / PAGE_SIZE; i++) {
- struct page *page;
-
- page = pfn_to_page(pfn_t_to_pfn(pfn) + i);
- if (page->mapping)
- continue;
- page->mapping = filp->f_mapping;
- page->index = pgoff + i;
- }
- }
+ /*
+ * In the device-dax case the only possibility for a
+ * VM_FAULT_NOPAGE result is when device-dax capacity is
+ * mapped. No need to consider the zero page, or racing
+ * conflicting mappings.
+ * We could get VM_FAULT_FALLBACK without even attempting
+ * to insert the page table entry. So make sure we test
+ * for the error code with a devmap @pfn value which is
+ * set right before vmf_insert_pfn*().
+ */
+ if (rc != VM_FAULT_NOPAGE && pfn_t_devmap(pfn))
+ dax_clear_mapping(vmf, pfn, fault_size);
dax_read_unlock(id);
return rc;
--
2.17.2