+static int zone_split_ddir(struct thread_options *o, enum fio_ddir ddir,
+ char *str, bool absolute)
+{
+ unsigned int i, perc, perc_missing, sperc, sperc_missing;
+ struct split split;
+
+ memset(&split, 0, sizeof(split));
+
+ if (split_parse_ddir(o, &split, str, absolute, ZONESPLIT_MAX))
+ return 1;
+ if (!split.nr)
+ return 0;
+
+ o->zone_split[ddir] = malloc(split.nr * sizeof(struct zone_split));
+ o->zone_split_nr[ddir] = split.nr;
+ for (i = 0; i < split.nr; i++) {
+ o->zone_split[ddir][i].access_perc = split.val1[i];
+ if (absolute)
+ o->zone_split[ddir][i].size = split.val2[i];
+ else
+ o->zone_split[ddir][i].size_perc = split.val2[i];
+ }
+
+ /*
+ * Now check if the percentages add up, and how much is missing
+ */
+ perc = perc_missing = 0;
+ sperc = sperc_missing = 0;
+ for (i = 0; i < o->zone_split_nr[ddir]; i++) {
+ struct zone_split *zsp = &o->zone_split[ddir][i];
+
+ if (zsp->access_perc == (uint8_t) -1U)
+ perc_missing++;
+ else
+ perc += zsp->access_perc;
+
+ if (!absolute) {
+ if (zsp->size_perc == (uint8_t) -1U)
+ sperc_missing++;
+ else
+ sperc += zsp->size_perc;
+ }
+ }
+
+ if (perc > 100 || sperc > 100) {
+ log_err("fio: zone_split percentages add to more than 100%%\n");
+ free(o->zone_split[ddir]);
+ o->zone_split[ddir] = NULL;
+ return 1;
+ }
+ if (perc < 100) {
+ log_err("fio: access percentage don't add up to 100 for zoned "
+ "random distribution (got=%u)\n", perc);
+ free(o->zone_split[ddir]);
+ o->zone_split[ddir] = NULL;
+ return 1;
+ }
+
+ /*
+ * If values didn't have a percentage set, divide the remains between
+ * them.
+ */
+ if (perc_missing) {
+ if (perc_missing == 1 && o->zone_split_nr[ddir] == 1)
+ perc = 100;
+ for (i = 0; i < o->zone_split_nr[ddir]; i++) {
+ struct zone_split *zsp = &o->zone_split[ddir][i];
+
+ if (zsp->access_perc == (uint8_t) -1U)
+ zsp->access_perc = (100 - perc) / perc_missing;
+ }
+ }
+ if (sperc_missing) {
+ if (sperc_missing == 1 && o->zone_split_nr[ddir] == 1)
+ sperc = 100;
+ for (i = 0; i < o->zone_split_nr[ddir]; i++) {
+ struct zone_split *zsp = &o->zone_split[ddir][i];
+
+ if (zsp->size_perc == (uint8_t) -1U)
+ zsp->size_perc = (100 - sperc) / sperc_missing;
+ }
+ }
+
+ return 0;
+}
+
+static int parse_zoned_distribution(struct thread_data *td, const char *input,
+ bool absolute)
+{
+ const char *pre = absolute ? "zoned_abs:" : "zoned:";
+ char *str, *p;
+ int i, ret = 0;
+
+ p = str = strdup(input);
+
+ strip_blank_front(&str);
+ strip_blank_end(str);
+
+ /* We expect it to start like that, bail if not */
+ if (strncmp(str, pre, strlen(pre))) {
+ log_err("fio: mismatch in zoned input <%s>\n", str);
+ free(p);
+ return 1;
+ }
+ str += strlen(pre);
+
+ ret = str_split_parse(td, str, zone_split_ddir, absolute);
+
+ free(p);
+
+ for (i = 0; i < DDIR_RWDIR_CNT; i++) {
+ int j;
+
+ dprint(FD_PARSE, "zone ddir %d (nr=%u): \n", i, td->o.zone_split_nr[i]);
+
+ for (j = 0; j < td->o.zone_split_nr[i]; j++) {
+ struct zone_split *zsp = &td->o.zone_split[i][j];
+
+ if (absolute) {
+ dprint(FD_PARSE, "\t%d: %u/%llu\n", j,
+ zsp->access_perc,
+ (unsigned long long) zsp->size);
+ } else {
+ dprint(FD_PARSE, "\t%d: %u/%u\n", j,
+ zsp->access_perc,
+ zsp->size_perc);
+ }
+ }
+ }
+
+ if (parse_dryrun()) {
+ for (i = 0; i < DDIR_RWDIR_CNT; i++) {
+ free(td->o.zone_split[i]);
+ td->o.zone_split[i] = NULL;
+ td->o.zone_split_nr[i] = 0;
+ }
+
+ return ret;
+ }
+
+ if (ret) {
+ for (i = 0; i < DDIR_RWDIR_CNT; i++)
+ td->o.zone_split_nr[i] = 0;
+ }
+
+ return ret;
+}
+