|
@@ -1202,60 +1202,117 @@ static int hdev_get_max_hw_transfer(int fd, struct stat *st)
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
-static int hdev_get_max_segments(int fd, struct stat *st)
|
|
|
-{
|
|
|
+/*
|
|
|
+ * Get a sysfs attribute value as character string.
|
|
|
+ */
|
|
|
#ifdef CONFIG_LINUX
|
|
|
- char buf[32];
|
|
|
- const char *end;
|
|
|
- char *sysfspath = NULL;
|
|
|
+static int get_sysfs_str_val(struct stat *st, const char *attribute,
|
|
|
+ char **val) {
|
|
|
+ g_autofree char *sysfspath = NULL;
|
|
|
int ret;
|
|
|
- int sysfd = -1;
|
|
|
- long max_segments;
|
|
|
+ size_t len;
|
|
|
|
|
|
- if (S_ISCHR(st->st_mode)) {
|
|
|
- if (ioctl(fd, SG_GET_SG_TABLESIZE, &ret) == 0) {
|
|
|
- return ret;
|
|
|
- }
|
|
|
+ if (!S_ISBLK(st->st_mode)) {
|
|
|
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);
|
|
|
+ ret = g_file_get_contents(sysfspath, val, &len, NULL);
|
|
|
+ if (ret == -1) {
|
|
|
+ return -ENOENT;
|
|
|
}
|
|
|
|
|
|
- sysfspath = g_strdup_printf("/sys/dev/block/%u:%u/queue/max_segments",
|
|
|
- major(st->st_rdev), minor(st->st_rdev));
|
|
|
- sysfd = open(sysfspath, O_RDONLY);
|
|
|
- if (sysfd == -1) {
|
|
|
- ret = -errno;
|
|
|
- goto out;
|
|
|
+ /* The file is ended with '\n' */
|
|
|
+ char *p;
|
|
|
+ p = *val;
|
|
|
+ if (*(p + len - 1) == '\n') {
|
|
|
+ *(p + len - 1) = '\0';
|
|
|
}
|
|
|
- ret = RETRY_ON_EINTR(read(sysfd, buf, sizeof(buf) - 1));
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+static int get_sysfs_zoned_model(struct stat *st, BlockZoneModel *zoned)
|
|
|
+{
|
|
|
+ g_autofree char *val = NULL;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = get_sysfs_str_val(st, "zoned", &val);
|
|
|
if (ret < 0) {
|
|
|
- ret = -errno;
|
|
|
- goto out;
|
|
|
- } else if (ret == 0) {
|
|
|
- ret = -EIO;
|
|
|
- goto out;
|
|
|
+ return ret;
|
|
|
}
|
|
|
- buf[ret] = 0;
|
|
|
- /* The file is ended with '\n', pass 'end' to accept that. */
|
|
|
- ret = qemu_strtol(buf, &end, 10, &max_segments);
|
|
|
- if (ret == 0 && end && *end == '\n') {
|
|
|
- ret = max_segments;
|
|
|
+
|
|
|
+ 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;
|
|
|
+}
|
|
|
|
|
|
-out:
|
|
|
- if (sysfd != -1) {
|
|
|
- close(sysfd);
|
|
|
+/*
|
|
|
+ * Get a sysfs attribute value as a long integer.
|
|
|
+ */
|
|
|
+#ifdef CONFIG_LINUX
|
|
|
+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;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* The file is ended with '\n', pass 'end' to accept that. */
|
|
|
+ ret = qemu_strtol(str, &end, 10, &val);
|
|
|
+ if (ret == 0 && end && *end == '\0') {
|
|
|
+ ret = val;
|
|
|
}
|
|
|
- g_free(sysfspath);
|
|
|
return ret;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+static int hdev_get_max_segments(int fd, struct stat *st)
|
|
|
+{
|
|
|
+#ifdef CONFIG_LINUX
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (S_ISCHR(st->st_mode)) {
|
|
|
+ if (ioctl(fd, SG_GET_SG_TABLESIZE, &ret) == 0) {
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ return -ENOTSUP;
|
|
|
+ }
|
|
|
+ return get_sysfs_long_val(st, "max_segments");
|
|
|
#else
|
|
|
return -ENOTSUP;
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
+static void raw_refresh_zoned_limits(BlockDriverState *bs, struct stat *st,
|
|
|
+ Error **errp)
|
|
|
+{
|
|
|
+ BlockZoneModel zoned;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ bs->bl.zoned = BLK_Z_NONE;
|
|
|
+
|
|
|
+ ret = get_sysfs_zoned_model(st, &zoned);
|
|
|
+ if (ret < 0 || zoned == BLK_Z_NONE) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ bs->bl.zoned = zoned;
|
|
|
+}
|
|
|
+
|
|
|
static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
|
|
|
{
|
|
|
BDRVRawState *s = bs->opaque;
|
|
@@ -1297,6 +1354,8 @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
|
|
|
bs->bl.max_hw_iov = ret;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ raw_refresh_zoned_limits(bs, &st, errp);
|
|
|
}
|
|
|
|
|
|
static int check_for_dasd(int fd)
|