+ RETURN(rc);
+}
+
+/* write global variable settings into log */
+static int mgs_write_log_sys(const struct lu_env *env,
+ struct mgs_device *mgs, struct fs_db *fsdb,
+ struct mgs_target_info *mti, char *sys, char *ptr)
+{
+ struct mgs_thread_info *mgi = mgs_env_info(env);
+ struct lustre_cfg *lcfg;
+ char *tmp, sep;
+ int rc, cmd, convert = 1;
+
+ if (class_match_param(ptr, PARAM_TIMEOUT, &tmp) == 0) {
+ cmd = LCFG_SET_TIMEOUT;
+ } else if (class_match_param(ptr, PARAM_LDLM_TIMEOUT, &tmp) == 0) {
+ cmd = LCFG_SET_LDLM_TIMEOUT;
+ /* Check for known params here so we can return error to lctl */
+ } else if ((class_match_param(ptr, PARAM_AT_MIN, &tmp) == 0) ||
+ (class_match_param(ptr, PARAM_AT_MAX, &tmp) == 0) ||
+ (class_match_param(ptr, PARAM_AT_EXTRA, &tmp) == 0) ||
+ (class_match_param(ptr, PARAM_AT_EARLY_MARGIN, &tmp) == 0) ||
+ (class_match_param(ptr, PARAM_AT_HISTORY, &tmp) == 0)) {
+ cmd = LCFG_PARAM;
+ } else if (class_match_param(ptr, PARAM_JOBID_VAR, &tmp) == 0) {
+ convert = 0; /* Don't convert string value to integer */
+ cmd = LCFG_PARAM;
+ } else {
+ return -EINVAL;
+ }
+
+ if (mgs_param_empty(ptr))
+ CDEBUG(D_MGS, "global '%s' removed\n", sys);
+ else
+ CDEBUG(D_MGS, "global '%s' val=%s\n", sys, tmp);
+
+ lustre_cfg_bufs_reset(&mgi->mgi_bufs, NULL);
+ lustre_cfg_bufs_set_string(&mgi->mgi_bufs, 1, sys);
+ if (!convert && *tmp != '\0')
+ lustre_cfg_bufs_set_string(&mgi->mgi_bufs, 2, tmp);
+ lcfg = lustre_cfg_new(cmd, &mgi->mgi_bufs);
+ lcfg->lcfg_num = convert ? simple_strtoul(tmp, NULL, 0) : 0;
+ /* truncate the comment to the parameter name */
+ ptr = tmp - 1;
+ sep = *ptr;
+ *ptr = '\0';
+ /* modify all servers and clients */
+ rc = mgs_write_log_direct_all(env, mgs, fsdb, mti,
+ *tmp == '\0' ? NULL : lcfg,
+ mti->mti_fsname, sys, 0);
+ if (rc == 0 && *tmp != '\0') {
+ switch (cmd) {
+ case LCFG_SET_TIMEOUT:
+ if (!obd_timeout_set || lcfg->lcfg_num > obd_timeout)
+ class_process_config(lcfg);
+ break;
+ case LCFG_SET_LDLM_TIMEOUT:
+ if (!ldlm_timeout_set || lcfg->lcfg_num > ldlm_timeout)
+ class_process_config(lcfg);
+ break;
+ default:
+ break;
+ }
+ }
+ *ptr = sep;
+ lustre_cfg_free(lcfg);
+ return rc;
+}
+
+/* write quota settings into log */
+static int mgs_write_log_quota(const struct lu_env *env, struct mgs_device *mgs,
+ struct fs_db *fsdb, struct mgs_target_info *mti,
+ char *quota, char *ptr)
+{
+ struct mgs_thread_info *mgi = mgs_env_info(env);
+ struct lustre_cfg *lcfg;
+ char *tmp;
+ char sep;
+ int rc, cmd = LCFG_PARAM;
+
+ /* support only 'meta' and 'data' pools so far */
+ if (class_match_param(ptr, QUOTA_METAPOOL_NAME, &tmp) != 0 &&
+ class_match_param(ptr, QUOTA_DATAPOOL_NAME, &tmp) != 0) {
+ CERROR("parameter quota.%s isn't supported (only quota.mdt "
+ "& quota.ost are)\n", ptr);
+ return -EINVAL;
+ }
+
+ if (*tmp == '\0') {
+ CDEBUG(D_MGS, "global '%s' removed\n", quota);
+ } else {
+ CDEBUG(D_MGS, "global '%s'\n", quota);
+
+ if (strchr(tmp, 'u') == NULL && strchr(tmp, 'g') == NULL &&
+ strcmp(tmp, "none") != 0) {
+ CERROR("enable option(%s) isn't supported\n", tmp);
+ return -EINVAL;
+ }
+ }
+
+ lustre_cfg_bufs_reset(&mgi->mgi_bufs, mti->mti_fsname);
+ lustre_cfg_bufs_set_string(&mgi->mgi_bufs, 1, quota);
+ lcfg = lustre_cfg_new(cmd, &mgi->mgi_bufs);
+ /* truncate the comment to the parameter name */
+ ptr = tmp - 1;
+ sep = *ptr;
+ *ptr = '\0';
+
+ /* XXX we duplicated quota enable information in all server
+ * config logs, it should be moved to a separate config
+ * log once we cleanup the config log for global param. */
+ /* modify all servers */
+ rc = mgs_write_log_direct_all(env, mgs, fsdb, mti,
+ *tmp == '\0' ? NULL : lcfg,
+ mti->mti_fsname, quota, 1);
+ *ptr = sep;
+ lustre_cfg_free(lcfg);
+ return rc < 0 ? rc : 0;