L_FILE,
L_NAME,
L_LAZYSBCNTR,
+ L_CONCURRENCY,
L_MAX_OPTS,
};
[L_FILE] = "file",
[L_NAME] = "name",
[L_LAZYSBCNTR] = "lazy-count",
+ [L_CONCURRENCY] = "concurrency",
[L_MAX_OPTS] = NULL,
},
.subopt_params = {
.defaultval = 1,
},
{ .index = L_SIZE,
- .conflicts = { { NULL, LAST_CONFLICT } },
+ .conflicts = { { &lopts, L_CONCURRENCY },
+ { NULL, LAST_CONFLICT } },
.convert = true,
.minval = 2 * 1024 * 1024LL, /* XXX: XFS_MIN_LOG_BYTES */
.maxval = XFS_MAX_LOG_BYTES,
.conflicts = { { &lopts, L_AGNUM },
{ &lopts, L_NAME },
{ &lopts, L_INTERNAL },
+ { &lopts, L_CONCURRENCY },
{ NULL, LAST_CONFLICT } },
.defaultval = SUBOPT_NEEDS_VAL,
},
},
{ .index = L_FILE,
.conflicts = { { &lopts, L_INTERNAL },
+ { &lopts, L_CONCURRENCY },
{ NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = 1,
.maxval = 1,
.defaultval = 1,
},
+ { .index = L_CONCURRENCY,
+ .conflicts = { { &lopts, L_SIZE },
+ { &lopts, L_FILE },
+ { &lopts, L_DEV },
+ { NULL, LAST_CONFLICT } },
+ .minval = 0,
+ .maxval = INT_MAX,
+ .defaultval = 1,
+ },
},
};
int is_supported;
int proto_slashes_are_spaces;
int data_concurrency;
+ int log_concurrency;
/* parameters where 0 is not a valid value */
int64_t agcount;
projid32bit=0|1,sparse=0|1,nrext64=0|1]\n\
/* no discard */ [-K]\n\
/* log subvol */ [-l agnum=n,internal,size=num,logdev=xxx,version=n\n\
- sunit=value|su=num,sectsize=num,lazy-count=0|1]\n\
+ sunit=value|su=num,sectsize=num,lazy-count=0|1,\n\
+ concurrency=num]\n\
/* label */ [-L label (maximum 12 characters)]\n\
/* naming */ [-n size=num,version=2|ci,ftype=0|1]\n\
/* no-op info only */ [-N]\n\
return 0;
}
+static void
+set_log_concurrency(
+ struct opt_params *opts,
+ int subopt,
+ const char *value,
+ struct cli_params *cli)
+{
+ long long optnum;
+
+ /*
+ * "nr_cpus" or 1 means set the concurrency level to the CPU count. If
+ * this cannot be determined, fall back to the default computation.
+ */
+ if (!strcmp(value, "nr_cpus"))
+ optnum = 1;
+ else
+ optnum = getnum(value, opts, subopt);
+
+ if (optnum == 1)
+ cli->log_concurrency = nr_cpus();
+ else
+ cli->log_concurrency = optnum;
+}
+
static int
log_opts_parser(
struct opt_params *opts,
case L_LAZYSBCNTR:
cli->sb_feat.lazy_sb_counters = getnum(value, opts, subopt);
break;
+ case L_CONCURRENCY:
+ set_log_concurrency(opts, subopt, value, cli);
+ break;
default:
return -EINVAL;
}
cfg->logblocks = min(cfg->logblocks, *max_logblocks);
}
+static uint64_t
+calc_concurrency_logblocks(
+ struct mkfs_params *cfg,
+ struct cli_params *cli,
+ struct libxfs_init *xi,
+ unsigned int max_tx_bytes)
+{
+ uint64_t log_bytes;
+ uint64_t logblocks = cfg->logblocks;
+ unsigned int new_logblocks;
+
+ if (cli->log_concurrency < 0) {
+ if (!ddev_is_solidstate(xi))
+ goto out;
+
+ cli->log_concurrency = nr_cpus();
+ }
+ if (cli->log_concurrency == 0)
+ goto out;
+
+ /*
+ * If this filesystem is smaller than a gigabyte, there's little to be
+ * gained from making the log larger.
+ */
+ if (cfg->dblocks < GIGABYTES(1, cfg->blocklog))
+ goto out;
+
+ /*
+ * Create a log that is large enough to handle simultaneous maximally
+ * sized transactions at the concurrency level specified by the user
+ * without blocking for space. Increase the figure by 50% so that
+ * background threads can also run.
+ */
+ log_bytes = max_tx_bytes * 3 * cli->log_concurrency / 2;
+ new_logblocks = min(XFS_MAX_LOG_BYTES >> cfg->blocklog,
+ log_bytes >> cfg->blocklog);
+
+ logblocks = max(logblocks, new_logblocks);
+out:
+ return logblocks;
+}
+
static void
calculate_log_size(
struct mkfs_params *cfg,
struct xfs_sb *sbp = &mp->m_sb;
int min_logblocks; /* absolute minimum */
int max_logblocks; /* absolute max for this AG */
+ unsigned int max_tx_bytes = 0;
struct xfs_mount mount;
struct libxfs_init dummy_init = { };
mount.m_sb = *sbp;
libxfs_mount(&mount, &mp->m_sb, &dummy_init, 0);
min_logblocks = libxfs_log_calc_minimum_size(&mount);
+ if (cli->log_concurrency != 0) {
+ struct xfs_trans_res res;
+
+ libxfs_log_get_max_trans_res(&mount, &res);
+ max_tx_bytes = res.tr_logres * res.tr_logcount;
+ }
libxfs_umount(&mount);
ASSERT(min_logblocks);
cfg->logblocks = (cfg->dblocks << cfg->blocklog) / 2048;
cfg->logblocks = cfg->logblocks >> cfg->blocklog;
+ if (cli->log_concurrency != 0)
+ cfg->logblocks = calc_concurrency_logblocks(cfg, cli,
+ xi, max_tx_bytes);
+
/* But don't go below a reasonable size */
cfg->logblocks = max(cfg->logblocks,
XFS_MIN_REALISTIC_LOG_BLOCKS(cfg->blocklog));
.loginternal = 1,
.is_supported = 1,
.data_concurrency = -1, /* auto detect non-mechanical storage */
+ .log_concurrency = -1, /* auto detect non-mechanical ddev */
};
struct mkfs_params cfg = {};