OPTION(osd_scan_list_ping_tp_interval, OPT_U64, 100)
OPTION(osd_class_dir, OPT_STR, CEPH_LIBDIR "/rados-classes") // where rados plugins are stored
OPTION(osd_open_classes_on_start, OPT_BOOL, true)
+OPTION(osd_class_load_list, OPT_STR, "cephfs hello journal lock log numops "
+ "rbd refcount replica_log rgw statelog timeindex user version") // list of object classes allowed to be loaded (allow all: *)
OPTION(osd_check_for_log_corruption, OPT_BOOL, false)
OPTION(osd_use_stale_snap, OPT_BOOL, false)
OPTION(osd_rollback_to_cluster_snap, OPT_STR, "")
int ClassHandler::open_class(const string& cname, ClassData **pcls)
{
Mutex::Locker lock(mutex);
- ClassData *cls = _get_class(cname);
+ ClassData *cls = _get_class(cname, true);
+ if (!cls)
+ return -EPERM;
if (cls->status != ClassData::CLASS_OPEN) {
int r = _load_class(cls);
if (r)
cname[strlen(cname) - (sizeof(CLS_SUFFIX) - 1)] = '\0';
dout(10) << __func__ << " found " << cname << dendl;
ClassData *cls;
+ // skip classes that aren't in 'osd class load list'
r = open_class(cname, &cls);
- if (r < 0)
+ if (r < 0 && r != -EPERM)
goto out;
}
}
classes.clear();
}
-ClassHandler::ClassData *ClassHandler::_get_class(const string& cname)
+/*
+ * Check if @cname is in the whitespace delimited list @list, or the @list
+ * contains the wildcard "*".
+ *
+ * This is expensive but doesn't consume memory for an index, and is performed
+ * only once when a class is loaded.
+ */
+bool ClassHandler::in_class_list(const std::string& cname,
+ const std::string& list)
+{
+ std::istringstream ss(list);
+ std::istream_iterator<std::string> begin{ss};
+ std::istream_iterator<std::string> end{};
+
+ const std::vector<std::string> targets{cname, "*"};
+
+ auto it = std::find_first_of(begin, end,
+ targets.begin(), targets.end());
+
+ if (it == end)
+ return false;
+
+ return true;
+}
+
+ClassHandler::ClassData *ClassHandler::_get_class(const string& cname,
+ bool check_allowed)
{
ClassData *cls;
map<string, ClassData>::iterator iter = classes.find(cname);
if (iter != classes.end()) {
cls = &iter->second;
} else {
+ if (check_allowed && !in_class_list(cname, cct->_conf->osd_class_load_list)) {
+ dout(0) << "_get_class not permitted to load " << cname << dendl;
+ return NULL;
+ }
cls = &classes[cname];
dout(10) << "_get_class adding new class name " << cname << " " << cls << dendl;
cls->name = cname;
while (deps) {
if (!deps->name)
break;
- ClassData *cls_dep = _get_class(deps->name);
+ ClassData *cls_dep = _get_class(deps->name, false);
cls->dependencies.insert(cls_dep);
if (cls_dep->status != ClassData::CLASS_OPEN)
cls->missing_dependencies.insert(cls_dep);
{
assert(mutex.is_locked());
- ClassData *cls = _get_class(cname);
+ ClassData *cls = _get_class(cname, false);
dout(10) << "register_class " << cname << " status " << cls->status << dendl;
if (cls->status != ClassData::CLASS_INITIALIZING) {
Mutex mutex;
map<string, ClassData> classes;
- ClassData *_get_class(const string& cname);
+ ClassData *_get_class(const string& cname, bool check_allowed);
int _load_class(ClassData *cls);
+ bool in_class_list(const std::string& cname,
+ const std::string& list);
+
public:
explicit ClassHandler(CephContext *cct_) : cct(cct_), mutex("ClassHandler") {}