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", ¶m.check_config, \ #define CREATE_OPTIONS() \ OPT_STRING('s', "size", ¶m.size, "size", "size to switch the device to"), \ OPT_STRING('a', "align", ¶m.align, "align", "alignment to switch the device to"), \ -OPT_STRING('\0', "input", ¶m.input, "input", "input device JSON file") +OPT_STRING('\0', "input", ¶m.input, "input", "input device JSON file"), \ +OPT_STRING('\0', "uuid", ¶m.uuid, "uuid", \ + "claim sparse dax_resource(s) matching this uuid (\"0\" for untagged)") #define DESTROY_OPTIONS() \ OPT_BOOLEAN('f', "force", ¶m.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; + } + + 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; + } + + /* + * 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; + } + if (sysfs_read_attr(ctx, path, buf) < 0) { + err(ctx, "%s: failed to read back size\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, -- 2.43.0

