std::deque<std::string> *parse_errors, int flags)
{
Mutex::Locker l(lock);
+ if (internal_safe_to_start_threads)
+ return -ENOSYS;
if (!conf_files) {
const char *c = getenv("CEPH_CONF");
if (c) {
parse_env()
{
Mutex::Locker l(lock);
+ if (internal_safe_to_start_threads)
+ return;
if (getenv("CEPH_KEYRING"))
keyring = getenv("CEPH_KEYRING");
}
-void md_config_t::
+int md_config_t::
parse_argv(std::vector<const char*>& args)
{
Mutex::Locker l(lock);
+ if (internal_safe_to_start_threads) {
+ return -ENOSYS;
+ }
+
// In this function, don't change any parts of the configuration directly.
// Instead, use set_val to set them. This will allow us to send the proper
// observer notifications later.
}
}
}
+ return 0;
}
int md_config_t::parse_injectargs(std::vector<const char*>& args,
for (int i = 0; i < NUM_CONFIG_OPTIONS; ++i) {
config_option *opt = &config_optionsp[i];
- if (strcmp(opt->name, k.c_str()) == 0)
+ if (strcmp(opt->name, k.c_str()) == 0) {
+ if (internal_safe_to_start_threads) {
+ // If threads have been started...
+ if ((opt->type == OPT_STR) || (opt->type == OPT_ADDR)) {
+ // And this is NOT an integer valued variable....
+ if (observers.find(opt->name) == observers.end()) {
+ // And there is no observer to safely change it...
+ // You lose.
+ return -ENOSYS;
+ }
+ }
+ }
return set_val_impl(v.c_str(), opt);
+ }
}
// couldn't find a configuration option with key 'key'
void parse_env();
// Absorb config settings from argv
- void parse_argv(std::vector<const char*>& args);
+ int parse_argv(std::vector<const char*>& args);
// Expand all metavariables. Make any pending observer callbacks.
void apply_changes(std::ostringstream *oss);
*/
int ceph_conf_read_file(struct ceph_mount_info *cmount, const char *path_list);
-void ceph_conf_parse_argv(struct ceph_mount_info *cmount, int argc, const char **argv);
+int ceph_conf_parse_argv(struct ceph_mount_info *cmount, int argc, const char **argv);
/* Sets a configuration value from a string.
* Returns 0 on success, error code otherwise. */
int rados_conf_read_file(rados_t cluster, const char *path);
/* Parse argv */
-void rados_conf_parse_argv(rados_t cluster, int argc, const char **argv);
+int rados_conf_parse_argv(rados_t cluster, int argc, const char **argv);
/* Sets a configuration value from a string.
* Returns 0 on success, error code otherwise. */
int connect();
void shutdown();
int conf_read_file(const char * const path) const;
- void conf_parse_argv(int argc, const char ** argv) const;
+ int conf_parse_argv(int argc, const char ** argv) const;
int conf_set(const char *option, const char *value);
int conf_get(const char *option, std::string &val);
return 0;
}
- void conf_parse_argv(int argc, const char **argv)
+ int conf_parse_argv(int argc, const char **argv)
{
+ int ret;
vector<const char*> args;
argv_to_vec(argc, argv, args);
- cct->_conf->parse_argv(args);
+ ret = cct->_conf->parse_argv(args);
+ if (ret)
+ return ret;
cct->_conf->apply_changes(NULL);
+ return 0;
}
int conf_set(const char *option, const char *value)
return cmount->conf_read_file(path);
}
-extern "C" void ceph_conf_parse_argv(struct ceph_mount_info *cmount, int argc,
+extern "C" int ceph_conf_parse_argv(struct ceph_mount_info *cmount, int argc,
const char **argv)
{
- cmount->conf_parse_argv(argc, argv);
+ return cmount->conf_parse_argv(argc, argv);
}
extern "C" int ceph_conf_set(struct ceph_mount_info *cmount, const char *option,
return rados_conf_read_file((rados_t)client, path);
}
-void librados::Rados::
+int librados::Rados::
conf_parse_argv(int argc, const char ** argv) const
{
- rados_conf_parse_argv((rados_t)client, argc, argv);
+ return rados_conf_parse_argv((rados_t)client, argc, argv);
}
int librados::Rados::
return 0;
}
-extern "C" void rados_conf_parse_argv(rados_t cluster, int argc, const char **argv)
+extern "C" int rados_conf_parse_argv(rados_t cluster, int argc, const char **argv)
{
librados::RadosClient *client = (librados::RadosClient *)cluster;
md_config_t *conf = client->cct->_conf;
vector<const char*> args;
argv_to_vec(argc, argv, args);
- conf->parse_argv(args);
+ int ret = conf->parse_argv(args);
+ if (ret)
+ return ret;
conf->apply_changes(NULL);
+ return 0;
}
extern "C" int rados_conf_set(rados_t cluster, const char *option, const char *value)
}
TEST(DaemonConfig, ArgV) {
+ ASSERT_EQ(0, g_ceph_context->_conf->set_val("internal_safe_to_start_threads",
+ "false"));
+
int ret;
const char *argv[] = { "foo", "--debug", "22",
"--keyfile", "/tmp/my-keyfile", NULL };
ret = g_ceph_context->_conf->get_val("debug", &tmp, sizeof(buf));
ASSERT_EQ(ret, 0);
ASSERT_EQ(string("22"), string(buf));
+
+ ASSERT_EQ(0, g_ceph_context->_conf->set_val("internal_safe_to_start_threads",
+ "true"));
}
TEST(DaemonConfig, InjectArgs) {
// Clean up the garbage
unlink(tmpfile);
}
+
+TEST(DaemonConfig, ThreadSafety1) {
+ int ret;
+ // Verify that we can't change this, since internal_safe_to_start_threads has
+ // been set.
+ ret = g_ceph_context->_conf->set_val("osd_data", "");
+ ASSERT_EQ(ret, -ENOSYS);
+
+ ASSERT_EQ(0, g_ceph_context->_conf->set_val("internal_safe_to_start_threads",
+ "false"));
+
+ // Ok, now we can change this. Since this is just a test, and there are no
+ // OSD threads running, we know changing osd_data won't actually blow up the
+ // world.
+ ret = g_ceph_context->_conf->set_val("osd_data", "/tmp/crazydata");
+ ASSERT_EQ(ret, 0);
+
+ char buf[128];
+ char *tmp = buf;
+ memset(buf, 0, sizeof(buf));
+ ret = g_ceph_context->_conf->get_val("osd_data", &tmp, sizeof(buf));
+ ASSERT_EQ(ret, 0);
+ ASSERT_EQ(string("/tmp/crazydata"), string(buf));
+
+ ASSERT_EQ(0, g_ceph_context->_conf->set_val("internal_safe_to_start_threads",
+ "false"));
+ ASSERT_EQ(ret, 0);
+}