On 5/22/26 12:19 PM, John Groves wrote:
> From: John Groves <[email protected]>
> 
> Two fixes for virtual address handling in fsdev:
> 
> 1. Use __va(phys) instead of virt_addr + linear_offset for the kaddr
>    return in __fsdev_dax_direct_access(). The previous code added a
>    device-linear byte offset to virt_addr (which is __va of ranges[0]),
>    but for multi-range devices with physical gaps between ranges, this
>    linear arithmetic crosses the gap and produces a wrong kernel virtual
>    address. Using __va(phys) where phys comes from dax_pgoff_to_phys()
>    is correct for any range layout because the direct map translates
>    each physical address independently.
> 
> 2. Convert the WARN_ON to a fatal error when pgmap_phys > phys. This
>    condition means the remapped region starts after the device's data
>    region, which is an impossible state. Previously the probe continued
>    with data_offset=0, leaving virt_addr silently misaligned. Now probe
>    returns -EINVAL with a diagnostic message.

Split to 2 different patches I'd say.

DJ

> 
> Fixes: 759455848df0b ("dax: Save the kva from memremap")
> Signed-off-by: John Groves <[email protected]>
> ---
>  drivers/dax/fsdev.c | 16 +++++++++-------
>  1 file changed, 9 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/dax/fsdev.c b/drivers/dax/fsdev.c
> index 42aac7e952516..aac0130ab2833 100644
> --- a/drivers/dax/fsdev.c
> +++ b/drivers/dax/fsdev.c
> @@ -51,9 +51,7 @@ static long __fsdev_dax_direct_access(struct dax_device 
> *dax_dev, pgoff_t pgoff,
>       struct dev_dax *dev_dax = dax_get_private(dax_dev);
>       size_t size = nr_pages << PAGE_SHIFT;
>       size_t offset = pgoff << PAGE_SHIFT;
> -     void *virt_addr = dev_dax->virt_addr + offset;
>       phys_addr_t phys;
> -     unsigned long local_pfn;
>  
>       phys = dax_pgoff_to_phys(dev_dax, pgoff, size);
>       if (phys == -1) {
> @@ -63,11 +61,10 @@ static long __fsdev_dax_direct_access(struct dax_device 
> *dax_dev, pgoff_t pgoff,
>       }
>  
>       if (kaddr)
> -             *kaddr = virt_addr;
> +             *kaddr = __va(phys);
>  
> -     local_pfn = PHYS_PFN(phys);
>       if (pfn)
> -             *pfn = local_pfn;
> +             *pfn = PHYS_PFN(phys);
>  
>       /*
>        * Use cached_size which was computed at probe time. The size cannot
> @@ -313,8 +310,13 @@ static int fsdev_dax_probe(struct dev_dax *dev_dax)
>               u64 phys = dev_dax->ranges[0].range.start;
>               u64 pgmap_phys = dev_dax->pgmap[0].range.start;
>  
> -             if (!WARN_ON(pgmap_phys > phys))
> -                     data_offset = phys - pgmap_phys;
> +             if (pgmap_phys > phys) {
> +                     dev_err(dev, "pgmap start %#llx exceeds data start 
> %#llx\n",
> +                             pgmap_phys, phys);
> +                     rc = -EINVAL;
> +                     goto err_pgmap;
> +             }
> +             data_offset = phys - pgmap_phys;
>  
>               pr_debug("%s: offset detected phys=%llx pgmap_phys=%llx 
> offset=%llx\n",
>                      __func__, phys, pgmap_phys, data_offset);


Reply via email to