On Mon, Feb 7, 2022 at 3:06 PM <[email protected]> wrote:
>
> From: Alison Schofield <[email protected]>
>
> CXL devices may support both volatile and persistent memory capacity.
> The amount of device capacity set aside for each type is typically
> established at the factory, but some devices also allow for dynamic
> re-partitioning, add a command for this purpose.
>
> Synopsis:
>
> cxl set-partition <mem0> [<mem1>..<memN>] [<options>]
>
> -t, --type=<type>       'pmem' or 'volatile' (Default: 'pmem')
> -s, --size=<size>       size in bytes (Default: all partitionable capacity)
> -a, --align             allow alignment correction
> -v, --verbose           turn on debug
>
> Signed-off-by: Alison Schofield <[email protected]>
> ---
>  Documentation/cxl/cxl-set-partition.txt |  60 ++++++++
>  Documentation/cxl/meson.build           |   1 +
>  cxl/builtin.h                           |   1 +
>  cxl/cxl.c                               |   1 +
>  cxl/memdev.c                            | 196 ++++++++++++++++++++++++
>  5 files changed, 259 insertions(+)
>  create mode 100644 Documentation/cxl/cxl-set-partition.txt
>
> diff --git a/Documentation/cxl/cxl-set-partition.txt 
> b/Documentation/cxl/cxl-set-partition.txt
> new file mode 100644
> index 0000000..e20afba
> --- /dev/null
> +++ b/Documentation/cxl/cxl-set-partition.txt
> @@ -0,0 +1,60 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +cxl-set-partition(1)
> +====================
> +
> +NAME
> +----
> +cxl-set-partition - set the partitioning between volatile and persistent 
> capacity on a CXL memdev
> +
> +SYNOPSIS
> +--------
> +[verse]
> +'cxl set-partition <mem> [ [<mem1>..<memN>] [<options>]'
> +
> +DESCRIPTION
> +-----------
> +Partition the device into volatile and persistent capacity.

I wonder if this should briefly describe the theory of operation of
partitioning of CXL devices. I.e. that this command is only relevant
for devices that support dual capacity (volatile + pmem) and only dual
capacity devices that have partitionable as opposed to static capacity
assignments. Maybe a reference to how to use 'cxl list' to determine
if 'cxl set-partition' is even relevant for the given memdev?


 The change
> +in partitioning will become the “next” configuration, to become active
> +on the next device reset.
> +
> +Use "cxl list -m <memdev> -I" to examine the partitioning capabilities
> +of a device. A partition_alignment_bytes value of zero means there are
> +no partitionable bytes available and therefore the partitions cannot be
> +changed.
> +
> +Using this command to change the size of the persistent capacity shall
> +result in the loss of data stored.
> +
> +OPTIONS
> +-------
> +<memory device(s)>::
> +include::memdev-option.txt[]
> +
> +-t::
> +--type=::
> +       Type of partition, 'pmem' or 'volatile', to create.

s/create/modify/

...since the partition is statically present, just variably sized.

> +       Default: 'pmem'
> +
> +-s::
> +--size=::
> +       Size of the <type> partition in bytes. Size must align to the
> +       devices alignment size. Use 'cxl list -m <memdev> -I' to find
> +       the 'partition_alignment_size', or, use the 'align' option.
> +       Default: All partitionable capacity is assigned to <type>.
> +
> +-a::
> +--align::
> +       This option allows the size of the partition to be increased to
> +       meet device alignment requirements.

Perhaps reword this to say it auto-aligns so that the user can specify
the minimum size of the partition?

> +
> +-v::
> +        Turn on verbose debug messages in the library (if libcxl was built 
> with
> +        logging and debug enabled).
> +
> +include::../copyright.txt[]
> +
> +SEE ALSO
> +--------
> +linkcxl:cxl-list[1],
> +CXL-2.0 8.2.9.5.2
> diff --git a/Documentation/cxl/meson.build b/Documentation/cxl/meson.build
> index 96f4666..e927644 100644
> --- a/Documentation/cxl/meson.build
> +++ b/Documentation/cxl/meson.build
> @@ -34,6 +34,7 @@ cxl_manpages = [
>    'cxl-disable-memdev.txt',
>    'cxl-enable-port.txt',
>    'cxl-disable-port.txt',
> +  'cxl-set-partition.txt',
>  ]
>
>  foreach man : cxl_manpages
> diff --git a/cxl/builtin.h b/cxl/builtin.h
> index 3123d5e..7bbad98 100644
> --- a/cxl/builtin.h
> +++ b/cxl/builtin.h
> @@ -14,4 +14,5 @@ int cmd_disable_memdev(int argc, const char **argv, struct 
> cxl_ctx *ctx);
>  int cmd_enable_memdev(int argc, const char **argv, struct cxl_ctx *ctx);
>  int cmd_disable_port(int argc, const char **argv, struct cxl_ctx *ctx);
>  int cmd_enable_port(int argc, const char **argv, struct cxl_ctx *ctx);
> +int cmd_set_partition(int argc, const char **argv, struct cxl_ctx *ctx);
>  #endif /* _CXL_BUILTIN_H_ */
> diff --git a/cxl/cxl.c b/cxl/cxl.c
> index c20c569..ab4bbec 100644
> --- a/cxl/cxl.c
> +++ b/cxl/cxl.c
> @@ -68,6 +68,7 @@ static struct cmd_struct commands[] = {
>         { "enable-memdev", .c_fn = cmd_enable_memdev },
>         { "disable-port", .c_fn = cmd_disable_port },
>         { "enable-port", .c_fn = cmd_enable_port },
> +       { "set-partition", .c_fn = cmd_set_partition },
>  };
>
>  int main(int argc, const char **argv)
> diff --git a/cxl/memdev.c b/cxl/memdev.c
> index 90b33e1..5d97610 100644
> --- a/cxl/memdev.c
> +++ b/cxl/memdev.c
> @@ -6,11 +6,14 @@
>  #include <unistd.h>
>  #include <limits.h>
>  #include <util/log.h>
> +#include <util/json.h>
> +#include <util/size.h>
>  #include <cxl/libcxl.h>
>  #include <util/parse-options.h>
>  #include <ccan/minmax/minmax.h>
>  #include <ccan/array_size/array_size.h>
>
> +#include "json.h"
>  #include "filter.h"
>
>  struct action_context {
> @@ -26,6 +29,9 @@ static struct parameters {
>         bool verbose;
>         bool serial;
>         bool force;
> +       bool align;
> +       const char *type;
> +       const char *size;
>  } param;
>
>  static struct log_ctx ml;
> @@ -51,6 +57,14 @@ OPT_UINTEGER('O', "offset", &param.offset, \
>  OPT_BOOLEAN('f', "force", &param.force,                                \
>             "DANGEROUS: override active memdev safety checks")
>
> +#define SET_PARTITION_OPTIONS() \
> +OPT_STRING('t', "type",  &param.type, "type",                  \
> +       "'pmem' or 'volatile' (Default: 'pmem')"),              \
> +OPT_STRING('s', "size",  &param.size, "size",                  \
> +       "size in bytes (Default: all partitionable capacity)"), \
> +OPT_BOOLEAN('a', "align",  &param.align,                       \
> +       "allow alignment correction")
> +
>  static const struct option read_options[] = {
>         BASE_OPTIONS(),
>         LABEL_OPTIONS(),
> @@ -82,6 +96,12 @@ static const struct option enable_options[] = {
>         OPT_END(),
>  };
>
> +static const struct option set_partition_options[] = {
> +       BASE_OPTIONS(),
> +       SET_PARTITION_OPTIONS(),
> +       OPT_END(),
> +};
> +
>  static int action_disable(struct cxl_memdev *memdev, struct action_context 
> *actx)
>  {
>         if (!cxl_memdev_is_enabled(memdev))
> @@ -209,6 +229,171 @@ out:
>         return rc;
>  }
>
> +static unsigned long long
> +partition_align(const char *devname, unsigned long long volatile_size,
> +               unsigned long long alignment, unsigned long long 
> partitionable)
> +{
> +       if (IS_ALIGNED(volatile_size, alignment))
> +               return volatile_size;
> +
> +       if (!param.align) {
> +               log_err(&ml, "%s: size %lld is not partition aligned %lld\n",
> +                       devname, volatile_size, alignment);
> +               return ULLONG_MAX;
> +       }
> +
> +       /* Align based on partition type to fulfill users size request */
> +       if (strcmp(param.type, "pmem") == 0)
> +               volatile_size = ALIGN_DOWN(volatile_size, alignment);
> +       else
> +               volatile_size = ALIGN(volatile_size, alignment);
> +
> +       /* Fail if the align pushes size over the partitionable limit. */
> +       if (volatile_size > partitionable) {
> +               log_err(&ml, "%s: aligned partition size %lld exceeds 
> partitionable size %lld\n",
> +                       devname, volatile_size, partitionable);
> +               volatile_size = ULLONG_MAX;
> +       }
> +
> +       return volatile_size;
> +}
> +
> +static unsigned long long
> +param_size_to_volatile_size(const char *devname, unsigned long long size,
> +               unsigned long long partitionable)
> +{
> +       /* User omits size option. Apply all partitionable capacity to type. 
> */
> +       if (size == ULLONG_MAX)
> +               return (strcmp(param.type, "pmem") == 0) ? 0 : partitionable;

Somewhat inefficient to keep needing to parse the string parameter
buffer. How about plumb an 'enum cxl_setpart_type type' argument to
all the functions that are parsing param.type?

Where @type is:

enum cxl_setpart_type {
    CXL_SETPART_PMEM,
    CXL_SETPART_VOLATILE,
};

Other than the above,

Reviewed-by: Dan Williams <[email protected]>

Reply via email to