+
+ /* Add ost to all MDT lov defs */
+ for (i = 0; i < INDEX_MAP_SIZE * 8; i++){
+ if (test_bit(i, fsdb->fsdb_mdt_index_map)) {
+ char mdt_index[9];
+
+ rc = name_create_mdt_and_lov(&logname, &lovname, fsdb,
+ i);
+ if (rc)
+ RETURN(rc);
+ sprintf(mdt_index, "-MDT%04x", i);
+ rc = mgs_write_log_osc_to_lov(env, mgs, fsdb, mti,
+ logname, mdt_index,
+ lovname, LUSTRE_SP_MDT,
+ flags);
+ name_destroy(&logname);
+ name_destroy(&lovname);
+ if (rc)
+ RETURN(rc);
+ }
+ }
+
+ /* Append ost info to the client log */
+ rc = name_create(&logname, mti->mti_fsname, "-client");
+ if (rc)
+ RETURN(rc);
+ if (mgs_log_is_empty(env, mgs, logname)) {
+ /* Start client log */
+ rc = mgs_write_log_lov(env, mgs, fsdb, mti, logname,
+ fsdb->fsdb_clilov);
+ if (rc)
+ GOTO(out_free, rc);
+ rc = mgs_write_log_lmv(env, mgs, fsdb, mti, logname,
+ fsdb->fsdb_clilmv);
+ if (rc)
+ GOTO(out_free, rc);
+ }
+ rc = mgs_write_log_osc_to_lov(env, mgs, fsdb, mti, logname, "",
+ fsdb->fsdb_clilov, LUSTRE_SP_CLI, 0);
+out_free:
+ name_destroy(&logname);
+ RETURN(rc);
+}
+
+static __inline__ int mgs_param_empty(char *ptr)
+{
+ char *tmp;
+
+ if ((tmp = strchr(ptr, '=')) && (*(++tmp) == '\0'))
+ return 1;
+ return 0;
+}
+
+static int mgs_write_log_failnid_internal(const struct lu_env *env,
+ struct mgs_device *mgs,
+ struct fs_db *fsdb,
+ struct mgs_target_info *mti,
+ char *logname, char *cliname)
+{
+ int rc;
+ struct llog_handle *llh = NULL;
+
+ if (mgs_param_empty(mti->mti_params)) {
+ /* Remove _all_ failnids */
+ rc = mgs_modify(env, mgs, fsdb, mti, logname,
+ mti->mti_svname, "add failnid", CM_SKIP);
+ return rc < 0 ? rc : 0;
+ }
+
+ /* Otherwise failover nids are additive */
+ rc = record_start_log(env, mgs, &llh, logname);
+ if (rc)
+ return rc;
+ /* FIXME this should be a single journal transaction */
+ rc = record_marker(env, llh, fsdb, CM_START, mti->mti_svname,
+ "add failnid");
+ if (rc)
+ goto out_end;
+ rc = mgs_write_log_failnids(env, mti, llh, cliname);
+ if (rc)
+ goto out_end;
+ rc = record_marker(env, llh, fsdb, CM_END,
+ mti->mti_svname, "add failnid");
+out_end:
+ record_end_log(env, &llh);
+ return rc;
+}
+
+
+/* Add additional failnids to an existing log.
+ The mdc/osc must have been added to logs first */
+/* tcp nids must be in dotted-quad ascii -
+ we can't resolve hostnames from the kernel. */
+static int mgs_write_log_add_failnid(const struct lu_env *env,
+ struct mgs_device *mgs,
+ struct fs_db *fsdb,
+ struct mgs_target_info *mti)
+{
+ char *logname, *cliname;
+ int rc;
+ ENTRY;
+
+ /* FIXME we currently can't erase the failnids
+ * given when a target first registers, since they aren't part of
+ * an "add uuid" stanza */
+
+ /* Verify that we know about this target */
+ if (mgs_log_is_empty(env, mgs, mti->mti_svname)) {
+ LCONSOLE_ERROR_MSG(0x142, "The target %s has not registered "
+ "yet. It must be started before failnids "
+ "can be added.\n", mti->mti_svname);
+ RETURN(-ENOENT);
+ }
+
+ /* Create mdc/osc client name (e.g. lustre-OST0001-osc) */
+ if (mti->mti_flags & LDD_F_SV_TYPE_MDT) {
+ rc = name_create(&cliname, mti->mti_svname, "-mdc");
+ } else if (mti->mti_flags & LDD_F_SV_TYPE_OST) {
+ rc = name_create(&cliname, mti->mti_svname, "-osc");
+ } else {
+ RETURN(-EINVAL);
+ }
+ if (rc)
+ RETURN(rc);
+ /* Add failover nids to the client log */
+ rc = name_create(&logname, mti->mti_fsname, "-client");
+ if (rc) {
+ name_destroy(&cliname);
+ RETURN(rc);
+ }
+ rc = mgs_write_log_failnid_internal(env, mgs, fsdb,mti,logname,cliname);
+ name_destroy(&logname);
+ name_destroy(&cliname);
+ if (rc)
+ RETURN(rc);
+
+ if (mti->mti_flags & LDD_F_SV_TYPE_OST) {
+ /* Add OST failover nids to the MDT logs as well */
+ int i;
+
+ for (i = 0; i < INDEX_MAP_SIZE * 8; i++) {
+ if (!test_bit(i, fsdb->fsdb_mdt_index_map))
+ continue;
+ rc = name_create_mdt(&logname, mti->mti_fsname, i);
+ if (rc)
+ RETURN(rc);
+ rc = name_create_mdt_osc(&cliname, mti->mti_svname,
+ fsdb, i);
+ if (rc) {
+ name_destroy(&logname);
+ RETURN(rc);
+ }
+ rc = mgs_write_log_failnid_internal(env, mgs, fsdb,
+ mti, logname,
+ cliname);
+ name_destroy(&cliname);
+ name_destroy(&logname);
+ if (rc)
+ RETURN(rc);
+ }
+ }
+
+ RETURN(rc);
+}
+
+static int mgs_wlp_lcfg(const struct lu_env *env,
+ struct mgs_device *mgs, struct fs_db *fsdb,
+ struct mgs_target_info *mti,
+ char *logname, struct lustre_cfg_bufs *bufs,
+ char *tgtname, char *ptr)
+{
+ char comment[MTI_NAME_MAXLEN];
+ char *tmp;
+ struct lustre_cfg *lcfg;
+ int rc, del;
+
+ /* Erase any old settings of this same parameter */
+ memcpy(comment, ptr, MTI_NAME_MAXLEN);
+ comment[MTI_NAME_MAXLEN - 1] = 0;
+ /* But don't try to match the value. */
+ if ((tmp = strchr(comment, '=')))
+ *tmp = 0;
+ /* FIXME we should skip settings that are the same as old values */
+ rc = mgs_modify(env, mgs, fsdb, mti, logname, tgtname, comment,CM_SKIP);
+ if (rc < 0)
+ return rc;
+ del = mgs_param_empty(ptr);
+
+ LCONSOLE_INFO("%sing parameter %s.%s in log %s\n", del ? "Disabl" : rc ?
+ "Sett" : "Modify", tgtname, comment, logname);
+ if (del)
+ return rc;
+
+ lustre_cfg_bufs_reset(bufs, tgtname);
+ lustre_cfg_bufs_set_string(bufs, 1, ptr);
+ lcfg = lustre_cfg_new(LCFG_PARAM, bufs);
+ if (!lcfg)
+ return -ENOMEM;
+ rc = mgs_write_log_direct(env, mgs, fsdb, logname,lcfg,tgtname,comment);
+ lustre_cfg_free(lcfg);
+ 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;
+}
+
+static int mgs_srpc_set_param_disk(const struct lu_env *env,
+ struct mgs_device *mgs,
+ struct fs_db *fsdb,
+ struct mgs_target_info *mti,
+ char *param)
+{
+ struct mgs_thread_info *mgi = mgs_env_info(env);
+ struct llog_handle *llh = NULL;
+ char *logname;
+ char *comment, *ptr;
+ struct lustre_cfg *lcfg;
+ int rc, len;
+ ENTRY;
+
+ /* get comment */
+ ptr = strchr(param, '=');
+ LASSERT(ptr);
+ len = ptr - param;
+
+ OBD_ALLOC(comment, len + 1);
+ if (comment == NULL)
+ RETURN(-ENOMEM);
+ strncpy(comment, param, len);
+ comment[len] = '\0';
+
+ /* prepare lcfg */
+ lustre_cfg_bufs_reset(&mgi->mgi_bufs, mti->mti_svname);
+ lustre_cfg_bufs_set_string(&mgi->mgi_bufs, 1, param);
+ lcfg = lustre_cfg_new(LCFG_SPTLRPC_CONF, &mgi->mgi_bufs);
+ if (lcfg == NULL)
+ GOTO(out_comment, rc = -ENOMEM);
+
+ /* construct log name */
+ rc = name_create(&logname, mti->mti_fsname, "-sptlrpc");
+ if (rc)
+ GOTO(out_lcfg, rc);
+
+ if (mgs_log_is_empty(env, mgs, logname)) {
+ rc = record_start_log(env, mgs, &llh, logname);
+ if (rc)
+ GOTO(out, rc);
+ record_end_log(env, &llh);
+ }
+
+ /* obsolete old one */
+ rc = mgs_modify(env, mgs, fsdb, mti, logname, mti->mti_svname,
+ comment, CM_SKIP);
+ if (rc < 0)
+ GOTO(out, rc);
+ /* write the new one */
+ rc = mgs_write_log_direct(env, mgs, fsdb, logname, lcfg,
+ mti->mti_svname, comment);
+ if (rc)
+ CERROR("err %d writing log %s\n", rc, logname);
+out:
+ name_destroy(&logname);
+out_lcfg:
+ lustre_cfg_free(lcfg);
+out_comment:
+ OBD_FREE(comment, len + 1);
+ RETURN(rc);
+}
+
+static int mgs_srpc_set_param_udesc_mem(struct fs_db *fsdb,
+ char *param)
+{
+ char *ptr;
+
+ /* disable the adjustable udesc parameter for now, i.e. use default
+ * setting that client always ship udesc to MDT if possible. to enable
+ * it simply remove the following line */
+ goto error_out;
+
+ ptr = strchr(param, '=');
+ if (ptr == NULL)
+ goto error_out;
+ *ptr++ = '\0';
+
+ if (strcmp(param, PARAM_SRPC_UDESC))
+ goto error_out;
+
+ if (strcmp(ptr, "yes") == 0) {
+ set_bit(FSDB_UDESC, &fsdb->fsdb_flags);
+ CWARN("Enable user descriptor shipping from client to MDT\n");
+ } else if (strcmp(ptr, "no") == 0) {
+ clear_bit(FSDB_UDESC, &fsdb->fsdb_flags);
+ CWARN("Disable user descriptor shipping from client to MDT\n");
+ } else {
+ *(ptr - 1) = '=';
+ goto error_out;
+ }
+ return 0;
+
+error_out:
+ CERROR("Invalid param: %s\n", param);
+ return -EINVAL;
+}
+
+static int mgs_srpc_set_param_mem(struct fs_db *fsdb,
+ const char *svname,
+ char *param)
+{
+ struct sptlrpc_rule rule;
+ struct sptlrpc_rule_set *rset;
+ int rc;
+ ENTRY;
+
+ if (strncmp(param, PARAM_SRPC, sizeof(PARAM_SRPC) - 1) != 0) {
+ CERROR("Invalid sptlrpc parameter: %s\n", param);
+ RETURN(-EINVAL);
+ }
+
+ if (strncmp(param, PARAM_SRPC_UDESC,
+ sizeof(PARAM_SRPC_UDESC) - 1) == 0) {
+ RETURN(mgs_srpc_set_param_udesc_mem(fsdb, param));
+ }
+
+ if (strncmp(param, PARAM_SRPC_FLVR, sizeof(PARAM_SRPC_FLVR) - 1) != 0) {
+ CERROR("Invalid sptlrpc flavor parameter: %s\n", param);
+ RETURN(-EINVAL);
+ }
+
+ param += sizeof(PARAM_SRPC_FLVR) - 1;
+
+ rc = sptlrpc_parse_rule(param, &rule);
+ if (rc)
+ RETURN(rc);
+
+ /* mgs rules implies must be mgc->mgs */
+ if (test_bit(FSDB_MGS_SELF, &fsdb->fsdb_flags)) {
+ if ((rule.sr_from != LUSTRE_SP_MGC &&
+ rule.sr_from != LUSTRE_SP_ANY) ||
+ (rule.sr_to != LUSTRE_SP_MGS &&
+ rule.sr_to != LUSTRE_SP_ANY))
+ RETURN(-EINVAL);
+ }
+
+ /* preapre room for this coming rule. svcname format should be:
+ * - fsname: general rule
+ * - fsname-tgtname: target-specific rule
+ */
+ if (strchr(svname, '-')) {
+ struct mgs_tgt_srpc_conf *tgtconf;
+ int found = 0;
+
+ for (tgtconf = fsdb->fsdb_srpc_tgt; tgtconf != NULL;
+ tgtconf = tgtconf->mtsc_next) {
+ if (!strcmp(tgtconf->mtsc_tgt, svname)) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ int name_len;
+
+ OBD_ALLOC_PTR(tgtconf);
+ if (tgtconf == NULL)
+ RETURN(-ENOMEM);
+
+ name_len = strlen(svname);
+
+ OBD_ALLOC(tgtconf->mtsc_tgt, name_len + 1);
+ if (tgtconf->mtsc_tgt == NULL) {
+ OBD_FREE_PTR(tgtconf);
+ RETURN(-ENOMEM);
+ }
+ memcpy(tgtconf->mtsc_tgt, svname, name_len);
+
+ tgtconf->mtsc_next = fsdb->fsdb_srpc_tgt;
+ fsdb->fsdb_srpc_tgt = tgtconf;
+ }
+
+ rset = &tgtconf->mtsc_rset;
+ } else {
+ rset = &fsdb->fsdb_srpc_gen;
+ }
+
+ rc = sptlrpc_rule_set_merge(rset, &rule);
+
+ RETURN(rc);
+}
+
+static int mgs_srpc_set_param(const struct lu_env *env,
+ struct mgs_device *mgs,
+ struct fs_db *fsdb,
+ struct mgs_target_info *mti,
+ char *param)
+{
+ char *copy;
+ int rc, copy_size;
+ ENTRY;
+
+#ifndef HAVE_GSS
+ RETURN(-EINVAL);
+#endif
+ /* keep a copy of original param, which could be destroied
+ * during parsing */
+ copy_size = strlen(param) + 1;
+ OBD_ALLOC(copy, copy_size);
+ if (copy == NULL)
+ return -ENOMEM;
+ memcpy(copy, param, copy_size);
+
+ rc = mgs_srpc_set_param_mem(fsdb, mti->mti_svname, param);
+ if (rc)
+ goto out_free;
+
+ /* previous steps guaranteed the syntax is correct */
+ rc = mgs_srpc_set_param_disk(env, mgs, fsdb, mti, copy);
+ if (rc)
+ goto out_free;
+
+ if (test_bit(FSDB_MGS_SELF, &fsdb->fsdb_flags)) {
+ /*
+ * for mgs rules, make them effective immediately.
+ */
+ LASSERT(fsdb->fsdb_srpc_tgt == NULL);
+ sptlrpc_target_update_exp_flavor(mgs->mgs_obd,
+ &fsdb->fsdb_srpc_gen);
+ }
+
+out_free:
+ OBD_FREE(copy, copy_size);