+ /* 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(obd, 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) {
+ name_create(&cliname, mti->mti_svname, "-mdc");
+ } else if (mti->mti_flags & LDD_F_SV_TYPE_OST) {
+ name_create(&cliname, mti->mti_svname, "-osc");
+ } else {
+ RETURN(-EINVAL);
+ }
+
+ /* Add failover nids to the client log */
+ name_create(&logname, mti->mti_fsname, "-client");
+ rc = mgs_write_log_failnid_internal(obd, fsdb, mti, logname, cliname);
+ name_destroy(&logname);
+ name_destroy(&cliname);
+
+ 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 (!cfs_test_bit(i, fsdb->fsdb_mdt_index_map))
+ continue;
+ name_create_mdt(&logname, mti->mti_fsname, i);
+ name_create_mdt_osc(&cliname, mti->mti_svname, fsdb, i);
+ rc = mgs_write_log_failnid_internal(obd, fsdb, mti,
+ logname, cliname);
+ name_destroy(&cliname);
+ name_destroy(&logname);
+ }
+ }
+
+ RETURN(rc);
+}
+
+static int mgs_wlp_lcfg(struct obd_device *obd, 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(obd, fsdb, mti, logname, tgtname, comment, CM_SKIP);
+ 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(obd, fsdb, logname, lcfg, tgtname, comment);
+ lustre_cfg_free(lcfg);
+ return rc;
+}
+
+/* write global variable settings into log */
+static int mgs_write_log_sys(struct obd_device *obd, struct fs_db *fsdb,
+ struct mgs_target_info *mti, char *sys, char *ptr)
+{
+ struct lustre_cfg_bufs bufs;
+ struct lustre_cfg *lcfg;
+ char *tmp;
+ char sep;
+ int cmd, val;
+ int rc;
+
+ 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
+ return -EINVAL;
+
+ /* separate the value */
+ val = simple_strtoul(tmp, NULL, 0);
+ if (*tmp == '\0')
+ CDEBUG(D_MGS, "global '%s' removed\n", sys);
+ else
+ CDEBUG(D_MGS, "global '%s' val=%d\n", sys, val);
+
+ lustre_cfg_bufs_reset(&bufs, NULL);
+ lustre_cfg_bufs_set_string(&bufs, 1, sys);
+ lcfg = lustre_cfg_new(cmd, &bufs);
+ lcfg->lcfg_num = val;
+ /* 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(obd, fsdb, mti,
+ *tmp == '\0' ? NULL : lcfg,
+ mti->mti_fsname, sys);
+ *ptr = sep;
+ lustre_cfg_free(lcfg);
+ return rc;
+}
+
+static int mgs_srpc_set_param_disk(struct obd_device *obd,
+ struct fs_db *fsdb,
+ struct mgs_target_info *mti,
+ char *param)
+{
+ struct llog_handle *llh = NULL;
+ char *logname;
+ char *comment, *ptr;
+ struct lustre_cfg_bufs bufs;
+ 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(&bufs, mti->mti_svname);
+ lustre_cfg_bufs_set_string(&bufs, 1, param);
+ lcfg = lustre_cfg_new(LCFG_SPTLRPC_CONF, &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(obd, logname)) {
+ rc = record_start_log(obd, &llh, logname);
+ record_end_log(obd, &llh);
+ if (rc)
+ GOTO(out, rc);
+ }
+
+ /* obsolete old one */
+ mgs_modify(obd, fsdb, mti, logname, mti->mti_svname, comment, CM_SKIP);
+
+ if (!mgs_param_empty(param)) {
+ /* write the new one */
+ rc = mgs_write_log_direct(obd, 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) {
+ fsdb->fsdb_fl_udesc = 1;
+ CWARN("Enable user descriptor shipping from client to MDT\n");
+ } else if (strcmp(ptr, "no") == 0) {
+ fsdb->fsdb_fl_udesc = 0;
+ 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 (fsdb->fsdb_fl_mgsself) {
+ 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(struct obd_device *obd,
+ struct fs_db *fsdb,
+ struct mgs_target_info *mti,
+ char *param)
+{
+ char *copy;
+ int rc, copy_size, del;
+ 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);
+
+ del = mgs_param_empty(param);
+ if (!del) {
+ 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(obd, fsdb, mti, copy);
+ if (rc)
+ goto out_free;
+
+ if (fsdb->fsdb_fl_mgsself) {
+ /*
+ * for mgs rules, make them effective immediately.
+ */
+ LASSERT(fsdb->fsdb_srpc_tgt == NULL);
+ sptlrpc_target_update_exp_flavor(obd, &fsdb->fsdb_srpc_gen);
+ }
+
+out_free:
+ OBD_FREE(copy, copy_size);
+ RETURN(rc);
+}
+
+struct mgs_srpc_read_data {
+ struct fs_db *msrd_fsdb;
+ int msrd_skip;
+};
+
+static int mgs_srpc_read_handler(struct llog_handle *llh,
+ struct llog_rec_hdr *rec,
+ void *data)
+{
+ struct mgs_srpc_read_data *msrd = (struct mgs_srpc_read_data *) data;
+ struct cfg_marker *marker;
+ struct lustre_cfg *lcfg = (struct lustre_cfg *)(rec + 1);
+ char *svname, *param;
+ int cfg_len, rc;
+ ENTRY;
+
+ if (rec->lrh_type != OBD_CFG_REC) {
+ CERROR("unhandled lrh_type: %#x\n", rec->lrh_type);
+ RETURN(-EINVAL);
+ }
+
+ cfg_len = rec->lrh_len - sizeof(struct llog_rec_hdr) -
+ sizeof(struct llog_rec_tail);
+
+ rc = lustre_cfg_sanity_check(lcfg, cfg_len);
+ if (rc) {
+ CERROR("Insane cfg\n");
+ RETURN(rc);
+ }
+
+ if (lcfg->lcfg_command == LCFG_MARKER) {
+ marker = lustre_cfg_buf(lcfg, 1);