in turbonfs/src/config.cpp [19:252]
bool aznfsc_cfg::parse_config_yaml()
{
#define __CHECK_INT(var, min, max, zeroisvalid) \
do { \
if (((var) == -1) && config[#var]) { \
(var) = config[#var].as<int>(); \
if ((var) < min || (var) > max) { \
if ((zeroisvalid) && ((var) == 0)) { \
break; \
} \
throw YAML::Exception( \
config[#var].Mark(), \
std::string("Invalid value for config "#var": ") + \
std::to_string(var) + \
std::string(" (valid range [") + \
std::to_string(min) + ", " + std::to_string(max) + "])"); \
}\
} \
} while (0);
/*
* Macro to check validity of config var of integer type.
*/
#define _CHECK_INT(var, min, max) __CHECK_INT(var, min, max, false)
/*
* Macro to check validity of config var of integer type with 0 being a
* valid value.
*/
#define _CHECK_INTZ(var, min, max) __CHECK_INT(var, min, max, true)
/*
* Macro to check validity of config var of boolean type.
*/
#define _CHECK_BOOL(var) \
do { \
if (config[#var]) { \
(var) = config[#var].as<bool>(); \
} \
} while (0);
/*
* Macro to check validity of config var of string type.
*/
#define __CHECK_STR(var, is_valid, ignore_empty) \
do { \
if (((var) == nullptr) && config[#var]) { \
/* Empty key is returned as "null" by the yaml parser */ \
if ((ignore_empty) && config[#var].as<std::string>() == "null") { \
break; \
} \
(var) = ::strdup(config[#var].as<std::string>().c_str()); \
if (!is_valid(var)) { \
throw YAML::Exception( \
config[#var].Mark(), \
std::string("Invalid value for config "#var": ") + \
std::string(var)); \
} \
} \
} while (0);
#define _CHECK_STR(var) __CHECK_STR(var, is_valid_##var, false)
#define _CHECK_STR2(var, is_valid) __CHECK_STR(var, is_valid, false)
/*
* Macro to check validity of config var of percentage type.
* var can be set to one of the following values:
* 1) -2 => var is not specified in the config.
* 2) -1 => var is not a valid percentage string. Caller must try other valid
* interpretations.
* 3) var >= 0 && var <= 100 => var is specified as a percentage value.
*/
#define _MAYBE_PERCENT(var) \
do { \
if (!config[#var] || config[#var].as<std::string>() == "null") { \
var = -2; \
break; \
}\
var = get_percent_value(config[#var].as<std::string>()); \
assert((var == -1) || (var >= 0 && var <= 100)); \
} while (0);
if (config_yaml == nullptr) {
return true;
}
AZLogDebug("Parsing config yaml {}", config_yaml);
/*
* We parse the config yaml and set *only* those options which are not yet
* set by cmdline. Thus cmdline options are given higher priority than the
* corresponding option in the config yaml.
*/
try {
YAML::Node config = YAML::LoadFile(config_yaml);
_CHECK_BOOL(debug);
_CHECK_STR(account);
_CHECK_STR(container);
_CHECK_STR(cloud_suffix);
if ((port == -1) && config["port"]) {
port = config["port"].as<int>();
#ifndef ENABLE_NON_AZURE_NFS
if (port != 2048 && port != 2047) {
throw YAML::Exception(
config["port"].Mark(),
std::string("Invalid port number: ") +
std::to_string(port) +
std::string(" (can be 2048 or 2047)"));
}
#endif
}
_CHECK_INT(nconnect, AZNFSCFG_NCONNECT_MIN, AZNFSCFG_NCONNECT_MAX);
_CHECK_INT(timeo, AZNFSCFG_TIMEO_MIN, AZNFSCFG_TIMEO_MAX);
_CHECK_INT(acregmin, AZNFSCFG_ACTIMEO_MIN, AZNFSCFG_ACTIMEO_MAX);
_CHECK_INT(acregmax, AZNFSCFG_ACTIMEO_MIN, AZNFSCFG_ACTIMEO_MAX);
_CHECK_INT(acdirmin, AZNFSCFG_ACTIMEO_MIN, AZNFSCFG_ACTIMEO_MAX);
_CHECK_INT(acdirmax, AZNFSCFG_ACTIMEO_MIN, AZNFSCFG_ACTIMEO_MAX);
_CHECK_INT(actimeo, AZNFSCFG_ACTIMEO_MIN, AZNFSCFG_ACTIMEO_MAX);
_CHECK_STR(lookupcache);
_CHECK_STR(consistency);
_CHECK_BOOL(auth);
/*
* bc_iovec::add_bc() does not accept bytes_chunk larger than wsize.
* Since fuse can send max 1MiB sized writes, we must not allow wsize
* to be set less than 1MiB.
* Since write can get a bytes_chunk allocated by read/readahead, rsize
* must not be allowed to be greater than wsize.
*/
_CHECK_INT(wsize, AZNFSCFG_WSIZE_MIN, AZNFSCFG_WSIZE_MAX);
_CHECK_INT(rsize, AZNFSCFG_RSIZE_MIN, std::min(wsize, AZNFSCFG_RSIZE_MAX));
_CHECK_INT(retrans, AZNFSCFG_RETRANS_MIN, AZNFSCFG_RETRANS_MAX);
_CHECK_INT(readdir_maxcount, AZNFSCFG_READDIR_MIN, AZNFSCFG_READDIR_MAX);
/*
* Allow special value of 0 to disable readahead.
* Mostly useful for testing.
*/
_CHECK_INTZ(readahead_kb, AZNFSCFG_READAHEAD_KB_MIN, AZNFSCFG_READAHEAD_KB_MAX);
_CHECK_INT(fuse_max_background, AZNFSCFG_FUSE_MAX_BG_MIN, AZNFSCFG_FUSE_MAX_BG_MAX);
_CHECK_INT(fuse_max_threads, AZNFSCFG_FUSE_MAX_THR_MIN, AZNFSCFG_FUSE_MAX_THR_MAX);
_CHECK_INT(fuse_max_idle_threads, AZNFSCFG_FUSE_MAX_IDLE_THR_MIN, AZNFSCFG_FUSE_MAX_IDLE_THR_MAX);
_CHECK_STR(xprtsec);
_CHECK_BOOL(oom_kill_disable);
_CHECK_BOOL(cache.attr.user.enable);
_CHECK_BOOL(cache.readdir.kernel.enable);
_CHECK_INT(cache.readdir.user.max_size_mb,
AZNFSCFG_CACHE_MAX_MB_MIN, AZNFSCFG_CACHE_MAX_MB_MAX);
// User readdir cache cannot be turned off.
assert(cache.readdir.user.enable);
_CHECK_BOOL(cache.data.kernel.enable);
// User data cache cannot be turned off.
assert(cache.data.user.enable);
if (cache.data.user.enable) {
/*
* cache.data.user.max_size_mb can be specified as a percentage
* value, in which case it's the percentage of the total RAM size
* else it's an absolute size in MB.
*/
_MAYBE_PERCENT(cache.data.user.max_size_mb);
if (cache.data.user.max_size_mb >= 0) {
AZLogDebug("Using {}% of total RAM {}MB for "
"cache.data.user.max_size_mb",
cache.data.user.max_size_mb,
(get_total_ram() / (1024 * 1024)));
cache.data.user.max_size_mb =
(cache.data.user.max_size_mb / 100.0) *
(get_total_ram() / (1024 * 1024));
if (cache.data.user.max_size_mb < AZNFSCFG_CACHE_MAX_MB_MIN ||
cache.data.user.max_size_mb > AZNFSCFG_CACHE_MAX_MB_MAX) {
throw YAML::Exception(
config["cache.data.user.max_size_mb"].Mark(),
std::string("Invalid value for config cache.data.user.max_size_mb: ") +
config["cache.data.user.max_size_mb"].as<std::string>().c_str() +
std::string(", resultant value ") +
std::to_string(cache.data.user.max_size_mb) +
std::string(" is not in valid range [") +
std::to_string(AZNFSCFG_CACHE_MAX_MB_MIN) +
std::string(", ") +
std::to_string(AZNFSCFG_CACHE_MAX_MB_MAX) +
std::string("]"));
}
} else if (cache.data.user.max_size_mb == -1) {
/*
* Not expressed as a percentage, try absolute MB.
*/
_CHECK_INT(cache.data.user.max_size_mb,
AZNFSCFG_CACHE_MAX_MB_MIN, AZNFSCFG_CACHE_MAX_MB_MAX);
}
} else {
cache.data.user.max_size_mb = 0;
}
_CHECK_BOOL(filecache.enable);
if (filecache.enable) {
_CHECK_STR2(filecache.cachedir, is_valid_cachedir);
_CHECK_INT(filecache.max_size_gb, AZNFSCFG_FILECACHE_MAX_GB_MIN, AZNFSCFG_FILECACHE_MAX_GB_MAX);
} else {
filecache.max_size_gb = 0;
}
/*
* Config affecting misc system behaviour.
*/
_CHECK_BOOL(sys.force_stable_writes);
_CHECK_BOOL(sys.resolve_before_reconnect);
_CHECK_BOOL(sys.nodrc.remove_noent_as_success);
_CHECK_BOOL(sys.nodrc.create_exist_as_success);
_CHECK_BOOL(sys.nodrc.rename_noent_as_success);
} catch (const YAML::BadFile& e) {
AZLogError("Error loading config file {}: {}", config_yaml, e.what());
return false;
} catch (const YAML::Exception& e) {
AZLogError("Error parsing config file {}: {}", config_yaml, e.what());
return false;
} catch (...) {
AZLogError("Unknown error parsing config file {}", config_yaml);
return false;
}
return true;
}