* [PATCH 0/2] dax: Fix Device DAX range allocation validation
@ 2026-09-15 9:56 Muchun Song
2026-09-15 9:56 ` [PATCH 1/2] dax/bus: fix Device DAX range alignment validation Muchun Song
` (2 more replies)
0 siblings, 3 replies; 11+ messages in thread
From: Muchun Song @ 2026-09-15 9:56 UTC (permalink / raw)
To: Dan Williams, Vishal Verma, Dave Jiang, Alison Schofield
Cc: Andrew Morton, Joao Martins, nvdimm, linux-cxl, linux-kernel,
Muchun Song, muchun.song
While working on the HugeTLB Vmemmap Optimization (HVO) generalization,
Sashiko reported that memmap_init_zone_device() could be asked to
initialize struct pages with a large-page order for a physical range
that was not naturally aligned to that order.
Following the Device DAX call path confirmed that the condition was
reachable. Device DAX range validation checks the range size, but not
its start address. An unaligned range can therefore reach
memmap_init_zone_device() after the device binds, and a subsequent write
to a userspace mapping may trigger a kernel panic. With the help of an
LLM, I was able to reproduce the failure.
The automatic resize path has a related problem. It can split an aligned
size request across arbitrary free gaps, consume an unaligned fragment,
and leave the resize partially applied when a later allocation fails.
This series validates both the start and size of every Device DAX range
and makes automatic resize account only for usable aligned space. It
also fixes the mapping sysfs attribute to propagate validation failures
instead of reporting success without allocating the requested range.
Muchun Song (2):
dax/bus: fix Device DAX range alignment validation
dax/bus: fix mapping attribute error reporting
drivers/dax/bus.c | 144 +++++++++++++++++++++++++++++++++++-----------
1 file changed, 109 insertions(+), 35 deletions(-)
base-commit: 1a1de54f7369cd2b5bac0f265910e60ad3a6b4c3
--
2.54.0
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH 1/2] dax/bus: fix Device DAX range alignment validation 2026-09-15 9:56 [PATCH 0/2] dax: Fix Device DAX range allocation validation Muchun Song @ 2026-09-15 9:56 ` Muchun Song 2026-09-21 21:01 ` Dave Jiang 2026-09-15 9:56 ` [PATCH 2/2] dax/bus: fix mapping attribute error reporting Muchun Song 2026-09-18 17:02 ` [PATCH 0/2] dax: Fix Device DAX range allocation validation Dave Jiang 2 siblings, 1 reply; 11+ messages in thread From: Muchun Song @ 2026-09-15 9:56 UTC (permalink / raw) To: Dan Williams, Vishal Verma, Dave Jiang, Alison Schofield Cc: Andrew Morton, Joao Martins, nvdimm, linux-cxl, linux-kernel, Muchun Song, muchun.song dev_dax->align describes the page size used by a Device DAX mapping. Both the start and size of every range must therefore be aligned to it; otherwise the starting PFN cannot represent a naturally aligned page of that size. Only range sizes are currently validated. A dynamic device can therefore select a large-page alignment and allocate a range whose start is not naturally aligned to that page size. The device binds successfully, but a subsequent write to a userspace mapping may trigger a kernel panic. The automatic resize path can also split a size-aligned request across arbitrary free gaps. When devices with different alignments fragment a region, this can extend a range by less than its alignment. A later allocation then fails, leaving the failed resize partially applied. Validate both the start and size of allocated and adjusted ranges. Make the resize path account only for usable aligned space before changing any ranges, and skip gaps that cannot satisfy the device alignment. Initialize the device alignment before allocating its initial range so that all allocations use the same validation. A mapping with an unaligned start is now rejected with -EINVAL, while a naturally aligned mapping still binds successfully. Fixes: 6d82120f4156 ("device-dax: add an 'align' attribute") Assisted-by: LLM Signed-off-by: Muchun Song <songmuchun@bytedance.com> --- drivers/dax/bus.c | 143 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 109 insertions(+), 34 deletions(-) diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c index b809e1a264af..54e4bbc98218 100644 --- a/drivers/dax/bus.c +++ b/drivers/dax/bus.c @@ -848,6 +848,44 @@ static int devm_register_dax_mapping(struct dev_dax *dev_dax, int range_id) return 0; } +static inline unsigned long dev_dax_min_align(struct dev_dax *dev_dax) +{ + return max_t(unsigned long, dev_dax->align, memremap_compat_align()); +} + +static inline bool size_is_aligned(struct dev_dax *dev_dax, resource_size_t size) +{ + /* + * The minimum mapping granularity for a device instance is a + * single subsection, unless the arch says otherwise. + */ + return IS_ALIGNED(size, dev_dax_min_align(dev_dax)); +} + +static inline bool range_is_aligned(struct dev_dax *dev_dax, u64 start, + resource_size_t size) +{ + return IS_ALIGNED(start | size, dev_dax_min_align(dev_dax)); +} + +static resource_size_t +aligned_gap_size(struct dev_dax *dev_dax, resource_size_t *start, + resource_size_t end) +{ + resource_size_t aligned_start = ALIGN(*start, dev_dax_min_align(dev_dax)); + resource_size_t size; + + if (aligned_start < *start || aligned_start > end) + return 0; + + size = ALIGN_DOWN(end - aligned_start + 1, dev_dax_min_align(dev_dax)); + if (!size) + return 0; + + *start = aligned_start; + return size; +} + static int alloc_dev_dax_range(struct dev_dax *dev_dax, u64 start, resource_size_t size) { @@ -870,6 +908,9 @@ static int alloc_dev_dax_range(struct dev_dax *dev_dax, u64 start, return 0; } + if (!range_is_aligned(dev_dax, start, size)) + return -EINVAL; + alloc = __request_region(res, start, size, dev_name(dev), 0); if (!alloc) return -ENOMEM; @@ -923,6 +964,9 @@ static int adjust_dev_dax_range(struct dev_dax *dev_dax, struct resource *res, r if (dev_WARN_ONCE(dev, !size, "deletion is handled by dev_dax_shrink\n")) return -EINVAL; + if (!range_is_aligned(dev_dax, range->start, size)) + return -EINVAL; + rc = adjust_resource(res, range->start, size); if (rc) return rc; @@ -955,15 +999,6 @@ static ssize_t size_show(struct device *dev, return sysfs_emit(buf, "%llu\n", size); } -static bool alloc_is_aligned(struct dev_dax *dev_dax, resource_size_t size) -{ - /* - * The minimum mapping granularity for a device instance is a - * single subsection, unless the arch says otherwise. - */ - return IS_ALIGNED(size, max_t(unsigned long, dev_dax->align, memremap_compat_align())); -} - static int dev_dax_shrink(struct dev_dax *dev_dax, resource_size_t size) { resource_size_t to_shrink = dev_dax_size(dev_dax) - size; @@ -1030,30 +1065,55 @@ static bool adjust_ok(struct dev_dax *dev_dax, struct resource *res) return true; } +static resource_size_t +dax_region_aligned_avail_size(struct dax_region *dax_region, + struct dev_dax *dev_dax) +{ + struct resource *region_res = &dax_region->res; + resource_size_t start = region_res->start; + resource_size_t avail = 0; + struct resource *res; + + lockdep_assert_held_write(&dax_region_rwsem); + + for_each_dax_region_resource(dax_region, res) { + if (res->start > start) { + resource_size_t gap_start = start; + + avail += aligned_gap_size(dev_dax, &gap_start, + res->start - 1); + } + start = res->end + 1; + } + if (start <= region_res->end) + avail += aligned_gap_size(dev_dax, &start, region_res->end); + + return avail; +} + static ssize_t dev_dax_resize(struct dax_region *dax_region, struct dev_dax *dev_dax, resource_size_t size) { - resource_size_t avail = dax_region_avail_size(dax_region), to_alloc; resource_size_t dev_size = dev_dax_size(dev_dax); struct resource *region_res = &dax_region->res; struct device *dev = &dev_dax->dev; struct resource *res, *first; - resource_size_t alloc = 0; + resource_size_t alloc, to_alloc; int rc; if (dev->driver) return -EBUSY; if (size == dev_size) return 0; - if (size > dev_size && size - dev_size > avail) - return -ENOSPC; if (size < dev_size) return dev_dax_shrink(dev_dax, size); to_alloc = size - dev_size; - if (dev_WARN_ONCE(dev, !alloc_is_aligned(dev_dax, to_alloc), - "resize of %pa misaligned\n", &to_alloc)) + if (dev_WARN_ONCE(dev, !size_is_aligned(dev_dax, to_alloc), + "resize of %pa misaligned\n", &to_alloc)) return -ENXIO; + if (to_alloc > dax_region_aligned_avail_size(dax_region, dev_dax)) + return -ENOSPC; /* * Expand the device into the unused portion of the region. This @@ -1062,37 +1122,52 @@ static ssize_t dev_dax_resize(struct dax_region *dax_region, */ retry: first = region_res->child; - if (!first) - return alloc_dev_dax_range(dev_dax, dax_region->res.start, to_alloc); + if (!first) { + resource_size_t start = region_res->start; + + alloc = aligned_gap_size(dev_dax, &start, region_res->end); + return alloc_dev_dax_range(dev_dax, start, + min(alloc, to_alloc)); + } rc = -ENOSPC; for (res = first; res; res = res->sibling) { struct resource *next = res->sibling; + resource_size_t start, end; /* space at the beginning of the region */ if (res == first && res->start > dax_region->res.start) { - alloc = min(res->start - dax_region->res.start, to_alloc); - rc = alloc_dev_dax_range(dev_dax, dax_region->res.start, alloc); - break; + start = dax_region->res.start; + end = res->start - 1; + alloc = min(aligned_gap_size(dev_dax, &start, end), to_alloc); + if (alloc) { + rc = alloc_dev_dax_range(dev_dax, start, alloc); + break; + } } - alloc = 0; /* space between allocations */ - if (next && next->start > res->end + 1) - alloc = min(next->start - (res->end + 1), to_alloc); - - /* space at the end of the region */ - if (!alloc && !next && res->end < region_res->end) - alloc = min(region_res->end - res->end, to_alloc); + if (next) { + if (next->start <= res->end + 1) + continue; + end = next->start - 1; + } else { + /* space at the end of the region */ + if (res->end >= region_res->end) + continue; + end = region_res->end; + } + start = res->end + 1; + alloc = min(aligned_gap_size(dev_dax, &start, end), to_alloc); if (!alloc) continue; - if (adjust_ok(dev_dax, res)) { + if (start == res->end + 1 && adjust_ok(dev_dax, res)) { rc = adjust_dev_dax_range(dev_dax, res, resource_size(res) + alloc); break; } - rc = alloc_dev_dax_range(dev_dax, res->end + 1, alloc); + rc = alloc_dev_dax_range(dev_dax, start, alloc); break; } if (rc) @@ -1115,7 +1190,7 @@ static ssize_t size_store(struct device *dev, struct device_attribute *attr, if (rc) return rc; - if (!alloc_is_aligned(dev_dax, val)) { + if (!size_is_aligned(dev_dax, val)) { dev_dbg(dev, "%s: size: %lld misaligned\n", __func__, val); return -EINVAL; } @@ -1201,7 +1276,7 @@ static ssize_t mapping_store(struct device *dev, struct device_attribute *attr, } to_alloc = range_len(&r); - if (alloc_is_aligned(dev_dax, to_alloc)) + if (size_is_aligned(dev_dax, to_alloc)) rc = alloc_dev_dax_range(dev_dax, r.start, to_alloc); up_write(&dax_dev_rwsem); up_write(&dax_region_rwsem); @@ -1224,9 +1299,9 @@ static ssize_t dev_dax_validate_align(struct dev_dax *dev_dax) int i; for (i = 0; i < dev_dax->nr_range; i++) { - size_t len = range_len(&dev_dax->ranges[i].range); + struct range *range = &dev_dax->ranges[i].range; - if (!alloc_is_aligned(dev_dax, len)) { + if (!range_is_aligned(dev_dax, range->start, range_len(range))) { dev_dbg(dev, "%s: align %u invalid for range %d\n", __func__, dev_dax->align, i); return -EINVAL; @@ -1464,6 +1539,7 @@ static struct dev_dax *__devm_create_dev_dax(struct dev_dax_data *data) return ERR_PTR(-ENOMEM); dev_dax->region = dax_region; + dev_dax->align = dax_region->align; if (is_static(dax_region)) { if (dev_WARN_ONCE(parent, data->id < 0, "dynamic id specified to static region\n")) { @@ -1522,7 +1598,6 @@ static struct dev_dax *__devm_create_dev_dax(struct dev_dax_data *data) dev_dax->dax_dev = dax_dev; dev_dax->target_node = dax_region->target_node; - dev_dax->align = dax_region->align; ida_init(&dev_dax->ida); dev_dax->memmap_on_memory = data->memmap_on_memory; -- 2.54.0 ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/2] dax/bus: fix Device DAX range alignment validation 2026-09-15 9:56 ` [PATCH 1/2] dax/bus: fix Device DAX range alignment validation Muchun Song @ 2026-09-21 21:01 ` Dave Jiang 2026-09-22 2:21 ` Muchun Song 0 siblings, 1 reply; 11+ messages in thread From: Dave Jiang @ 2026-09-21 21:01 UTC (permalink / raw) To: Muchun Song, Dan Williams, Vishal Verma, Alison Schofield Cc: Andrew Morton, Joao Martins, nvdimm, linux-cxl, linux-kernel, muchun.song On 9/15/26 2:56 AM, Muchun Song wrote: > dev_dax->align describes the page size used by a Device DAX mapping. > Both the start and size of every range must therefore be aligned to it; > otherwise the starting PFN cannot represent a naturally aligned page of > that size. > > Only range sizes are currently validated. A dynamic device can therefore > select a large-page alignment and allocate a range whose start is not > naturally aligned to that page size. The device binds successfully, but a > subsequent write to a userspace mapping may trigger a kernel panic. > > The automatic resize path can also split a size-aligned request across > arbitrary free gaps. When devices with different alignments fragment a > region, this can extend a range by less than its alignment. A later > allocation then fails, leaving the failed resize partially applied. > > Validate both the start and size of allocated and adjusted ranges. Make > the resize path account only for usable aligned space before changing any > ranges, and skip gaps that cannot satisfy the device alignment. Initialize > the device alignment before allocating its initial range so that all > allocations use the same validation. > > A mapping with an unaligned start is now rejected with -EINVAL, while a > naturally aligned mapping still binds successfully. > > Fixes: 6d82120f4156 ("device-dax: add an 'align' attribute") > Assisted-by: LLM > Signed-off-by: Muchun Song <songmuchun@bytedance.com> > --- > drivers/dax/bus.c | 143 +++++++++++++++++++++++++++++++++++----------- > 1 file changed, 109 insertions(+), 34 deletions(-) > > diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c > index b809e1a264af..54e4bbc98218 100644 > --- a/drivers/dax/bus.c > +++ b/drivers/dax/bus.c > @@ -848,6 +848,44 @@ static int devm_register_dax_mapping(struct dev_dax *dev_dax, int range_id) > return 0; > } > > +static inline unsigned long dev_dax_min_align(struct dev_dax *dev_dax) > +{ > + return max_t(unsigned long, dev_dax->align, memremap_compat_align()); > +} > + > +static inline bool size_is_aligned(struct dev_dax *dev_dax, resource_size_t size) Leave the name alloc_is_aligned() may generate less churn in this patch DJ > +{ > + /* > + * The minimum mapping granularity for a device instance is a > + * single subsection, unless the arch says otherwise. > + */ > + return IS_ALIGNED(size, dev_dax_min_align(dev_dax)); > +} > + > +static inline bool range_is_aligned(struct dev_dax *dev_dax, u64 start, > + resource_size_t size) > +{ > + return IS_ALIGNED(start | size, dev_dax_min_align(dev_dax)); > +} > + > +static resource_size_t > +aligned_gap_size(struct dev_dax *dev_dax, resource_size_t *start, > + resource_size_t end) > +{ > + resource_size_t aligned_start = ALIGN(*start, dev_dax_min_align(dev_dax)); > + resource_size_t size; > + > + if (aligned_start < *start || aligned_start > end) > + return 0; > + > + size = ALIGN_DOWN(end - aligned_start + 1, dev_dax_min_align(dev_dax)); > + if (!size) > + return 0; > + > + *start = aligned_start; > + return size; > +} > + > static int alloc_dev_dax_range(struct dev_dax *dev_dax, u64 start, > resource_size_t size) > { > @@ -870,6 +908,9 @@ static int alloc_dev_dax_range(struct dev_dax *dev_dax, u64 start, > return 0; > } > > + if (!range_is_aligned(dev_dax, start, size)) > + return -EINVAL; > + > alloc = __request_region(res, start, size, dev_name(dev), 0); > if (!alloc) > return -ENOMEM; > @@ -923,6 +964,9 @@ static int adjust_dev_dax_range(struct dev_dax *dev_dax, struct resource *res, r > if (dev_WARN_ONCE(dev, !size, "deletion is handled by dev_dax_shrink\n")) > return -EINVAL; > > + if (!range_is_aligned(dev_dax, range->start, size)) > + return -EINVAL; > + > rc = adjust_resource(res, range->start, size); > if (rc) > return rc; > @@ -955,15 +999,6 @@ static ssize_t size_show(struct device *dev, > return sysfs_emit(buf, "%llu\n", size); > } > > -static bool alloc_is_aligned(struct dev_dax *dev_dax, resource_size_t size) > -{ > - /* > - * The minimum mapping granularity for a device instance is a > - * single subsection, unless the arch says otherwise. > - */ > - return IS_ALIGNED(size, max_t(unsigned long, dev_dax->align, memremap_compat_align())); > -} > - > static int dev_dax_shrink(struct dev_dax *dev_dax, resource_size_t size) > { > resource_size_t to_shrink = dev_dax_size(dev_dax) - size; > @@ -1030,30 +1065,55 @@ static bool adjust_ok(struct dev_dax *dev_dax, struct resource *res) > return true; > } > > +static resource_size_t > +dax_region_aligned_avail_size(struct dax_region *dax_region, > + struct dev_dax *dev_dax) > +{ > + struct resource *region_res = &dax_region->res; > + resource_size_t start = region_res->start; > + resource_size_t avail = 0; > + struct resource *res; > + > + lockdep_assert_held_write(&dax_region_rwsem); > + > + for_each_dax_region_resource(dax_region, res) { > + if (res->start > start) { > + resource_size_t gap_start = start; > + > + avail += aligned_gap_size(dev_dax, &gap_start, > + res->start - 1); > + } > + start = res->end + 1; > + } > + if (start <= region_res->end) > + avail += aligned_gap_size(dev_dax, &start, region_res->end); > + > + return avail; > +} > + > static ssize_t dev_dax_resize(struct dax_region *dax_region, > struct dev_dax *dev_dax, resource_size_t size) > { > - resource_size_t avail = dax_region_avail_size(dax_region), to_alloc; > resource_size_t dev_size = dev_dax_size(dev_dax); > struct resource *region_res = &dax_region->res; > struct device *dev = &dev_dax->dev; > struct resource *res, *first; > - resource_size_t alloc = 0; > + resource_size_t alloc, to_alloc; > int rc; > > if (dev->driver) > return -EBUSY; > if (size == dev_size) > return 0; > - if (size > dev_size && size - dev_size > avail) > - return -ENOSPC; > if (size < dev_size) > return dev_dax_shrink(dev_dax, size); > > to_alloc = size - dev_size; > - if (dev_WARN_ONCE(dev, !alloc_is_aligned(dev_dax, to_alloc), > - "resize of %pa misaligned\n", &to_alloc)) > + if (dev_WARN_ONCE(dev, !size_is_aligned(dev_dax, to_alloc), > + "resize of %pa misaligned\n", &to_alloc)) > return -ENXIO; > + if (to_alloc > dax_region_aligned_avail_size(dax_region, dev_dax)) > + return -ENOSPC; > > /* > * Expand the device into the unused portion of the region. This > @@ -1062,37 +1122,52 @@ static ssize_t dev_dax_resize(struct dax_region *dax_region, > */ > retry: > first = region_res->child; > - if (!first) > - return alloc_dev_dax_range(dev_dax, dax_region->res.start, to_alloc); > + if (!first) { > + resource_size_t start = region_res->start; > + > + alloc = aligned_gap_size(dev_dax, &start, region_res->end); > + return alloc_dev_dax_range(dev_dax, start, > + min(alloc, to_alloc)); > + } > > rc = -ENOSPC; > for (res = first; res; res = res->sibling) { > struct resource *next = res->sibling; > + resource_size_t start, end; > > /* space at the beginning of the region */ > if (res == first && res->start > dax_region->res.start) { > - alloc = min(res->start - dax_region->res.start, to_alloc); > - rc = alloc_dev_dax_range(dev_dax, dax_region->res.start, alloc); > - break; > + start = dax_region->res.start; > + end = res->start - 1; > + alloc = min(aligned_gap_size(dev_dax, &start, end), to_alloc); > + if (alloc) { > + rc = alloc_dev_dax_range(dev_dax, start, alloc); > + break; > + } > } > > - alloc = 0; > /* space between allocations */ > - if (next && next->start > res->end + 1) > - alloc = min(next->start - (res->end + 1), to_alloc); > - > - /* space at the end of the region */ > - if (!alloc && !next && res->end < region_res->end) > - alloc = min(region_res->end - res->end, to_alloc); > + if (next) { > + if (next->start <= res->end + 1) > + continue; > + end = next->start - 1; > + } else { > + /* space at the end of the region */ > + if (res->end >= region_res->end) > + continue; > + end = region_res->end; > + } > > + start = res->end + 1; > + alloc = min(aligned_gap_size(dev_dax, &start, end), to_alloc); > if (!alloc) > continue; > > - if (adjust_ok(dev_dax, res)) { > + if (start == res->end + 1 && adjust_ok(dev_dax, res)) { > rc = adjust_dev_dax_range(dev_dax, res, resource_size(res) + alloc); > break; > } > - rc = alloc_dev_dax_range(dev_dax, res->end + 1, alloc); > + rc = alloc_dev_dax_range(dev_dax, start, alloc); > break; > } > if (rc) > @@ -1115,7 +1190,7 @@ static ssize_t size_store(struct device *dev, struct device_attribute *attr, > if (rc) > return rc; > > - if (!alloc_is_aligned(dev_dax, val)) { > + if (!size_is_aligned(dev_dax, val)) { > dev_dbg(dev, "%s: size: %lld misaligned\n", __func__, val); > return -EINVAL; > } > @@ -1201,7 +1276,7 @@ static ssize_t mapping_store(struct device *dev, struct device_attribute *attr, > } > > to_alloc = range_len(&r); > - if (alloc_is_aligned(dev_dax, to_alloc)) > + if (size_is_aligned(dev_dax, to_alloc)) > rc = alloc_dev_dax_range(dev_dax, r.start, to_alloc); > up_write(&dax_dev_rwsem); > up_write(&dax_region_rwsem); > @@ -1224,9 +1299,9 @@ static ssize_t dev_dax_validate_align(struct dev_dax *dev_dax) > int i; > > for (i = 0; i < dev_dax->nr_range; i++) { > - size_t len = range_len(&dev_dax->ranges[i].range); > + struct range *range = &dev_dax->ranges[i].range; > > - if (!alloc_is_aligned(dev_dax, len)) { > + if (!range_is_aligned(dev_dax, range->start, range_len(range))) { > dev_dbg(dev, "%s: align %u invalid for range %d\n", > __func__, dev_dax->align, i); > return -EINVAL; > @@ -1464,6 +1539,7 @@ static struct dev_dax *__devm_create_dev_dax(struct dev_dax_data *data) > return ERR_PTR(-ENOMEM); > > dev_dax->region = dax_region; > + dev_dax->align = dax_region->align; > if (is_static(dax_region)) { > if (dev_WARN_ONCE(parent, data->id < 0, > "dynamic id specified to static region\n")) { > @@ -1522,7 +1598,6 @@ static struct dev_dax *__devm_create_dev_dax(struct dev_dax_data *data) > > dev_dax->dax_dev = dax_dev; > dev_dax->target_node = dax_region->target_node; > - dev_dax->align = dax_region->align; > ida_init(&dev_dax->ida); > > dev_dax->memmap_on_memory = data->memmap_on_memory; ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/2] dax/bus: fix Device DAX range alignment validation 2026-09-21 21:01 ` Dave Jiang @ 2026-09-22 2:21 ` Muchun Song 0 siblings, 0 replies; 11+ messages in thread From: Muchun Song @ 2026-09-22 2:21 UTC (permalink / raw) To: Dave Jiang Cc: Muchun Song, Dan Williams, Vishal Verma, Alison Schofield, Andrew Morton, Joao Martins, nvdimm, linux-cxl, linux-kernel > On Sep 22, 2026, at 05:01, Dave Jiang <dave.jiang@intel.com> wrote: > > > > On 9/15/26 2:56 AM, Muchun Song wrote: >> dev_dax->align describes the page size used by a Device DAX mapping. >> Both the start and size of every range must therefore be aligned to it; >> otherwise the starting PFN cannot represent a naturally aligned page of >> that size. >> >> Only range sizes are currently validated. A dynamic device can therefore >> select a large-page alignment and allocate a range whose start is not >> naturally aligned to that page size. The device binds successfully, but a >> subsequent write to a userspace mapping may trigger a kernel panic. >> >> The automatic resize path can also split a size-aligned request across >> arbitrary free gaps. When devices with different alignments fragment a >> region, this can extend a range by less than its alignment. A later >> allocation then fails, leaving the failed resize partially applied. >> >> Validate both the start and size of allocated and adjusted ranges. Make >> the resize path account only for usable aligned space before changing any >> ranges, and skip gaps that cannot satisfy the device alignment. Initialize >> the device alignment before allocating its initial range so that all >> allocations use the same validation. >> >> A mapping with an unaligned start is now rejected with -EINVAL, while a >> naturally aligned mapping still binds successfully. >> >> Fixes: 6d82120f4156 ("device-dax: add an 'align' attribute") >> Assisted-by: LLM >> Signed-off-by: Muchun Song <songmuchun@bytedance.com> >> --- >> drivers/dax/bus.c | 143 +++++++++++++++++++++++++++++++++++----------- >> 1 file changed, 109 insertions(+), 34 deletions(-) >> >> diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c >> index b809e1a264af..54e4bbc98218 100644 >> --- a/drivers/dax/bus.c >> +++ b/drivers/dax/bus.c >> @@ -848,6 +848,44 @@ static int devm_register_dax_mapping(struct dev_dax *dev_dax, int range_id) >> return 0; >> } >> >> +static inline unsigned long dev_dax_min_align(struct dev_dax *dev_dax) >> +{ >> + return max_t(unsigned long, dev_dax->align, memremap_compat_align()); >> +} >> + >> +static inline bool size_is_aligned(struct dev_dax *dev_dax, resource_size_t size) > > Leave the name alloc_is_aligned() may generate less churn in this patch > Yes, I initially thought that `alloc_is_aligned` was doing a size check, in order to keep it clearly consistent with `range_is_aligned`. But this did indeed introduce unnecessary churn, and it might be more suitable for a separate cleanup later, rather than being squeezed into this series. Thanks for your review. Muchun ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 2/2] dax/bus: fix mapping attribute error reporting 2026-09-15 9:56 [PATCH 0/2] dax: Fix Device DAX range allocation validation Muchun Song 2026-09-15 9:56 ` [PATCH 1/2] dax/bus: fix Device DAX range alignment validation Muchun Song @ 2026-09-15 9:56 ` Muchun Song 2026-09-21 19:23 ` Dave Jiang 2026-09-18 17:02 ` [PATCH 0/2] dax: Fix Device DAX range allocation validation Dave Jiang 2 siblings, 1 reply; 11+ messages in thread From: Muchun Song @ 2026-09-15 9:56 UTC (permalink / raw) To: Dan Williams, Vishal Verma, Dave Jiang, Alison Schofield Cc: Andrew Morton, Joao Martins, nvdimm, linux-cxl, linux-kernel, Muchun Song, muchun.song After the DAX configuration locking was converted to rwsems, successful lock acquisition leaves rc set to zero in mapping_store(). If the requested range size is misaligned, the allocation is skipped and the zero rc is converted to len. The sysfs write therefore reports success without allocating the requested range. Call alloc_dev_dax_range() unconditionally and let its full range validation return -EINVAL for a misaligned start or size. Fixes: c05ae9d85b47 ("dax/bus.c: replace driver-core lock usage by a local rwsem") Assisted-by: LLM Signed-off-by: Muchun Song <songmuchun@bytedance.com> --- drivers/dax/bus.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c index 54e4bbc98218..f232001ff5b7 100644 --- a/drivers/dax/bus.c +++ b/drivers/dax/bus.c @@ -1276,8 +1276,7 @@ static ssize_t mapping_store(struct device *dev, struct device_attribute *attr, } to_alloc = range_len(&r); - if (size_is_aligned(dev_dax, to_alloc)) - rc = alloc_dev_dax_range(dev_dax, r.start, to_alloc); + rc = alloc_dev_dax_range(dev_dax, r.start, to_alloc); up_write(&dax_dev_rwsem); up_write(&dax_region_rwsem); -- 2.54.0 ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 2/2] dax/bus: fix mapping attribute error reporting 2026-09-15 9:56 ` [PATCH 2/2] dax/bus: fix mapping attribute error reporting Muchun Song @ 2026-09-21 19:23 ` Dave Jiang 2026-09-22 2:27 ` Muchun Song 0 siblings, 1 reply; 11+ messages in thread From: Dave Jiang @ 2026-09-21 19:23 UTC (permalink / raw) To: Muchun Song, Dan Williams, Vishal Verma, Alison Schofield Cc: Andrew Morton, Joao Martins, nvdimm, linux-cxl, linux-kernel, muchun.song On 9/15/26 2:56 AM, Muchun Song wrote: > After the DAX configuration locking was converted to rwsems, successful > lock acquisition leaves rc set to zero in mapping_store(). If the requested > range size is misaligned, the allocation is skipped and the zero rc is > converted to len. The sysfs write therefore reports success without > allocating the requested range. > > Call alloc_dev_dax_range() unconditionally and let its full range > validation return -EINVAL for a misaligned start or size. > > Fixes: c05ae9d85b47 ("dax/bus.c: replace driver-core lock usage by a local rwsem") > Assisted-by: LLM > Signed-off-by: Muchun Song <songmuchun@bytedance.com> > --- > drivers/dax/bus.c | 3 +-- > 1 file changed, 1 insertion(+), 2 deletions(-) > > diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c > index 54e4bbc98218..f232001ff5b7 100644 > --- a/drivers/dax/bus.c > +++ b/drivers/dax/bus.c > @@ -1276,8 +1276,7 @@ static ssize_t mapping_store(struct device *dev, struct device_attribute *attr, > } > > to_alloc = range_len(&r); > - if (size_is_aligned(dev_dax, to_alloc)) > - rc = alloc_dev_dax_range(dev_dax, r.start, to_alloc); > + rc = alloc_dev_dax_range(dev_dax, r.start, to_alloc); > up_write(&dax_dev_rwsem); > up_write(&dax_region_rwsem); > So this patch becomes somewhat of a backport issue as it depends on patch 1. Please consider swap the ordering of your patch series and fix this issue first. Maybe something like so the fix can be independently backported: diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c index b809e1a264af..e40c25401cf0 100644 --- a/drivers/dax/bus.c +++ b/drivers/dax/bus.c @@ -1192,7 +1192,7 @@ static ssize_t mapping_store(struct device *dev, struct de vice_attribute *attr, return rc; if (!dax_region->dev->driver) { up_write(&dax_region_rwsem); - return rc; + return -ENXIO; } rc = down_write_killable(&dax_dev_rwsem); if (rc) { @@ -1201,8 +1201,12 @@ static ssize_t mapping_store(struct device *dev, struct d evice_attribute *attr, } to_alloc = range_len(&r); - if (alloc_is_aligned(dev_dax, to_alloc)) + if (!alloc_is_aligned(dev_dax, to_alloc)) { + dev_dbg(dev, "%s: size: %zu misaligned\n", __func__, to_alloc); + rc = -EINVAL; + } else { rc = alloc_dev_dax_range(dev_dax, r.start, to_alloc); + } up_write(&dax_dev_rwsem); up_write(&dax_region_rwsem); ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 2/2] dax/bus: fix mapping attribute error reporting 2026-09-21 19:23 ` Dave Jiang @ 2026-09-22 2:27 ` Muchun Song 0 siblings, 0 replies; 11+ messages in thread From: Muchun Song @ 2026-09-22 2:27 UTC (permalink / raw) To: Dave Jiang Cc: Muchun Song, Dan Williams, Vishal Verma, Alison Schofield, Andrew Morton, Joao Martins, nvdimm, linux-cxl, linux-kernel > On Sep 22, 2026, at 03:23, Dave Jiang <dave.jiang@intel.com> wrote: > > > > On 9/15/26 2:56 AM, Muchun Song wrote: >> After the DAX configuration locking was converted to rwsems, successful >> lock acquisition leaves rc set to zero in mapping_store(). If the requested >> range size is misaligned, the allocation is skipped and the zero rc is >> converted to len. The sysfs write therefore reports success without >> allocating the requested range. >> >> Call alloc_dev_dax_range() unconditionally and let its full range >> validation return -EINVAL for a misaligned start or size. >> >> Fixes: c05ae9d85b47 ("dax/bus.c: replace driver-core lock usage by a local rwsem") >> Assisted-by: LLM >> Signed-off-by: Muchun Song <songmuchun@bytedance.com> >> --- >> drivers/dax/bus.c | 3 +-- >> 1 file changed, 1 insertion(+), 2 deletions(-) >> >> diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c >> index 54e4bbc98218..f232001ff5b7 100644 >> --- a/drivers/dax/bus.c >> +++ b/drivers/dax/bus.c >> @@ -1276,8 +1276,7 @@ static ssize_t mapping_store(struct device *dev, struct device_attribute *attr, >> } >> >> to_alloc = range_len(&r); >> - if (size_is_aligned(dev_dax, to_alloc)) >> - rc = alloc_dev_dax_range(dev_dax, r.start, to_alloc); >> + rc = alloc_dev_dax_range(dev_dax, r.start, to_alloc); >> up_write(&dax_dev_rwsem); >> up_write(&dax_region_rwsem); >> > > So this patch becomes somewhat of a backport issue as it depends on patch 1. Please consider swap the ordering of your patch series and fix this issue first. Maybe something like so the fix can be independently backported: Make sense. I'll update soon. Thanks, Muchun > > diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c > index b809e1a264af..e40c25401cf0 100644 > --- a/drivers/dax/bus.c > +++ b/drivers/dax/bus.c > @@ -1192,7 +1192,7 @@ static ssize_t mapping_store(struct device *dev, struct de > vice_attribute *attr, > return rc; > if (!dax_region->dev->driver) { > up_write(&dax_region_rwsem); > - return rc; > + return -ENXIO; > } > rc = down_write_killable(&dax_dev_rwsem); > if (rc) { > @@ -1201,8 +1201,12 @@ static ssize_t mapping_store(struct device *dev, struct d > evice_attribute *attr, > } > > to_alloc = range_len(&r); > - if (alloc_is_aligned(dev_dax, to_alloc)) > + if (!alloc_is_aligned(dev_dax, to_alloc)) { > + dev_dbg(dev, "%s: size: %zu misaligned\n", __func__, to_alloc); > + rc = -EINVAL; > + } else { > rc = alloc_dev_dax_range(dev_dax, r.start, to_alloc); > + } > up_write(&dax_dev_rwsem); > up_write(&dax_region_rwsem); ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 0/2] dax: Fix Device DAX range allocation validation 2026-09-15 9:56 [PATCH 0/2] dax: Fix Device DAX range allocation validation Muchun Song 2026-09-15 9:56 ` [PATCH 1/2] dax/bus: fix Device DAX range alignment validation Muchun Song 2026-09-15 9:56 ` [PATCH 2/2] dax/bus: fix mapping attribute error reporting Muchun Song @ 2026-09-18 17:02 ` Dave Jiang 2026-09-19 5:03 ` Muchun Song 2 siblings, 1 reply; 11+ messages in thread From: Dave Jiang @ 2026-09-18 17:02 UTC (permalink / raw) To: Muchun Song, Dan Williams, Vishal Verma, Alison Schofield Cc: Andrew Morton, Joao Martins, nvdimm, linux-cxl, linux-kernel, muchun.song On 9/15/26 2:56 AM, Muchun Song wrote: > While working on the HugeTLB Vmemmap Optimization (HVO) generalization, > Sashiko reported that memmap_init_zone_device() could be asked to > initialize struct pages with a large-page order for a physical range > that was not naturally aligned to that order. > > Following the Device DAX call path confirmed that the condition was > reachable. Device DAX range validation checks the range size, but not > its start address. An unaligned range can therefore reach > memmap_init_zone_device() after the device binds, and a subsequent write > to a userspace mapping may trigger a kernel panic. With the help of an > LLM, I was able to reproduce the failure. > > The automatic resize path has a related problem. It can split an aligned > size request across arbitrary free gaps, consume an unaligned fragment, > and leave the resize partially applied when a later allocation fails. > > This series validates both the start and size of every Device DAX range > and makes automatic resize account only for usable aligned space. It > also fixes the mapping sysfs attribute to propagate validation failures > instead of reporting success without allocating the requested range. > > Muchun Song (2): > dax/bus: fix Device DAX range alignment validation > dax/bus: fix mapping attribute error reporting > > drivers/dax/bus.c | 144 +++++++++++++++++++++++++++++++++++----------- > 1 file changed, 109 insertions(+), 35 deletions(-) > > > base-commit: 1a1de54f7369cd2b5bac0f265910e60ad3a6b4c3 This commit does not exist in Linus's tree. Can you please base the series on top of the latest 7.3-rc tag so sashiko can look over it? Thanks! ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 0/2] dax: Fix Device DAX range allocation validation 2026-09-18 17:02 ` [PATCH 0/2] dax: Fix Device DAX range allocation validation Dave Jiang @ 2026-09-19 5:03 ` Muchun Song 2026-09-21 18:58 ` Dave Jiang 0 siblings, 1 reply; 11+ messages in thread From: Muchun Song @ 2026-09-19 5:03 UTC (permalink / raw) To: Dave Jiang Cc: Muchun Song, Dan Williams, Vishal Verma, Alison Schofield, Andrew Morton, Joao Martins, nvdimm, linux-cxl, linux-kernel > On Sep 19, 2026, at 01:02, Dave Jiang <dave.jiang@intel.com> wrote: > > > > On 9/15/26 2:56 AM, Muchun Song wrote: >> While working on the HugeTLB Vmemmap Optimization (HVO) generalization, >> Sashiko reported that memmap_init_zone_device() could be asked to >> initialize struct pages with a large-page order for a physical range >> that was not naturally aligned to that order. >> >> Following the Device DAX call path confirmed that the condition was >> reachable. Device DAX range validation checks the range size, but not >> its start address. An unaligned range can therefore reach >> memmap_init_zone_device() after the device binds, and a subsequent write >> to a userspace mapping may trigger a kernel panic. With the help of an >> LLM, I was able to reproduce the failure. >> >> The automatic resize path has a related problem. It can split an aligned >> size request across arbitrary free gaps, consume an unaligned fragment, >> and leave the resize partially applied when a later allocation fails. >> >> This series validates both the start and size of every Device DAX range >> and makes automatic resize account only for usable aligned space. It >> also fixes the mapping sysfs attribute to propagate validation failures >> instead of reporting success without allocating the requested range. >> >> Muchun Song (2): >> dax/bus: fix Device DAX range alignment validation >> dax/bus: fix mapping attribute error reporting >> >> drivers/dax/bus.c | 144 +++++++++++++++++++++++++++++++++++----------- >> 1 file changed, 109 insertions(+), 35 deletions(-) >> >> >> base-commit: 1a1de54f7369cd2b5bac0f265910e60ad3a6b4c3 > > This commit does not exist in Linus's tree. Can you please base the series on top of the latest 7.3-rc tag so sashiko can look over it? Thanks! Hi, The series is based on linux-next 20260914, and drivers/dax/bus.c is identical between that branch and the latest 7.3-rc. Sashiko has also already reviewed it here: [1]. Therefore, I didn't quite catch your point. Are you expecting Sashiko to conduct another round of review based on the 7.3-rc code? (Are you concerned about issues introduced by the additional commits in linux-next compared to 7.3-rc?) [1] https://sashiko.dev/#/patchset/20260915095621.3744167-1-songmuchun%40bytedance.com Thanks, Muchun ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 0/2] dax: Fix Device DAX range allocation validation 2026-09-19 5:03 ` Muchun Song @ 2026-09-21 18:58 ` Dave Jiang 2026-09-22 2:25 ` Muchun Song 0 siblings, 1 reply; 11+ messages in thread From: Dave Jiang @ 2026-09-21 18:58 UTC (permalink / raw) To: Muchun Song Cc: Muchun Song, Dan Williams, Vishal Verma, Alison Schofield, Andrew Morton, Joao Martins, nvdimm, linux-cxl, linux-kernel On 9/18/26 10:03 PM, Muchun Song wrote: > > >> On Sep 19, 2026, at 01:02, Dave Jiang <dave.jiang@intel.com> wrote: >> >> >> >> On 9/15/26 2:56 AM, Muchun Song wrote: >>> While working on the HugeTLB Vmemmap Optimization (HVO) generalization, >>> Sashiko reported that memmap_init_zone_device() could be asked to >>> initialize struct pages with a large-page order for a physical range >>> that was not naturally aligned to that order. >>> >>> Following the Device DAX call path confirmed that the condition was >>> reachable. Device DAX range validation checks the range size, but not >>> its start address. An unaligned range can therefore reach >>> memmap_init_zone_device() after the device binds, and a subsequent write >>> to a userspace mapping may trigger a kernel panic. With the help of an >>> LLM, I was able to reproduce the failure. >>> >>> The automatic resize path has a related problem. It can split an aligned >>> size request across arbitrary free gaps, consume an unaligned fragment, >>> and leave the resize partially applied when a later allocation fails. >>> >>> This series validates both the start and size of every Device DAX range >>> and makes automatic resize account only for usable aligned space. It >>> also fixes the mapping sysfs attribute to propagate validation failures >>> instead of reporting success without allocating the requested range. >>> >>> Muchun Song (2): >>> dax/bus: fix Device DAX range alignment validation >>> dax/bus: fix mapping attribute error reporting >>> >>> drivers/dax/bus.c | 144 +++++++++++++++++++++++++++++++++++----------- >>> 1 file changed, 109 insertions(+), 35 deletions(-) >>> >>> >>> base-commit: 1a1de54f7369cd2b5bac0f265910e60ad3a6b4c3 >> >> This commit does not exist in Linus's tree. Can you please base the series on top of the latest 7.3-rc tag so sashiko can look over it? Thanks! > > Hi, > > The series is based on linux-next 20260914, and drivers/dax/bus.c is identical > between that branch and the latest 7.3-rc. Sashiko has also already reviewed it > here: [1]. > > Therefore, I didn't quite catch your point. Are you expecting Sashiko to conduct > another round of review based on the 7.3-rc code? (Are you concerned about issues > introduced by the additional commits in linux-next compared to 7.3-rc?) Ok that's fine. But next time please use a tag that's valid from Linus tree and not linux-next. While there's a sashiko link, I'd like to see the sashiko response on the mailing list for easier review. I'm not sure if it's due to the base commit or something else for it to not show up. Sometimes sashiko responds with no regression found and sometimes it just does not respond. I'm not sure why the varied behavior. DJ > > [1] https://sashiko.dev/#/patchset/20260915095621.3744167-1-songmuchun%40bytedance.com > > Thanks, > Muchun > > ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 0/2] dax: Fix Device DAX range allocation validation 2026-09-21 18:58 ` Dave Jiang @ 2026-09-22 2:25 ` Muchun Song 0 siblings, 0 replies; 11+ messages in thread From: Muchun Song @ 2026-09-22 2:25 UTC (permalink / raw) To: Dave Jiang Cc: Muchun Song, Dan Williams, Vishal Verma, Alison Schofield, Andrew Morton, Joao Martins, nvdimm, linux-cxl, linux-kernel > On Sep 22, 2026, at 02:58, Dave Jiang <dave.jiang@intel.com> wrote: > > > > On 9/18/26 10:03 PM, Muchun Song wrote: >> >> >>> On Sep 19, 2026, at 01:02, Dave Jiang <dave.jiang@intel.com> wrote: >>> >>> >>> >>> On 9/15/26 2:56 AM, Muchun Song wrote: >>>> While working on the HugeTLB Vmemmap Optimization (HVO) generalization, >>>> Sashiko reported that memmap_init_zone_device() could be asked to >>>> initialize struct pages with a large-page order for a physical range >>>> that was not naturally aligned to that order. >>>> >>>> Following the Device DAX call path confirmed that the condition was >>>> reachable. Device DAX range validation checks the range size, but not >>>> its start address. An unaligned range can therefore reach >>>> memmap_init_zone_device() after the device binds, and a subsequent write >>>> to a userspace mapping may trigger a kernel panic. With the help of an >>>> LLM, I was able to reproduce the failure. >>>> >>>> The automatic resize path has a related problem. It can split an aligned >>>> size request across arbitrary free gaps, consume an unaligned fragment, >>>> and leave the resize partially applied when a later allocation fails. >>>> >>>> This series validates both the start and size of every Device DAX range >>>> and makes automatic resize account only for usable aligned space. It >>>> also fixes the mapping sysfs attribute to propagate validation failures >>>> instead of reporting success without allocating the requested range. >>>> >>>> Muchun Song (2): >>>> dax/bus: fix Device DAX range alignment validation >>>> dax/bus: fix mapping attribute error reporting >>>> >>>> drivers/dax/bus.c | 144 +++++++++++++++++++++++++++++++++++----------- >>>> 1 file changed, 109 insertions(+), 35 deletions(-) >>>> >>>> >>>> base-commit: 1a1de54f7369cd2b5bac0f265910e60ad3a6b4c3 >>> >>> This commit does not exist in Linus's tree. Can you please base the series on top of the latest 7.3-rc tag so sashiko can look over it? Thanks! >> >> Hi, >> >> The series is based on linux-next 20260914, and drivers/dax/bus.c is identical >> between that branch and the latest 7.3-rc. Sashiko has also already reviewed it >> here: [1]. >> >> Therefore, I didn't quite catch your point. Are you expecting Sashiko to conduct >> another round of review based on the 7.3-rc code? (Are you concerned about issues >> introduced by the additional commits in linux-next compared to 7.3-rc?) > > Ok that's fine. But next time please use a tag that's valid from Linus tree and not linux-next. While there's a sashiko link, I'd like to see the sashiko response on the mailing list for easier review. I'm not sure if it's due to the base commit or something else for it to not show up. Sometimes sashiko responds with no regression found and sometimes it just does not respond. I'm not sure why the varied behavior. I previously worked based on the mm development model, and this is my first time learning about the development rules for DAX. I will develop DAX based on Linus's tree going forward. Thanks, Muchun > > DJ > > >> >> [1] https://sashiko.dev/#/patchset/20260915095621.3744167-1-songmuchun%40bytedance.com >> >> Thanks, >> Muchun ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-09-22 2:27 UTC | newest] Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-09-15 9:56 [PATCH 0/2] dax: Fix Device DAX range allocation validation Muchun Song 2026-09-15 9:56 ` [PATCH 1/2] dax/bus: fix Device DAX range alignment validation Muchun Song 2026-09-21 21:01 ` Dave Jiang 2026-09-22 2:21 ` Muchun Song 2026-09-15 9:56 ` [PATCH 2/2] dax/bus: fix mapping attribute error reporting Muchun Song 2026-09-21 19:23 ` Dave Jiang 2026-09-22 2:27 ` Muchun Song 2026-09-18 17:02 ` [PATCH 0/2] dax: Fix Device DAX range allocation validation Dave Jiang 2026-09-19 5:03 ` Muchun Song 2026-09-21 18:58 ` Dave Jiang 2026-09-22 2:25 ` Muchun Song
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®