On Mon, Jun 08, 2026 at 05:12:59PM -0700, Dave Jiang wrote:
> 
> 
> On 5/23/26 2:50 AM, Anisa Su wrote:
> > Add a --uuid option to 'daxctl create-device' that writes the given
> > uuid to the new dax device's sysfs 'uuid' attribute.  On sparse (DCD)
> > regions this claims dax_resources whose tag matches and populates the
> > seed device with their capacity; size is determined by the claim, so
> > --uuid is mutually exclusive with --size.
> > 
> > Pass "0" to claim a single untagged dax_resource.  A claim that
> > matches no dax_resource leaves the device at size 0; the kernel
> > returns ENOENT.
> > 
> > Plumb the write through a new daxctl_dev_set_uuid() libdaxctl helper
> > (LIBDAXCTL_11) and document the option in the man page.
> > 
> > Signed-off-by: Anisa Su <[email protected]>
> > ---
> >  Documentation/daxctl/daxctl-create-device.txt | 12 ++++
> >  daxctl/device.c                               | 72 +++++++++++++------
> >  daxctl/lib/libdaxctl.c                        | 44 ++++++++++++
> >  daxctl/lib/libdaxctl.sym                      |  5 ++
> >  daxctl/libdaxctl.h                            |  1 +
> >  5 files changed, 114 insertions(+), 20 deletions(-)
> > 
> > diff --git a/Documentation/daxctl/daxctl-create-device.txt 
> > b/Documentation/daxctl/daxctl-create-device.txt
> > index b774b86..27b87d0 100644
> > --- a/Documentation/daxctl/daxctl-create-device.txt
> > +++ b/Documentation/daxctl/daxctl-create-device.txt
> > @@ -82,6 +82,18 @@ include::region-option.txt[]
> >  
> >     The size must be a multiple of the region alignment.
> >  
> > +   Mutually exclusive with --uuid.
> > +
> > +--uuid=::
> > +   For dax devices on sparse (DCD) regions, claim dax_resource(s) whose
> > +   tag matches the given UUID.  The device's size is determined by the
> > +   claimed capacity, so --uuid cannot be combined with --size.
> > +
> > +   A non-null UUID claims every matching dax_resource in the parent
> > +   region.  The value "0" is shorthand for the null UUID and claims a
> > +   single untagged dax_resource.  A write that matches no dax_resource
> > +   fails with ENOENT and the device is left at size 0.
> > +
> >  -a::
> >  --align::
> >     Applications that want to establish dax memory mappings with
> > diff --git a/daxctl/device.c b/daxctl/device.c
> > index a4e36b1..21a941e 100644
> > --- a/daxctl/device.c
> > +++ b/daxctl/device.c
> > @@ -30,6 +30,7 @@ static struct {
> >     const char *size;
> >     const char *align;
> >     const char *input;
> > +   const char *uuid;
> >     bool check_config;
> >     bool no_online;
> >     bool no_movable;
> > @@ -85,7 +86,9 @@ OPT_BOOLEAN('C', "check-config", &param.check_config, \
> >  #define CREATE_OPTIONS() \
> >  OPT_STRING('s', "size", &param.size, "size", "size to switch the device 
> > to"), \
> >  OPT_STRING('a', "align", &param.align, "align", "alignment to switch the 
> > device to"), \
> > -OPT_STRING('\0', "input", &param.input, "input", "input device JSON file")
> > +OPT_STRING('\0', "input", &param.input, "input", "input device JSON 
> > file"), \
> > +OPT_STRING('\0', "uuid", &param.uuid, "uuid", \
> > +   "claim sparse dax_resource(s) matching this uuid (\"0\" for untagged)")
> >  
> >  #define DESTROY_OPTIONS() \
> >  OPT_BOOLEAN('f', "force", &param.force, \
> > @@ -808,6 +811,22 @@ static int do_create(struct daxctl_region *region, 
> > long long val,
> >     struct daxctl_dev *dev;
> >     int i, rc = 0;
> >     long long alloc = 0;
> > +   uuid_t uuid;
> > +
> > +   if (param.uuid) {
> > +           if (param.size) {
> > +                   fprintf(stderr,
> > +                           "--uuid and --size are mutually exclusive\n");
> > +                   return -EINVAL;
> > +           }
> > +           if (strcmp(param.uuid, "0") == 0) {
> > +                   uuid_clear(uuid);
> > +           } else if (uuid_parse(param.uuid, uuid) < 0) {
> > +                   fprintf(stderr, "failed to parse uuid '%s'\n",
> > +                           param.uuid);
> > +                   return -EINVAL;
> > +           }
> > +   }
> >  
> >     if (daxctl_region_create_dev(region))
> >             return -ENOSPC;
> > @@ -816,33 +835,46 @@ static int do_create(struct daxctl_region *region, 
> > long long val,
> >     if (!dev)
> >             return -ENOSPC;
> >  
> > -   if (val == -1)
> > -           val = daxctl_region_get_available_size(region);
> > -
> > -   if (val <= 0)
> > -           return -ENOSPC;
> > -
> >     if (align > 0) {
> >             rc = daxctl_dev_set_align(dev, align);
> >             if (rc < 0)
> >                     return rc;
> >     }
> >  
> > -   /* @maps is ordered by page_offset */
> > -   for (i = 0; i < nmaps; i++) {
> > -           rc = daxctl_dev_set_mapping(dev, maps[i].start, maps[i].end);
> > -           if (rc < 0)
> > +   if (param.uuid) {
> > +           rc = daxctl_dev_set_uuid(dev, uuid);
> > +           if (rc < 0) {
> > +                   fprintf(stderr,
> > +                           "%s: failed to claim uuid '%s': %s\n",
> > +                           daxctl_dev_get_devname(dev), param.uuid,
> > +                           strerror(-rc));
> >                     return rc;
> > -           alloc += (maps[i].end - maps[i].start + 1);
> > -   }
> > -
> > -   if (nmaps > 0 && val > 0 && alloc != val) {
> > -           fprintf(stderr, "%s: allocated %lld but specified size %lld\n",
> > -                   daxctl_dev_get_devname(dev), alloc, val);
> > +           }
> >     } else {
> > -           rc = daxctl_dev_set_size(dev, val);
> > -           if (rc < 0)
> > -                   return rc;
> > +           if (val == -1)
> > +                   val = daxctl_region_get_available_size(region);
> > +
> > +           if (val <= 0)
> > +                   return -ENOSPC;
> > +
> > +           /* @maps is ordered by page_offset */
> > +           for (i = 0; i < nmaps; i++) {
> > +                   rc = daxctl_dev_set_mapping(dev, maps[i].start,
> > +                                               maps[i].end);
> > +                   if (rc < 0)
> > +                           return rc;
> > +                   alloc += (maps[i].end - maps[i].start + 1);
> > +           }
> > +
> > +           if (nmaps > 0 && val > 0 && alloc != val) {
> > +                   fprintf(stderr,
> > +                           "%s: allocated %lld but specified size %lld\n",
> > +                           daxctl_dev_get_devname(dev), alloc, val);
> > +           } else {
> > +                   rc = daxctl_dev_set_size(dev, val);
> > +                   if (rc < 0)
> > +                           return rc;
> > +           }
> >     }
> >  
> >     rc = daxctl_dev_enable_devdax(dev);
> > diff --git a/daxctl/lib/libdaxctl.c b/daxctl/lib/libdaxctl.c
> > index 02ae7e5..fe07939 100644
> > --- a/daxctl/lib/libdaxctl.c
> > +++ b/daxctl/lib/libdaxctl.c
> > @@ -1107,6 +1107,50 @@ DAXCTL_EXPORT int daxctl_dev_set_size(struct 
> > daxctl_dev *dev, unsigned long long
> >     return 0;
> >  }
> >  
> > +DAXCTL_EXPORT int daxctl_dev_set_uuid(struct daxctl_dev *dev, uuid_t uuid)
> > +{
> > +   struct daxctl_ctx *ctx = daxctl_dev_get_ctx(dev);
> > +   char buf[SYSFS_ATTR_SIZE];
> > +   char *path = dev->dev_buf;
> > +   int len = dev->buf_len;
> > +
> > +   if (snprintf(path, len, "%s/uuid", dev->dev_path) >= len) {
> > +           err(ctx, "%s: buffer too small!\n",
> > +                           daxctl_dev_get_devname(dev));
> > +           return -ENXIO;
> 
> snprintf() returns negative errno, propogate
> 
> > +   }
> > +
> > +   if (uuid_is_null(uuid))
> > +           sprintf(buf, "0\n");
> > +   else
> > +           uuid_unparse(uuid, buf);
> > +
> > +   if (sysfs_write_attr(ctx, path, buf) < 0) {
> > +           err(ctx, "%s: failed to set uuid\n",
> > +                           daxctl_dev_get_devname(dev));
> > +           return -ENXIO;
> 
> propogate the errno from sysfs_write_attr()
> 
> > +   }
> > +
> > +   /*
> > +    * On a sparse region the kernel populates the device size as a
> > +    * side effect of claiming the matching dax_resource(s); refresh
> > +    * the cached size so callers see the post-claim value.
> > +    */
> > +   if (snprintf(path, len, "%s/size", dev->dev_path) >= len) {
> > +           err(ctx, "%s: buffer too small!\n",
> > +                           daxctl_dev_get_devname(dev));
> > +           return -ENXIO;
> 
> propogate negative return value from snprintf()
> 
> > +   }
> > +   if (sysfs_read_attr(ctx, path, buf) < 0) {
> > +           err(ctx, "%s: failed to read back size\n",
> > +                           daxctl_dev_get_devname(dev));
> > +           return -ENXIO;
> 
> propgate negative errno from sysfs_read_attr()
> 
errno propagated. For snprintf, since it returns pos rc if output was
truncated:

rc = snprintf(path, len, "%s/uuid", dev->dev_path);
if (rc < 0)
        return rc;
if (rc >= len) {
        err(ctx, "%s: buffer too small!\n",
                        daxctl_dev_get_devname(dev));
        return -ENXIO;
}

> > +   }
> > +   dev->size = strtoull(buf, NULL, 0);
> > +
> > +   return 0;
> > +}
> > +
> >  DAXCTL_EXPORT unsigned long daxctl_dev_get_align(struct daxctl_dev *dev)
> >  {
> >     return dev->align;
> > diff --git a/daxctl/lib/libdaxctl.sym b/daxctl/lib/libdaxctl.sym
> > index 3098811..16792eb 100644
> > --- a/daxctl/lib/libdaxctl.sym
> > +++ b/daxctl/lib/libdaxctl.sym
> > @@ -104,3 +104,8 @@ LIBDAXCTL_10 {
> >  global:
> >     daxctl_dev_is_system_ram_capable;
> >  } LIBDAXCTL_9;
> > +
> > +LIBDAXCTL_11 {
> > +global:
> > +   daxctl_dev_set_uuid;
> > +} LIBDAXCTL_10;
> > diff --git a/daxctl/libdaxctl.h b/daxctl/libdaxctl.h
> > index 53c6bbd..cdd5995 100644
> > --- a/daxctl/libdaxctl.h
> > +++ b/daxctl/libdaxctl.h
> > @@ -63,6 +63,7 @@ int daxctl_dev_get_minor(struct daxctl_dev *dev);
> >  unsigned long long daxctl_dev_get_resource(struct daxctl_dev *dev);
> >  unsigned long long daxctl_dev_get_size(struct daxctl_dev *dev);
> >  int daxctl_dev_set_size(struct daxctl_dev *dev, unsigned long long size);
> > +int daxctl_dev_set_uuid(struct daxctl_dev *dev, uuid_t uuid);
> >  unsigned long daxctl_dev_get_align(struct daxctl_dev *dev);
> >  int daxctl_dev_set_align(struct daxctl_dev *dev, unsigned long align);
> >  int daxctl_dev_set_mapping(struct daxctl_dev *dev, unsigned long long 
> > start,
> 

Reply via email to