diff mbox series

[RFC,v5,04/11] file-posix: introduce get_sysfs_str_val for device zoned model

Message ID 20220801013248.10468-1-faithilikerun@gmail.com
State New
Headers show
Series Add support for zoned device | expand

Commit Message

Sam Li Aug. 1, 2022, 1:32 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>
---
 block/file-posix.c               | 86 ++++++++++++++++++++++++++++++++
 include/block/block_int-common.h |  3 ++
 2 files changed, 89 insertions(+)

Comments

Stefan Hajnoczi Aug. 1, 2022, 2:42 p.m. UTC | #1
On Sun, 31 Jul 2022 at 21:34, Sam Li <faithilikerun@gmail.com> 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>
> ---
>  block/file-posix.c               | 86 ++++++++++++++++++++++++++++++++
>  include/block/block_int-common.h |  3 ++
>  2 files changed, 89 insertions(+)
>
> diff --git a/block/file-posix.c b/block/file-posix.c
> index bcf898f0cb..0d8b4acdc7 100644
> --- a/block/file-posix.c
> +++ b/block/file-posix.c
> @@ -1271,6 +1271,85 @@ 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[32];
> +    char *sysfspath = NULL;

This can be g_autofree and then the explicit g_free(sysfspath) call is
no longer necessary.

> +    int ret, offset;
> +    int sysfd = -1;
> +
> +    if (S_ISCHR(st->st_mode)) {
> +        if (ioctl(fd, SG_GET_SG_TABLESIZE, &ret) == 0) {
> +            return ret;
> +        }
> +        return -ENOTSUP;
> +    }

This is for max_segments only. See my comment on the previous patch.

> +
> +    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);

The code that follows can be replaced by a call to g_file_get_contents():
https://docs.gtk.org/glib/func.file_get_contents.html

Then the caller doesn't need to pre-allocate a 32-byte buffer. Instead
this function returns a string on the heap. The caller can free it
with g_free().

> +    sysfd = open(sysfspath, O_RDONLY);
> +    if (sysfd == -1) {
> +        ret = -errno;
> +        goto out;
> +    }
> +    offset = 0;
> +    do {
> +        ret = read(sysfd, buf + offset, sizeof(buf) - 1 + offset);
> +        if (ret > 0) {
> +            offset += ret;
> +        }
> +    } while (ret == -1);

I think this should be:

  } while (ret == -1 && errno == EINTR);

  if (ret < 0) {
      ret = -errno;
      goto out;
  }

Otherwise there is an infinite loop when an unrecoverable error occurs.

> +    /* The file is ended with '\n' */
> +    if (buf[ret - 1] == '\n') {
> +        buf[ret - 1] = '\0';
> +    }
> +
> +    if (!strncpy(*val, buf, ret)) {
> +        goto out;
> +    }
> +
> +out:
> +    if (sysfd != -1) {
> +        close(sysfd);
> +    }
> +    g_free(sysfspath);
> +    return ret;
> +#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) {
>      return get_sysfs_long_val(fd, st, "max_segments");
>  }
> @@ -1279,6 +1358,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 +1397,11 @@ 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;

QEMU coding style always uses {}:

  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;
> --
> 2.37.1
>
>
diff mbox series

Patch

diff --git a/block/file-posix.c b/block/file-posix.c
index bcf898f0cb..0d8b4acdc7 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -1271,6 +1271,85 @@  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[32];
+    char *sysfspath = NULL;
+    int ret, offset;
+    int sysfd = -1;
+
+    if (S_ISCHR(st->st_mode)) {
+        if (ioctl(fd, SG_GET_SG_TABLESIZE, &ret) == 0) {
+            return ret;
+        }
+        return -ENOTSUP;
+    }
+
+    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);
+    sysfd = open(sysfspath, O_RDONLY);
+    if (sysfd == -1) {
+        ret = -errno;
+        goto out;
+    }
+    offset = 0;
+    do {
+        ret = read(sysfd, buf + offset, sizeof(buf) - 1 + offset);
+        if (ret > 0) {
+            offset += ret;
+        }
+    } while (ret == -1);
+    /* The file is ended with '\n' */
+    if (buf[ret - 1] == '\n') {
+        buf[ret - 1] = '\0';
+    }
+
+    if (!strncpy(*val, buf, ret)) {
+        goto out;
+    }
+
+out:
+    if (sysfd != -1) {
+        close(sysfd);
+    }
+    g_free(sysfspath);
+    return ret;
+#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) {
     return get_sysfs_long_val(fd, st, "max_segments");
 }
@@ -1279,6 +1358,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 +1397,11 @@  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;