diff mbox series

[v6,3/8] file-posix: introduce get_sysfs_str_val for device zoned model

Message ID 20220805075751.77499-4-faithilikerun@gmail.com (mailing list archive)
State New, archived
Headers show
Series Add support for zoned device | expand

Commit Message

Sam Li Aug. 5, 2022, 7:57 a.m. UTC
Use sysfs attribute files to get the string value of device
zoned model. Then get_sysfs_zoned_model can convert it to
BlockZoneModel type in QEMU.

Signed-off-by: Sam Li <faithilikerun@gmail.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
---
 block/file-posix.c               | 70 ++++++++++++++++++++++++++++++++
 include/block/block_int-common.h |  3 ++
 2 files changed, 73 insertions(+)

Comments

Stefan Hajnoczi Aug. 6, 2022, 12:50 p.m. UTC | #1
On Fri, Aug 05, 2022 at 03:57:46PM +0800, Sam Li wrote:
> Use sysfs attribute files to get the string value of device
> zoned model. Then get_sysfs_zoned_model can convert it to
> BlockZoneModel type in QEMU.
> 
> Signed-off-by: Sam Li <faithilikerun@gmail.com>
> Reviewed-by: Hannes Reinecke <hare@suse.de>
> ---
>  block/file-posix.c               | 70 ++++++++++++++++++++++++++++++++
>  include/block/block_int-common.h |  3 ++
>  2 files changed, 73 insertions(+)
> 
> diff --git a/block/file-posix.c b/block/file-posix.c
> index a40eab64a2..4785203eea 100644
> --- a/block/file-posix.c
> +++ b/block/file-posix.c
> @@ -1264,6 +1264,68 @@ out:
>  #endif
>  }
>  
> +/*
> + * Convert the zoned attribute file in sysfs to internal value.
> + */
> +static int get_sysfs_str_val(int fd, struct stat *st,
> +                              const char *attribute,
> +                              char **val) {

The fd argument is unused and can be dropped.

> +#ifdef CONFIG_LINUX
> +    char *buf = NULL;
> +    g_autofree char *sysfspath = NULL;
> +    int ret;
> +    size_t len;
> +
> +    if (!S_ISBLK(st->st_mode)) {
> +        return -ENOTSUP;
> +    }
> +
> +    sysfspath = g_strdup_printf("/sys/dev/block/%u:%u/queue/%s",
> +                                major(st->st_rdev), minor(st->st_rdev),
> +                                attribute);
> +    ret = g_file_get_contents(sysfspath, &buf, &len, NULL);
> +    if (ret == -1) {
> +        ret = -errno;

g_file_get_contents() does not set errno. You can either pass in a
GError and report the message string by converting it into a QEMU Error
object (grep for g_file_get_contents() to see example), or you can
return a fixed error code like -ENOENT.

> +        return ret;
> +    }
> +
> +    /* The file is ended with '\n' */
> +    if (buf[len - 1] == '\n') {
> +        buf[len - 1] = '\0';
> +    }
> +
> +    if (!strncpy(*val, buf, len)) {
> +        ret = -errno;
> +        return ret;
> +    }
> +    g_free(buf);

buf is not necessary. val can be passed directly to g_file_get_contents().

> +    return 0;
> +#else
> +    return -ENOTSUP;
> +#endif
> +}

Now get_sysfs_long_val() can be written using get_sysfs_str_val():

  static long get_sysfs_long_val(struct stat *st, const char *attribute)
  {
      g_autofree char *str = NULL;
      const char *end;
      long val;
      int ret;

      ret = get_sysfs_str_val(st, attribute, &str);
      if (ret < 0) {
          return ret;
      }

      ret = qemu_strtol(str, &end, 10, &val);
      if (ret == 0 && end && *end == '\0') {
          ret = val;
      }
      return ret;
  }

The get_sysfs_long_val() patch can be moved after the
get_sysfs_str_val() patch.

> +
> +static int get_sysfs_zoned_model(int fd, struct stat *st,
> +                                 BlockZoneModel *zoned) {
> +    g_autofree char *val = NULL;
> +    val = g_malloc(32);
> +    get_sysfs_str_val(fd, st, "zoned", &val);

Once get_sysfs_str_val() passes val through to g_get_file_contents() the
caller will no longer have to g_malloc() val themselves.
Sam Li Aug. 8, 2022, 1:59 p.m. UTC | #2
Stefan Hajnoczi <stefanha@redhat.com> 于2022年8月8日周一 21:52写道:
>
> On Fri, Aug 05, 2022 at 03:57:46PM +0800, Sam Li wrote:
> > Use sysfs attribute files to get the string value of device
> > zoned model. Then get_sysfs_zoned_model can convert it to
> > BlockZoneModel type in QEMU.
> >
> > Signed-off-by: Sam Li <faithilikerun@gmail.com>
> > Reviewed-by: Hannes Reinecke <hare@suse.de>
> > ---
> >  block/file-posix.c               | 70 ++++++++++++++++++++++++++++++++
> >  include/block/block_int-common.h |  3 ++
> >  2 files changed, 73 insertions(+)
> >
> > diff --git a/block/file-posix.c b/block/file-posix.c
> > index a40eab64a2..4785203eea 100644
> > --- a/block/file-posix.c
> > +++ b/block/file-posix.c
> > @@ -1264,6 +1264,68 @@ out:
> >  #endif
> >  }
> >
> > +/*
> > + * Convert the zoned attribute file in sysfs to internal value.
> > + */
> > +static int get_sysfs_str_val(int fd, struct stat *st,
> > +                              const char *attribute,
> > +                              char **val) {
>
> The fd argument is unused and can be dropped.
>
> > +#ifdef CONFIG_LINUX
> > +    char *buf = NULL;
> > +    g_autofree char *sysfspath = NULL;
> > +    int ret;
> > +    size_t len;
> > +
> > +    if (!S_ISBLK(st->st_mode)) {
> > +        return -ENOTSUP;
> > +    }
> > +
> > +    sysfspath = g_strdup_printf("/sys/dev/block/%u:%u/queue/%s",
> > +                                major(st->st_rdev), minor(st->st_rdev),
> > +                                attribute);
> > +    ret = g_file_get_contents(sysfspath, &buf, &len, NULL);
> > +    if (ret == -1) {
> > +        ret = -errno;
>
> g_file_get_contents() does not set errno. You can either pass in a
> GError and report the message string by converting it into a QEMU Error
> object (grep for g_file_get_contents() to see example), or you can
> return a fixed error code like -ENOENT.
>
> > +        return ret;
> > +    }
> > +
> > +    /* The file is ended with '\n' */
> > +    if (buf[len - 1] == '\n') {
> > +        buf[len - 1] = '\0';
> > +    }
> > +
> > +    if (!strncpy(*val, buf, len)) {
> > +        ret = -errno;
> > +        return ret;
> > +    }
> > +    g_free(buf);
>
> buf is not necessary. val can be passed directly to g_file_get_contents().
>
> > +    return 0;
> > +#else
> > +    return -ENOTSUP;
> > +#endif
> > +}
>
> Now get_sysfs_long_val() can be written using get_sysfs_str_val():
>
>   static long get_sysfs_long_val(struct stat *st, const char *attribute)
>   {
>       g_autofree char *str = NULL;
>       const char *end;
>       long val;
>       int ret;
>
>       ret = get_sysfs_str_val(st, attribute, &str);
>       if (ret < 0) {
>           return ret;
>       }
>
>       ret = qemu_strtol(str, &end, 10, &val);
>       if (ret == 0 && end && *end == '\0') {
>           ret = val;
>       }
>       return ret;
>   }
>
> The get_sysfs_long_val() patch can be moved after the
> get_sysfs_str_val() patch.

Cool! Will change it.

> > +
> > +static int get_sysfs_zoned_model(int fd, struct stat *st,
> > +                                 BlockZoneModel *zoned) {
> > +    g_autofree char *val = NULL;
> > +    val = g_malloc(32);
> > +    get_sysfs_str_val(fd, st, "zoned", &val);
>
> Once get_sysfs_str_val() passes val through to g_get_file_contents() the
> caller will no longer have to g_malloc() val themselves.
diff mbox series

Patch

diff --git a/block/file-posix.c b/block/file-posix.c
index a40eab64a2..4785203eea 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -1264,6 +1264,68 @@  out:
 #endif
 }
 
+/*
+ * Convert the zoned attribute file in sysfs to internal value.
+ */
+static int get_sysfs_str_val(int fd, struct stat *st,
+                              const char *attribute,
+                              char **val) {
+#ifdef CONFIG_LINUX
+    char *buf = NULL;
+    g_autofree char *sysfspath = NULL;
+    int ret;
+    size_t len;
+
+    if (!S_ISBLK(st->st_mode)) {
+        return -ENOTSUP;
+    }
+
+    sysfspath = g_strdup_printf("/sys/dev/block/%u:%u/queue/%s",
+                                major(st->st_rdev), minor(st->st_rdev),
+                                attribute);
+    ret = g_file_get_contents(sysfspath, &buf, &len, NULL);
+    if (ret == -1) {
+        ret = -errno;
+        return ret;
+    }
+
+    /* The file is ended with '\n' */
+    if (buf[len - 1] == '\n') {
+        buf[len - 1] = '\0';
+    }
+
+    if (!strncpy(*val, buf, len)) {
+        ret = -errno;
+        return ret;
+    }
+    g_free(buf);
+    return 0;
+#else
+    return -ENOTSUP;
+#endif
+}
+
+static int get_sysfs_zoned_model(int fd, struct stat *st,
+                                 BlockZoneModel *zoned) {
+    g_autofree char *val = NULL;
+    val = g_malloc(32);
+    get_sysfs_str_val(fd, st, "zoned", &val);
+    if (!val) {
+        return -ENOTSUP;
+    }
+
+    if (strcmp(val, "host-managed") == 0) {
+        *zoned = BLK_Z_HM;
+    } else if (strcmp(val, "host-aware") == 0) {
+        *zoned = BLK_Z_HA;
+    } else if (strcmp(val, "none") == 0) {
+        *zoned = BLK_Z_NONE;
+    } else {
+        return -ENOTSUP;
+    }
+    return 0;
+}
+
 static int hdev_get_max_segments(int fd, struct stat *st) {
     int ret;
     if (S_ISCHR(st->st_mode)) {
@@ -1279,6 +1341,8 @@  static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
 {
     BDRVRawState *s = bs->opaque;
     struct stat st;
+    int ret;
+    BlockZoneModel zoned;
 
     s->needs_alignment = raw_needs_alignment(bs);
     raw_probe_alignment(bs, s->fd, errp);
@@ -1316,6 +1380,12 @@  static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
             bs->bl.max_hw_iov = ret;
         }
     }
+
+    ret = get_sysfs_zoned_model(s->fd, &st, &zoned);
+    if (ret < 0) {
+        zoned = BLK_Z_NONE;
+    }
+    bs->bl.zoned = zoned;
 }
 
 static int check_for_dasd(int fd)
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
index 8947abab76..7f7863cc9e 100644
--- a/include/block/block_int-common.h
+++ b/include/block/block_int-common.h
@@ -825,6 +825,9 @@  typedef struct BlockLimits {
 
     /* maximum number of iovec elements */
     int max_iov;
+
+    /* device zone model */
+    BlockZoneModel zoned;
 } BlockLimits;
 
 typedef struct BdrvOpBlocker BdrvOpBlocker;