@@ -577,6 +577,11 @@ struct lustre_attr {
#define LUSTRE_RO_ATTR(name) LUSTRE_ATTR(name, 0444, name##_show, NULL)
#define LUSTRE_RW_ATTR(name) LUSTRE_ATTR(name, 0644, name##_show, name##_store)
+ssize_t lustre_attr_show(struct kobject *kobj, struct attribute *attr,
+ char *buf);
+ssize_t lustre_attr_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t len);
+
extern const struct sysfs_ops lustre_sysfs_ops;
struct root_squash_info;
@@ -108,6 +108,9 @@ typedef int (*llog_cb_t)(const struct lu_env *, struct llog_handle *,
char *lustre_cfg_string(struct lustre_cfg *lcfg, u32 index);
void print_lustre_cfg(struct lustre_cfg *lcfg);
int class_process_config(struct lustre_cfg *lcfg);
+ssize_t class_set_global(const char *param);
+ssize_t class_modify_config(struct lustre_cfg *lcfg, const char *prefix,
+ struct kobject *kobj);
int class_process_proc_param(char *prefix, struct lprocfs_vars *lvars,
struct lustre_cfg *lcfg, void *data);
@@ -1762,21 +1762,23 @@ int lprocfs_wr_nosquash_nids(const char __user *buffer, unsigned long count,
}
EXPORT_SYMBOL(lprocfs_wr_nosquash_nids);
-static ssize_t lustre_attr_show(struct kobject *kobj,
- struct attribute *attr, char *buf)
+ssize_t lustre_attr_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
{
struct lustre_attr *a = container_of(attr, struct lustre_attr, attr);
return a->show ? a->show(kobj, attr, buf) : 0;
}
+EXPORT_SYMBOL_GPL(lustre_attr_show);
-static ssize_t lustre_attr_store(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t len)
+ssize_t lustre_attr_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t len)
{
struct lustre_attr *a = container_of(attr, struct lustre_attr, attr);
return a->store ? a->store(kobj, attr, buf, len) : len;
}
+EXPORT_SYMBOL_GPL(lustre_attr_store);
const struct sysfs_ops lustre_sysfs_ops = {
.show = lustre_attr_show,
@@ -575,6 +575,24 @@ static int obd_device_list_open(struct inode *inode, struct file *file)
.attrs = lustre_attrs,
};
+ssize_t class_set_global(const char *param)
+{
+ const char *value = strchr(param, '=') + 1;
+ size_t off = value - param - 1;
+ ssize_t count = -ENOENT;
+ int i;
+
+ for (i = 0; lustre_attrs[i]; i++) {
+ if (!strncmp(lustre_attrs[i]->name, param, off)) {
+ count = lustre_attr_store(&lustre_kset->kobj,
+ lustre_attrs[i], value,
+ strlen(value));
+ break;
+ }
+ }
+ return count;
+}
+
int class_procfs_init(void)
{
int rc = -ENOMEM;
@@ -814,28 +814,6 @@ void class_del_profiles(void)
}
EXPORT_SYMBOL(class_del_profiles);
-static int class_set_global(char *ptr, int val, struct lustre_cfg *lcfg)
-{
- if (class_match_param(ptr, PARAM_AT_MIN, NULL) == 0)
- at_min = val;
- else if (class_match_param(ptr, PARAM_AT_MAX, NULL) == 0)
- at_max = val;
- else if (class_match_param(ptr, PARAM_AT_EXTRA, NULL) == 0)
- at_extra = val;
- else if (class_match_param(ptr, PARAM_AT_EARLY_MARGIN, NULL) == 0)
- at_early_margin = val;
- else if (class_match_param(ptr, PARAM_AT_HISTORY, NULL) == 0)
- at_history = val;
- else if (class_match_param(ptr, PARAM_JOBID_VAR, NULL) == 0)
- strlcpy(obd_jobid_var, lustre_cfg_string(lcfg, 2),
- JOBSTATS_JOBID_VAR_MAX_LEN + 1);
- else
- return -EINVAL;
-
- CDEBUG(D_IOCTL, "global %s = %d\n", ptr, val);
- return 0;
-}
-
/* We can't call ll_process_config or lquota_process_config directly because
* it lives in a module that must be loaded after this one.
*/
@@ -851,38 +829,44 @@ void lustre_register_client_process_config(int (*cpc)(struct lustre_cfg *lcfg))
static int process_param2_config(struct lustre_cfg *lcfg)
{
char *param = lustre_cfg_string(lcfg, 1);
- char *upcall = lustre_cfg_string(lcfg, 2);
- char *argv[] = {
- [0] = "/usr/sbin/lctl",
- [1] = "set_param",
- [2] = param,
- [3] = NULL
- };
- ktime_t start;
- ktime_t end;
- int rc;
+ struct kobject *kobj = NULL;
+ const char *subsys = param;
+ char *envp[3];
+ char *value;
+ size_t len;
+ int rc;
+ int i;
- /* Add upcall processing here. Now only lctl is supported */
- if (strcmp(upcall, LCTL_UPCALL) != 0) {
- CERROR("Unsupported upcall %s\n", upcall);
+ print_lustre_cfg(lcfg);
+
+ len = strcspn(param, ".=");
+ if (!len)
return -EINVAL;
- }
- start = ktime_get();
- rc = call_usermodehelper(argv[0], argv, NULL, UMH_WAIT_PROC);
- end = ktime_get();
+ /* If we find '=' then its the top level sysfs directory */
+ if (param[len] == '=')
+ return class_set_global(param);
- if (rc < 0) {
- CERROR(
- "lctl: error invoking upcall %s %s %s: rc = %d; time %ldus\n",
- argv[0], argv[1], argv[2], rc,
- (long)ktime_us_delta(end, start));
- } else {
- CDEBUG(D_HA, "lctl: invoked upcall %s %s %s, time %ldus\n",
- argv[0], argv[1], argv[2],
- (long)ktime_us_delta(end, start));
- rc = 0;
- }
+ subsys = kstrndup(param, len, GFP_KERNEL);
+ if (!subsys)
+ return -ENOMEM;
+
+ kobj = kset_find_obj(lustre_kset, subsys);
+ kfree(subsys);
+ if (!kobj)
+ return -ENODEV;
+
+ value = param;
+ param = strsep(&value, "=");
+ envp[0] = kasprintf(GFP_KERNEL, "PARAM=%s", param);
+ envp[1] = kasprintf(GFP_KERNEL, "SETTING=%s", value);
+ envp[2] = NULL;
+
+ rc = kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
+ for (i = 0; i < ARRAY_SIZE(envp); i++)
+ kfree(envp[i]);
+
+ kobject_put(kobj);
return rc;
}
@@ -983,12 +967,12 @@ int class_process_config(struct lustre_cfg *lcfg)
} else if ((class_match_param(lustre_cfg_string(lcfg, 1),
PARAM_SYS, &tmp) == 0)) {
/* Global param settings */
- err = class_set_global(tmp, lcfg->lcfg_num, lcfg);
+ err = class_set_global(tmp);
/*
* Client or server should not fail to mount if
* it hits an unknown configuration parameter.
*/
- if (err != 0)
+ if (err < 0)
CWARN("Ignoring unknown param %s\n", tmp);
err = 0;
@@ -1082,6 +1066,90 @@ int class_process_config(struct lustre_cfg *lcfg)
}
EXPORT_SYMBOL(class_process_config);
+ssize_t class_modify_config(struct lustre_cfg *lcfg, const char *prefix,
+ struct kobject *kobj)
+{
+ struct kobj_type *typ;
+ ssize_t count = 0;
+ int i;
+
+ if (lcfg->lcfg_command != LCFG_PARAM) {
+ CERROR("Unknown command: %d\n", lcfg->lcfg_command);
+ return -EINVAL;
+ }
+
+ typ = get_ktype(kobj);
+ if (!typ || !typ->default_attrs)
+ return -ENODEV;
+
+ print_lustre_cfg(lcfg);
+
+ /*
+ * e.g. tunefs.lustre --param mdt.group_upcall=foo /r/tmp/lustre-mdt
+ * or lctl conf_param lustre-MDT0000.mdt.group_upcall=bar
+ * or lctl conf_param lustre-OST0000.osc.max_dirty_mb=36
+ */
+ for (i = 1; i < lcfg->lcfg_bufcount; i++) {
+ struct attribute *attr;
+ size_t keylen;
+ char *value;
+ char *key;
+ int j;
+
+ key = lustre_cfg_buf(lcfg, i);
+ /* Strip off prefix */
+ if (class_match_param(key, prefix, &key))
+ /* If the prefix doesn't match, return error so we
+ * can pass it down the stack
+ */
+ return -EINVAL;
+
+ value = strchr(key, '=');
+ if (!value || *(value + 1) == 0) {
+ CERROR("%s: can't parse param '%s' (missing '=')\n",
+ lustre_cfg_string(lcfg, 0),
+ lustre_cfg_string(lcfg, i));
+ /* continue parsing other params */
+ continue;
+ }
+ keylen = value - key;
+ value++;
+
+ attr = NULL;
+ for (j = 0; typ->default_attrs[j]; j++) {
+ if (!strncmp(typ->default_attrs[j]->name, key,
+ keylen)) {
+ attr = typ->default_attrs[j];
+ break;
+ }
+ }
+
+ if (!attr) {
+ char *envp[3];
+
+ envp[0] = kasprintf(GFP_KERNEL, "PARAM=%s.%s.%.*s",
+ kobject_name(kobj->parent),
+ kobject_name(kobj),
+ (int)keylen, key);
+ envp[1] = kasprintf(GFP_KERNEL, "SETTING=%s", value);
+ envp[2] = NULL;
+
+ if (kobject_uevent_env(kobj, KOBJ_CHANGE, envp)) {
+ CERROR("%s: failed to send uevent %s\n",
+ kobject_name(kobj), key);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(envp); i++)
+ kfree(envp[i]);
+ } else {
+ count += lustre_attr_store(kobj, attr, value,
+ strlen(value));
+ }
+ }
+ return count;
+}
+EXPORT_SYMBOL(class_modify_config);
+
int class_process_proc_param(char *prefix, struct lprocfs_vars *lvars,
struct lustre_cfg *lcfg, void *data)
{