[systemd-devel] [PATCH v4] nvme_id utility + support in 60-persistent-storage.rules

Lennart Poettering lennart at poettering.net
Wed May 20 05:22:53 PDT 2015


On Mon, 18.05.15 22:43, Per Bergqvist (per at bst.lu) wrote:

heya,

I talked to Kay now. He suggested that we should not add new "xyz_id"
tools anymore to udev, but actually rather remove more of them, and
have the kernel drivers export everything via sysfs, so that the
fields can be directly be accessed with ATTRS{} and $attrs{}, without
indirecting things via another tool, and more udev properties.

He suggested two options:

a) the preferred one: update the kernel driver to export the relevant
   fields in sysfs, so that udev can read them from there. when that's
   in place we can hook that up from udev without any new C code, and
   all is great.

b) maintain this outside of udev: introduce a new package nvme-tools
   or so, ship the tool there, and ask distros to add that to their
   base set of tools.

Of course, a) is much preferrably I think, and the kernel patch
shouldn't be particularly complex...

Sorry for the delay, and for putting this through multiple rouns of
reviews before then denying that...

Sorry!

Lennart

> ---
>  Makefile.am                       |  11 +++
>  rules/60-persistent-storage.rules |   5 ++
>  src/udev/nvme_id/nvme_id.c        | 147 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 163 insertions(+)
>  create mode 100644 src/udev/nvme_id/nvme_id.c
> 
> diff --git a/Makefile.am b/Makefile.am
> index bf04d31..0de0d18 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -3904,6 +3904,17 @@ dist_udevrules_DATA += \
>  	rules/60-persistent-v4l.rules
>  
>  # ------------------------------------------------------------------------------
> +nvme_id_SOURCES = \
> +	src/udev/nvme_id/nvme_id.c
> +
> +nvme_id_LDADD = \
> +	libudev-internal.la \
> +	libsystemd-shared.la
> +
> +udevlibexec_PROGRAMS += \
> +	nvme_id
> +
> +# ------------------------------------------------------------------------------
>  accelerometer_SOURCES = \
>  	src/udev/accelerometer/accelerometer.c
>  
> diff --git a/rules/60-persistent-storage.rules b/rules/60-persistent-storage.rules
> index 25b44a5..d3368a5 100644
> --- a/rules/60-persistent-storage.rules
> +++ b/rules/60-persistent-storage.rules
> @@ -42,6 +42,11 @@ KERNEL=="cciss*", ENV{DEVTYPE}=="disk", ENV{ID_SERIAL}!="?*", IMPORT{program}="s
>  KERNEL=="sd*|sr*|cciss*", ENV{DEVTYPE}=="disk", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/$env{ID_BUS}-$env{ID_SERIAL}"
>  KERNEL=="sd*|cciss*", ENV{DEVTYPE}=="partition", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/$env{ID_BUS}-$env{ID_SERIAL}-part%n"
>  
> +# NVMe
> +KERNEL=="nvme*", ENV{ID_SERIAL}!="?*", IMPORT{program}="nvme_id --export $devnode"
> +KERNEL=="nvme*", ENV{DEVTYPE}=="disk", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/nvme-$env{ID_SERIAL}"
> +KERNEL=="nvme*", ENV{DEVTYPE}=="partition", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/nvme-$env{ID_SERIAL}-part%n"
> +
>  # firewire
>  KERNEL=="sd*[!0-9]|sr*", ATTRS{ieee1394_id}=="?*", SYMLINK+="disk/by-id/ieee1394-$attr{ieee1394_id}"
>  KERNEL=="sd*[0-9]", ATTRS{ieee1394_id}=="?*", SYMLINK+="disk/by-id/ieee1394-$attr{ieee1394_id}-part%n"
> diff --git a/src/udev/nvme_id/nvme_id.c b/src/udev/nvme_id/nvme_id.c
> new file mode 100644
> index 0000000..c61b0b8
> --- /dev/null
> +++ b/src/udev/nvme_id/nvme_id.c
> @@ -0,0 +1,147 @@
> +/* -*- mode:c; tab-width:8; intent-tabs-mode:nil;  -*-
> + *
> + * nvme_id - reads model/serial/firmware revision numbers from nvme drives
> + *
> + * Copyright (C) 2015 Per Bergqvist <per at bst.lu>
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdint.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <ctype.h>
> +#include <string.h>
> +#include <errno.h>
> +#include <getopt.h>
> +#include <linux/nvme.h>
> +#include <sys/ioctl.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +
> +#include "libudev.h"
> +#include "libudev-private.h"
> +#include "udev-util.h"
> +#include "log.h"
> +
> +static int nvme_identify(struct udev *udev, int fd, void *buf, size_t buf_len) {
> +        struct nvme_admin_cmd command = {
> +                .opcode   = nvme_admin_identify,
> +                .addr     = (unsigned long)buf,
> +                .data_len = buf_len,
> +                .cdw10    = 1 };
> +
> +        if (ioctl(fd, NVME_IOCTL_ADMIN_CMD, &command) < 0)
> +                return -errno;
> +
> +        return 0;
> +}
> +
> +int main(int argc, char *argv[]) {
> +        _cleanup_udev_unref_ struct udev *udev = NULL;
> +
> +        struct nvme_id_ctrl nvme_id_ctrl = {};
> +
> +        char model[sizeof(nvme_id_ctrl.mn)+1];
> +        char model_enc[4*sizeof(nvme_id_ctrl.mn)+1];
> +        char serial[sizeof(nvme_id_ctrl.sn)+1];
> +        char revision[sizeof(nvme_id_ctrl.fr)+1];
> +
> +        const char *node = NULL;
> +        int export = 0;
> +
> +        _cleanup_close_ int fd = -1;
> +
> +        static const struct option options[] = {
> +                { "export", no_argument, NULL, 'x' },
> +                { "help", no_argument, NULL, 'h' },
> +                {}
> +        };
> +
> +        log_parse_environment();
> +        log_open();
> +
> +        udev = udev_new();
> +        if (udev == NULL)
> +                return EXIT_SUCCESS;
> +
> +        while (1) {
> +                int option;
> +
> +                option = getopt_long(argc, argv, "xh", options, NULL);
> +                if (option == -1)
> +                        break;
> +
> +                switch (option) {
> +                case 'x':
> +                        export = 1;
> +                        break;
> +                case 'h':
> +                        printf("Usage: nvme_id [--export] [--help] <device>\n"
> +                               "  -x,--export    print values as environment keys\n"
> +                               "  -h,--help      print this help text\n\n");
> +                        return EXIT_SUCCESS;
> +                }
> +        }
> +
> +        node = argv[optind];
> +        if (node == NULL) {
> +                log_error("no node specified");
> +                return EXIT_FAILURE;
> +        }
> +
> +        fd = open(node, O_RDONLY|O_NONBLOCK|O_CLOEXEC);
> +        if (fd < 0) {
> +                log_error_errno(errno, "Unable to open '%s': %m", node);
> +                return EXIT_FAILURE;
> +        }
> +
> +        if (nvme_identify(udev, fd, &nvme_id_ctrl, sizeof(struct nvme_id_ctrl)) == 0) {
> +                memcpy(model, nvme_id_ctrl.mn, sizeof(nvme_id_ctrl.mn));
> +                model[sizeof(nvme_id_ctrl.mn)] = '\0';
> +                strstrip(model);
> +                udev_util_encode_string(model, model_enc, sizeof(model_enc));
> +                util_replace_whitespace((char *) nvme_id_ctrl.mn, model, sizeof(nvme_id_ctrl.mn));
> +                util_replace_chars(model, NULL);
> +                util_replace_whitespace((char *) nvme_id_ctrl.sn, serial, sizeof(nvme_id_ctrl.sn));
> +                util_replace_chars(serial, NULL);
> +                util_replace_whitespace((char *) nvme_id_ctrl.fr, revision, sizeof(nvme_id_ctrl.fr));
> +                util_replace_chars(revision, NULL);
> +        } else {
> +                log_debug_errno(errno, "nvme_identify failed for '%s': %m", node);
> +                return EXIT_FAILURE;
> +        }
> +
> +
> +        if (export) {
> +                printf("ID_TYPE=nvme\n");
> +                printf("ID_MODEL=%s\n", model);
> +                printf("ID_MODEL_ENC=%s\n", model_enc);
> +                printf("ID_REVISION=%s\n", revision);
> +                if (serial[0] != '\0') {
> +                        printf("ID_SERIAL=%s_%s\n", model, serial);
> +                        printf("ID_SERIAL_SHORT=%s\n", serial);
> +                } else 
> +                        printf("ID_SERIAL=%s\n", model);
> +        } else {
> +                if (serial[0] != '\0')
> +                        printf("%s_%s\n", model, serial);
> +                else
> +                        printf("%s\n", model);
> +        }
> +
> +        return EXIT_SUCCESS;
> +}
> -- 
> 2.4.0
> 
> 
> 
> 
> _______________________________________________
> systemd-devel mailing list
> systemd-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/systemd-devel


Lennart

-- 
Lennart Poettering, Red Hat


More information about the systemd-devel mailing list