Whamcloud - gitweb
LU-13252 mgs: Handle possible failure from name_create_mdt
[fs/lustre-release.git] / lustre / mgs / mgs_llog.c
index 135e78b..726262f 100644 (file)
@@ -23,7 +23,7 @@
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  *
- * Copyright (c) 2011, 2016, Intel Corporation.
+ * Copyright (c) 2011, 2017, Intel Corporation.
  */
 /*
  * This file is part of Lustre, http://www.lustre.org/
@@ -46,6 +46,7 @@
 #include <uapi/linux/lustre/lustre_param.h>
 #include <lustre_sec.h>
 #include <lustre_quota.h>
+#include <lustre_sec.h>
 
 #include "mgs_internal.h"
 
@@ -70,6 +71,7 @@ int class_dentry_readdir(const struct lu_env *env, struct mgs_device *mgs,
        struct mgs_direntry *de;
        char *key;
        int rc, key_sz;
+       size_t suffix_len = sizeof(".bak") - 1;
 
        INIT_LIST_HEAD(log_list);
 
@@ -106,9 +108,8 @@ int class_dentry_readdir(const struct lu_env *env, struct mgs_device *mgs,
                }
 
                /* filter out ".bak" files */
-               /* sizeof(".bak") - 1 == 3 */
-               if (key_sz >= 3 &&
-                   !memcmp(".bak", key + key_sz - 3, 3)) {
+               if (key_sz >= suffix_len &&
+                   !memcmp(".bak", key + key_sz - suffix_len, suffix_len)) {
                        CDEBUG(D_MGS, "Skipping backup file %.*s\n",
                               key_sz, key);
                        goto next;
@@ -190,7 +191,7 @@ static int mgs_fsdb_handler(const struct lu_env *env, struct llog_handle *llh,
         int cfg_len = rec->lrh_len;
         char *cfg_buf = (char*) (rec + 1);
         struct lustre_cfg *lcfg;
-        __u32 index;
+       u32 index;
         int rc = 0;
         ENTRY;
 
@@ -210,12 +211,14 @@ static int mgs_fsdb_handler(const struct lu_env *env, struct llog_handle *llh,
         CDEBUG(D_INFO, "cmd %x %s %s\n", lcfg->lcfg_command,
                lustre_cfg_string(lcfg, 0), lustre_cfg_string(lcfg, 1));
 
-        /* Figure out ost indicies */
-        /* lov_modify_tgts add 0:lov1  1:ost1_UUID  2(index):0  3(gen):1 */
-        if (lcfg->lcfg_command == LCFG_LOV_ADD_OBD ||
-            lcfg->lcfg_command == LCFG_LOV_DEL_OBD) {
-                index = simple_strtoul(lustre_cfg_string(lcfg, 2),
-                                       NULL, 10);
+       /* Figure out ost indicies */
+       /* lov_modify_tgts add 0:lov1  1:ost1_UUID  2(index):0  3(gen):1 */
+       if (lcfg->lcfg_command == LCFG_LOV_ADD_OBD ||
+           lcfg->lcfg_command == LCFG_LOV_DEL_OBD) {
+               rc = kstrtouint(lustre_cfg_string(lcfg, 2), 10, &index);
+               if (rc)
+                       RETURN(rc);
+
                 CDEBUG(D_MGS, "OST index for %s is %u (%s)\n",
                        lustre_cfg_string(lcfg, 1), index,
                        lustre_cfg_string(lcfg, 2));
@@ -541,14 +544,15 @@ int mgs_cleanup_fsdb_list(struct mgs_device *mgs)
        return 0;
 }
 
-int mgs_find_or_make_fsdb(const struct lu_env *env, struct mgs_device *mgs,
-                         char *name, struct fs_db **dbh)
+/* The caller must hold mgs->mgs_mutex. */
+int mgs_find_or_make_fsdb_nolock(const struct lu_env *env,
+                               struct mgs_device *mgs,
+                               char *name, struct fs_db **dbh)
 {
        struct fs_db *fsdb;
        int rc = 0;
        ENTRY;
 
-       mutex_lock(&mgs->mgs_mutex);
        fsdb = mgs_find_fsdb(mgs, name);
        if (!fsdb) {
                fsdb = mgs_new_fsdb(env, mgs, name);
@@ -557,7 +561,6 @@ int mgs_find_or_make_fsdb(const struct lu_env *env, struct mgs_device *mgs,
 
                CDEBUG(D_MGS, "Created new db: rc = %d\n", rc);
        }
-       mutex_unlock(&mgs->mgs_mutex);
 
        if (!rc)
                *dbh = fsdb;
@@ -565,6 +568,19 @@ int mgs_find_or_make_fsdb(const struct lu_env *env, struct mgs_device *mgs,
        RETURN(rc);
 }
 
+int mgs_find_or_make_fsdb(const struct lu_env *env, struct mgs_device *mgs,
+                         char *name, struct fs_db **dbh)
+{
+       int rc;
+       ENTRY;
+
+       mutex_lock(&mgs->mgs_mutex);
+       rc = mgs_find_or_make_fsdb_nolock(env, mgs, name, dbh);
+       mutex_unlock(&mgs->mgs_mutex);
+
+       RETURN(rc);
+}
+
 /* 1 = index in use
    0 = index unused
    -1= empty client log */
@@ -955,18 +971,23 @@ out_pop:
         RETURN(rc);
 }
 
+enum replace_state {
+       REPLACE_COPY = 0,
+       REPLACE_SKIP,
+       REPLACE_DONE,
+       REPLACE_UUID,
+       REPLACE_SETUP
+};
+
 /** This structure is passed to mgs_replace_handler */
-struct mgs_replace_uuid_lookup {
+struct mgs_replace_data {
        /* Nids are replaced for this target device */
        struct mgs_target_info target;
        /* Temporary modified llog */
        struct llog_handle *temp_llh;
-       /* Flag is set if in target block*/
-       int in_target_device;
-       /* Nids already added. Just skip (multiple nids) */
-       int device_nids_added;
-       /* Flag is set if this block should not be copied */
-       int skip_it;
+       enum replace_state state;
+       char *failover;
+       char *nodeuuid;
 };
 
 /**
@@ -974,42 +995,42 @@ struct mgs_replace_uuid_lookup {
  * b) is it target block
  *
  * \param[in] lcfg
- * \param[in] mrul
+ * \param[in] mrd
  *
  * \retval 0 should not to be skipped
  * \retval 1 should to be skipped
  */
 static int check_markers(struct lustre_cfg *lcfg,
-                        struct mgs_replace_uuid_lookup *mrul)
+                        struct mgs_replace_data *mrd)
 {
         struct cfg_marker *marker;
 
        /* Track markers. Find given device */
        if (lcfg->lcfg_command == LCFG_MARKER) {
                marker = lustre_cfg_buf(lcfg, 1);
-               /* Clean llog from records marked as CM_EXCLUDE.
-                  CM_SKIP records are used for "active" command
+               /* Clean llog from records marked as CM_SKIP.
+                  CM_EXCLUDE records are used for "active" command
                   and can be restored if needed */
-               if ((marker->cm_flags & (CM_EXCLUDE | CM_START)) ==
-                   (CM_EXCLUDE | CM_START)) {
-                       mrul->skip_it = 1;
+               if ((marker->cm_flags & (CM_SKIP | CM_START)) ==
+                   (CM_SKIP | CM_START)) {
+                       mrd->state = REPLACE_SKIP;
                        return 1;
                }
 
-               if ((marker->cm_flags & (CM_EXCLUDE | CM_END)) ==
-                   (CM_EXCLUDE | CM_END)) {
-                       mrul->skip_it = 0;
+               if ((marker->cm_flags & (CM_SKIP | CM_END)) ==
+                   (CM_SKIP | CM_END)) {
+                       mrd->state = REPLACE_COPY;
                        return 1;
                }
 
-               if (strcmp(mrul->target.mti_svname, marker->cm_tgtname) == 0) {
+               if (strcmp(mrd->target.mti_svname, marker->cm_tgtname) == 0) {
                        LASSERT(!(marker->cm_flags & CM_START) ||
                                !(marker->cm_flags & CM_END));
                        if (marker->cm_flags & CM_START) {
-                               mrul->in_target_device = 1;
-                               mrul->device_nids_added = 0;
+                               mrd->state = REPLACE_UUID;
+                               mrd->failover = NULL;
                        } else if (marker->cm_flags & CM_END)
-                               mrul->in_target_device = 0;
+                               mrd->state = REPLACE_COPY;
                }
        }
 
@@ -1090,57 +1111,117 @@ static inline int record_setup(const struct lu_env *env,
  * \retval 0 record is not processed.
  */
 static int process_command(const struct lu_env *env, struct lustre_cfg *lcfg,
-                          struct mgs_replace_uuid_lookup *mrul)
+                          struct mgs_replace_data *mrd)
 {
        int nids_added = 0;
        lnet_nid_t nid;
        char *ptr;
-       int rc;
+       int rc = 0;
 
-       if (lcfg->lcfg_command == LCFG_ADD_UUID) {
+       if (mrd->state == REPLACE_UUID &&
+           lcfg->lcfg_command == LCFG_ADD_UUID) {
                /* LCFG_ADD_UUID command found. Let's skip original command
                   and add passed nids */
-               ptr = mrul->target.mti_params;
+               ptr = mrd->target.mti_params;
                while (class_parse_nid(ptr, &nid, &ptr) == 0) {
+                       if (!mrd->nodeuuid) {
+                               rc = name_create(&mrd->nodeuuid,
+                                                libcfs_nid2str(nid), "");
+                               if (rc) {
+                                       CERROR("Can't create uuid for "
+                                               "nid  %s, device %s\n",
+                                               libcfs_nid2str(nid),
+                                               mrd->target.mti_svname);
+                                       return rc;
+                               }
+                       }
                        CDEBUG(D_MGS, "add nid %s with uuid %s, "
                               "device %s\n", libcfs_nid2str(nid),
-                               mrul->target.mti_params,
-                               mrul->target.mti_svname);
+                               mrd->target.mti_params,
+                               mrd->nodeuuid);
                        rc = record_add_uuid(env,
-                                            mrul->temp_llh, nid,
-                                            mrul->target.mti_params);
+                                            mrd->temp_llh, nid,
+                                            mrd->nodeuuid);
                        if (!rc)
                                nids_added++;
+
+                       if (*ptr == ':') {
+                               mrd->failover = ptr;
+                               break;
+                       }
                }
 
                if (nids_added == 0) {
                        CERROR("No new nids were added, nid %s with uuid %s, "
                               "device %s\n", libcfs_nid2str(nid),
-                              mrul->target.mti_params,
-                              mrul->target.mti_svname);
-                       RETURN(-ENXIO);
+                              mrd->nodeuuid ? mrd->nodeuuid : "NULL",
+                              mrd->target.mti_svname);
+                       name_destroy(&mrd->nodeuuid);
+                       return -ENXIO;
                } else {
-                       mrul->device_nids_added = 1;
+                       mrd->state = REPLACE_SETUP;
                }
 
                return nids_added;
        }
 
-       if (mrul->device_nids_added && lcfg->lcfg_command == LCFG_SETUP) {
+       if (mrd->state == REPLACE_SETUP && lcfg->lcfg_command == LCFG_SETUP) {
                /* LCFG_SETUP command found. UUID should be changed */
                rc = record_setup(env,
-                                 mrul->temp_llh,
+                                 mrd->temp_llh,
                                  /* devname the same */
                                  lustre_cfg_string(lcfg, 0),
                                  /* s1 is not changed */
                                  lustre_cfg_string(lcfg, 1),
-                                 /* new uuid should be
-                                 the full nidlist */
-                                 mrul->target.mti_params,
+                                 mrd->nodeuuid,
                                  /* s3 is not changed */
                                  lustre_cfg_string(lcfg, 3),
                                  /* s4 is not changed */
                                  lustre_cfg_string(lcfg, 4));
+
+               name_destroy(&mrd->nodeuuid);
+               if (rc)
+                       return rc;
+
+               if (mrd->failover) {
+                       ptr = mrd->failover;
+                       while (class_parse_nid(ptr, &nid, &ptr) == 0) {
+                               if (mrd->nodeuuid == NULL) {
+                                       rc =  name_create(&mrd->nodeuuid,
+                                                         libcfs_nid2str(nid),
+                                                         "");
+                                       if (rc)
+                                               return rc;
+                               }
+
+                               CDEBUG(D_MGS, "add nid %s for failover %s\n",
+                                      libcfs_nid2str(nid), mrd->nodeuuid);
+                               rc = record_add_uuid(env, mrd->temp_llh, nid,
+                                                    mrd->nodeuuid);
+                               if (rc) {
+                                       name_destroy(&mrd->nodeuuid);
+                                       return rc;
+                               }
+                               if (*ptr == ':') {
+                                       rc = record_add_conn(env,
+                                               mrd->temp_llh,
+                                               lustre_cfg_string(lcfg, 0),
+                                               mrd->nodeuuid);
+                                       name_destroy(&mrd->nodeuuid);
+                                       if (rc)
+                                               return rc;
+                               }
+                       }
+                       if (mrd->nodeuuid) {
+                               rc = record_add_conn(env, mrd->temp_llh,
+                                                    lustre_cfg_string(lcfg, 0),
+                                                    mrd->nodeuuid);
+                               name_destroy(&mrd->nodeuuid);
+                               if (rc)
+                                       return rc;
+                       }
+               }
+               mrd->state = REPLACE_DONE;
                return rc ? rc : 1;
        }
 
@@ -1154,22 +1235,22 @@ static int process_command(const struct lu_env *env, struct lustre_cfg *lcfg,
  *
  * \param[in] llh       log to be processed
  * \param[in] rec       current record
- * \param[in] data      mgs_replace_uuid_lookup structure
+ * \param[in] data      mgs_replace_data structure
  *
  * \retval 0    success
  */
-static int mgs_replace_handler(const struct lu_env *env,
-                              struct llog_handle *llh,
-                              struct llog_rec_hdr *rec,
-                              void *data)
+static int mgs_replace_nids_handler(const struct lu_env *env,
+                                   struct llog_handle *llh,
+                                   struct llog_rec_hdr *rec,
+                                   void *data)
 {
-       struct mgs_replace_uuid_lookup *mrul;
+       struct mgs_replace_data *mrd;
        struct lustre_cfg *lcfg = REC_DATA(rec);
        int cfg_len = REC_DATA_LEN(rec);
        int rc;
        ENTRY;
 
-       mrul = (struct mgs_replace_uuid_lookup *)data;
+       mrd = (struct mgs_replace_data *)data;
 
        if (rec->lrh_type != OBD_CFG_REC) {
                CERROR("unhandled lrh_type: %#x, cmd %x %s %s\n",
@@ -1185,23 +1266,27 @@ static int mgs_replace_handler(const struct lu_env *env,
                GOTO(skip_out, rc = 0);
        }
 
-       rc = check_markers(lcfg, mrul);
-       if (rc || mrul->skip_it)
+       rc = check_markers(lcfg, mrd);
+       if (rc || mrd->state == REPLACE_SKIP)
                GOTO(skip_out, rc = 0);
 
        /* Write to new log all commands outside target device block */
-       if (!mrul->in_target_device)
+       if (mrd->state == REPLACE_COPY)
                GOTO(copy_out, rc = 0);
 
-       /* Skip all other LCFG_ADD_UUID and LCFG_ADD_CONN records
-          (failover nids) for this target, assuming that if then
-          primary is changing then so is the failover */
-       if (mrul->device_nids_added &&
+       if (mrd->state == REPLACE_DONE &&
            (lcfg->lcfg_command == LCFG_ADD_UUID ||
-            lcfg->lcfg_command == LCFG_ADD_CONN))
+            lcfg->lcfg_command == LCFG_ADD_CONN)) {
+               if (!mrd->failover)
+                       CWARN("Previous failover is deleted, but new one is "
+                             "not set. This means you configure system "
+                             "without failover or passed wrong replace_nids "
+                             "command parameters. Device %s, passed nids %s\n",
+                             mrd->target.mti_svname, mrd->target.mti_params);
                GOTO(skip_out, rc = 0);
+       }
 
-       rc = process_command(env, lcfg, mrul);
+       rc = process_command(env, lcfg, mrd);
        if (rc < 0)
                RETURN(rc);
 
@@ -1209,7 +1294,7 @@ static int mgs_replace_handler(const struct lu_env *env,
                RETURN(0);
 copy_out:
        /* Record is placed in temporary llog as is */
-       rc = llog_write(env, mrul->temp_llh, rec, LLOG_NEXT_IDX);
+       rc = llog_write(env, mrd->temp_llh, rec, LLOG_NEXT_IDX);
 
        CDEBUG(D_MGS, "Copied idx=%d, rc=%d, len=%d, cmd %x %s %s\n",
               rec->lrh_index, rc, rec->lrh_len, lcfg->lcfg_command,
@@ -1237,21 +1322,21 @@ static int mgs_log_is_empty(const struct lu_env *env,
        return rc;
 }
 
-static int mgs_replace_nids_log(const struct lu_env *env,
-                               struct obd_device *mgs, struct fs_db *fsdb,
-                               char *logname, char *devname, char *nids)
+static int mgs_replace_log(const struct lu_env *env,
+                          struct obd_device *mgs,
+                          char *logname, char *devname,
+                          llog_cb_t replace_handler, void *data)
 {
        struct llog_handle *orig_llh, *backup_llh;
        struct llog_ctxt *ctxt;
-       struct mgs_replace_uuid_lookup *mrul;
+       struct mgs_replace_data *mrd;
        struct mgs_device *mgs_dev = lu2mgs_dev(mgs->obd_lu_dev);
        static struct obd_uuid   cfg_uuid = { .uuid = "config_uuid" };
        char *backup;
-       int rc, rc2;
+       int rc, rc2, buf_size;
+       time64_t now;
        ENTRY;
 
-       CDEBUG(D_MGS, "Replace nids for %s in %s\n", devname, logname);
-
        ctxt = llog_get_context(mgs, LLOG_CONFIG_ORIG_CTXT);
        LASSERT(ctxt != NULL);
 
@@ -1260,11 +1345,15 @@ static int mgs_replace_nids_log(const struct lu_env *env,
                GOTO(out_put, rc = 0);
        }
 
-       OBD_ALLOC(backup, strlen(logname) + strlen(".bak") + 1);
+       now = ktime_get_real_seconds();
+
+       /* max time64_t in decimal fits into 20 bytes long string */
+       buf_size = strlen(logname) + 1 + 20 + 1 + strlen(".bak") + 1;
+       OBD_ALLOC(backup, buf_size);
        if (backup == NULL)
                GOTO(out_put, rc = -ENOMEM);
 
-       sprintf(backup, "%s.bak", logname);
+       snprintf(backup, buf_size, "%s.%llu.bak", logname, now);
 
        rc = llog_backup(env, mgs, ctxt, ctxt, logname, backup);
        if (rc == 0) {
@@ -1301,20 +1390,23 @@ static int mgs_replace_nids_log(const struct lu_env *env,
        if (llog_get_size(backup_llh) <= 1)
                GOTO(out_close, rc = 0);
 
-       OBD_ALLOC_PTR(mrul);
-       if (!mrul)
+       OBD_ALLOC_PTR(mrd);
+       if (!mrd)
                GOTO(out_close, rc = -ENOMEM);
        /* devname is only needed information to replace UUID records */
-       strlcpy(mrul->target.mti_svname, devname,
-               sizeof(mrul->target.mti_svname));
-       /* parse nids later */
-       strlcpy(mrul->target.mti_params, nids, sizeof(mrul->target.mti_params));
+       if (devname)
+               strlcpy(mrd->target.mti_svname, devname,
+                       sizeof(mrd->target.mti_svname));
+       /* data is parsed in llog callback */
+       if (data)
+               strlcpy(mrd->target.mti_params, data,
+                       sizeof(mrd->target.mti_params));
        /* Copy records to this temporary llog */
-       mrul->temp_llh = orig_llh;
+       mrd->temp_llh = orig_llh;
 
-       rc = llog_process(env, backup_llh, mgs_replace_handler,
-                         (void *)mrul, NULL);
-       OBD_FREE_PTR(mrul);
+       rc = llog_process(env, backup_llh, replace_handler,
+                         (void *)mrd, NULL);
+       OBD_FREE_PTR(mrd);
 out_close:
        rc2 = llog_close(NULL, backup_llh);
        if (!rc)
@@ -1336,30 +1428,55 @@ out_restore:
        }
 
 out_free:
-       OBD_FREE(backup, strlen(backup) + 1);
+       OBD_FREE(backup, buf_size);
 
 out_put:
        llog_ctxt_put(ctxt);
 
        if (rc)
-               CERROR("%s: failed to replace nids in log %s: rc = %d\n",
+               CERROR("%s: failed to replace log %s: rc = %d\n",
                       mgs->obd_name, logname, rc);
 
        RETURN(rc);
 }
 
+static int mgs_replace_nids_log(const struct lu_env *env,
+                               struct obd_device *obd,
+                               char *logname, char *devname, char *nids)
+{
+       CDEBUG(D_MGS, "Replace NIDs for %s in %s\n", devname, logname);
+       return mgs_replace_log(env, obd, logname, devname,
+                              mgs_replace_nids_handler, nids);
+}
+
 /**
  * Parse device name and get file system name and/or device index
  *
- * \param[in]   devname device name (ex. lustre-MDT0000)
- * \param[out]  fsname  file system name(optional)
- * \param[out]  index   device index(optional)
+ * @devname    device name (ex. lustre-MDT0000)
+ * @fsname     file system name extracted from @devname and returned
+ *             to the caller (optional)
+ * @index      device index extracted from @devname and returned to
+ *             the caller (optional)
  *
- * \retval 0    success
+ * RETURN      0                       success if we are only interested in
+ *                                     extracting fsname from devname.
+ *                                     i.e index is NULL
+ *
+ *             LDD_F_SV_TYPE_*         Besides extracting the fsname the
+ *                                     user also wants the index. Report to
+ *                                     the user the type of obd device the
+ *                                     returned index belongs too.
+ *
+ *             -EINVAL                 The obd device name is improper so
+ *                                     fsname could not be extracted.
+ *
+ *             -ENXIO                  Failed to extract the index out of
+ *                                     the obd device name. Most likely an
+ *                                     invalid obd device name
  */
-static int mgs_parse_devname(char *devname, char *fsname, __u32 *index)
+static int mgs_parse_devname(char *devname, char *fsname, u32 *index)
 {
-       int rc;
+       int rc = 0;
        ENTRY;
 
        /* Extract fsname */
@@ -1377,11 +1494,12 @@ static int mgs_parse_devname(char *devname, char *fsname, __u32 *index)
                if (rc < 0) {
                        CDEBUG(D_MGS, "Device name %s with wrong index\n",
                               devname);
-                       RETURN(-EINVAL);
+                       RETURN(-ENXIO);
                }
        }
 
-       RETURN(0);
+       /* server_name2index can return LDD_F_SV_TYPE_* so always return rc */
+       RETURN(rc);
 }
 
 /* This is only called during replace_nids */
@@ -1416,12 +1534,15 @@ static int only_mgs_is_running(struct obd_device *mgs_obd)
        return (num_devices <= 3) && (num_exports == 0);
 }
 
-static int name_create_mdt(char **logname, char *fsname, int i)
+static int name_create_mdt(char **logname, char *fsname, int mdt_idx)
 {
-       char mdt_index[9];
+       char postfix[9];
+
+       if (mdt_idx > INDEX_MAP_MAX_VALUE)
+               return -E2BIG;
 
-       sprintf(mdt_index, "-MDT%04x", i);
-       return name_create(logname, fsname, mdt_index);
+       snprintf(postfix, sizeof(postfix), "-MDT%04x", mdt_idx);
+       return name_create(logname, fsname, postfix);
 }
 
 /**
@@ -1461,9 +1582,9 @@ int mgs_replace_nids(const struct lu_env *env,
                GOTO(out, rc = -EINPROGRESS);
        }
 
-       /* Get fsname and index*/
+       /* Get fsname and index */
        rc = mgs_parse_devname(devname, fsname, &index);
-       if (rc)
+       if (rc < 0)
                GOTO(out, rc);
 
        rc = mgs_find_or_make_fsdb(env, mgs, fsname, &fsdb);
@@ -1473,8 +1594,10 @@ int mgs_replace_nids(const struct lu_env *env,
        }
 
        /* Process client llogs */
-       name_create(&logname, fsname, "-client");
-       rc = mgs_replace_nids_log(env, mgs_obd, fsdb, logname, devname, nids);
+       rc = name_create(&logname, fsname, "-client");
+       if (rc)
+               GOTO(out, rc);
+       rc = mgs_replace_nids_log(env, mgs_obd, logname, devname, nids);
        name_destroy(&logname);
        if (rc) {
                CERROR("%s: error while replacing NIDs for %s: rc = %d\n",
@@ -1486,8 +1609,10 @@ int mgs_replace_nids(const struct lu_env *env,
        for (i = 0; i < INDEX_MAP_SIZE * 8; i++) {
                if (!test_bit(i, fsdb->fsdb_mdt_index_map))
                        continue;
-               name_create_mdt(&logname, fsname, i);
-               rc = mgs_replace_nids_log(env, mgs_obd, fsdb, logname, devname, nids);
+               rc = name_create_mdt(&logname, fsname, i);
+               if (rc)
+                       GOTO(out, rc);
+               rc = mgs_replace_nids_log(env, mgs_obd, logname, devname, nids);
                name_destroy(&logname);
                if (rc)
                        GOTO(out, rc);
@@ -1504,6 +1629,188 @@ out:
        RETURN(rc);
 }
 
+/**
+ * This is called for every record in llog. Some of records are
+ * skipped, others are copied to new log as is.
+ * Records to be skipped are
+ *  marker records marked SKIP
+ *  records enclosed between SKIP markers
+ *
+ * \param[in] llh      log to be processed
+ * \param[in] rec      current record
+ * \param[in] data     mgs_replace_data structure
+ *
+ * \retval 0   success
+ **/
+static int mgs_clear_config_handler(const struct lu_env *env,
+                                   struct llog_handle *llh,
+                                   struct llog_rec_hdr *rec, void *data)
+{
+       struct mgs_replace_data *mrd;
+       struct lustre_cfg *lcfg = REC_DATA(rec);
+       int cfg_len = REC_DATA_LEN(rec);
+       int rc;
+
+       ENTRY;
+
+       mrd = (struct mgs_replace_data *)data;
+
+       if (rec->lrh_type != OBD_CFG_REC) {
+               CDEBUG(D_MGS, "Config llog Name=%s, Record Index=%u, "
+                      "Unhandled Record Type=%#x\n", llh->lgh_name,
+                      rec->lrh_index, rec->lrh_type);
+               RETURN(-EINVAL);
+       }
+
+       rc = lustre_cfg_sanity_check(lcfg, cfg_len);
+       if (rc) {
+               CDEBUG(D_MGS, "Config llog Name=%s, Invalid config file.",
+                      llh->lgh_name);
+               RETURN(-EINVAL);
+       }
+
+       if (lcfg->lcfg_command == LCFG_MARKER) {
+               struct cfg_marker *marker;
+
+               marker = lustre_cfg_buf(lcfg, 1);
+               if (marker->cm_flags & CM_SKIP) {
+                       if (marker->cm_flags & CM_START)
+                               mrd->state = REPLACE_SKIP;
+                       if (marker->cm_flags & CM_END)
+                               mrd->state = REPLACE_COPY;
+                       /* SKIP section started or finished */
+                       CDEBUG(D_MGS, "Skip idx=%d, rc=%d, len=%d, "
+                              "cmd %x %s %s\n", rec->lrh_index, rc,
+                              rec->lrh_len, lcfg->lcfg_command,
+                              lustre_cfg_string(lcfg, 0),
+                              lustre_cfg_string(lcfg, 1));
+                       RETURN(0);
+               }
+       } else {
+               if (mrd->state == REPLACE_SKIP) {
+                       /* record enclosed between SKIP markers, skip it */
+                       CDEBUG(D_MGS, "Skip idx=%d, rc=%d, len=%d, "
+                              "cmd %x %s %s\n", rec->lrh_index, rc,
+                              rec->lrh_len, lcfg->lcfg_command,
+                              lustre_cfg_string(lcfg, 0),
+                              lustre_cfg_string(lcfg, 1));
+                       RETURN(0);
+               }
+       }
+
+       /* Record is placed in temporary llog as is */
+       rc = llog_write(env, mrd->temp_llh, rec, LLOG_NEXT_IDX);
+
+       CDEBUG(D_MGS, "Copied idx=%d, rc=%d, len=%d, cmd %x %s %s\n",
+              rec->lrh_index, rc, rec->lrh_len, lcfg->lcfg_command,
+              lustre_cfg_string(lcfg, 0), lustre_cfg_string(lcfg, 1));
+       RETURN(rc);
+}
+
+/*
+ * Directory CONFIGS/ may contain files which are not config logs to
+ * be cleared. Skip any llogs with a non-alphanumeric character after
+ * the last '-'. For example, fsname-MDT0000.sav, fsname-MDT0000.bak,
+ * fsname-MDT0000.orig, fsname-MDT0000~, fsname-MDT0000.20150516, etc.
+ */
+static bool config_to_clear(const char *logname)
+{
+       int i;
+       char *str;
+
+       str = strrchr(logname, '-');
+       if (!str)
+               return 0;
+
+       i = 0;
+       while (isalnum(str[++i]));
+       return str[i] == '\0';
+}
+
+/**
+ * Clear config logs for \a name
+ *
+ * \param env
+ * \param mgs          MGS device
+ * \param name         name of device or of filesystem
+ *                     (ex. lustre-OST0000 or lustre) in later case all logs
+ *                     will be cleared
+ *
+ * \retval 0           success
+ */
+int mgs_clear_configs(const struct lu_env *env,
+                    struct mgs_device *mgs, const char *name)
+{
+       struct list_head dentry_list;
+       struct mgs_direntry *dirent, *n;
+       char *namedash;
+       int conn_state;
+       struct obd_device *mgs_obd = mgs->mgs_obd;
+       int rc;
+
+       ENTRY;
+
+       /* Prevent clients and servers from connecting to mgs */
+       spin_lock(&mgs_obd->obd_dev_lock);
+       conn_state = mgs_obd->obd_no_conn;
+       mgs_obd->obd_no_conn = 1;
+       spin_unlock(&mgs_obd->obd_dev_lock);
+
+       /*
+        * config logs cannot be cleaned if anything other than
+        * MGS is started
+        */
+       if (!only_mgs_is_running(mgs_obd)) {
+               CERROR("Only MGS is allowed to be started\n");
+               GOTO(out, rc = -EBUSY);
+       }
+
+       /* Find all the logs in the CONFIGS directory */
+       rc = class_dentry_readdir(env, mgs, &dentry_list);
+       if (rc) {
+               CERROR("%s: cannot read config directory '%s': rc = %d\n",
+                      mgs_obd->obd_name, MOUNT_CONFIGS_DIR, rc);
+               GOTO(out, rc);
+       }
+
+       if (list_empty(&dentry_list)) {
+               CERROR("%s: list empty reading config dir '%s': rc = %d\n",
+                       mgs_obd->obd_name, MOUNT_CONFIGS_DIR, -ENOENT);
+               GOTO(out, rc = -ENOENT);
+       }
+
+       OBD_ALLOC(namedash, strlen(name) + 2);
+       if (namedash == NULL)
+               GOTO(out, rc = -ENOMEM);
+       snprintf(namedash, strlen(name) + 2, "%s-", name);
+
+       list_for_each_entry(dirent, &dentry_list, mde_list) {
+               if (strcmp(name, dirent->mde_name) &&
+                   strncmp(namedash, dirent->mde_name, strlen(namedash)))
+                       continue;
+               if (!config_to_clear(dirent->mde_name))
+                       continue;
+               CDEBUG(D_MGS, "%s: Clear config log %s\n",
+                      mgs_obd->obd_name, dirent->mde_name);
+               rc = mgs_replace_log(env, mgs_obd, dirent->mde_name, NULL,
+                                    mgs_clear_config_handler, NULL);
+               if (rc)
+                       break;
+       }
+
+       list_for_each_entry_safe(dirent, n, &dentry_list, mde_list) {
+               list_del_init(&dirent->mde_list);
+               mgs_direntry_free(dirent);
+       }
+       OBD_FREE(namedash, strlen(name) + 2);
+out:
+       spin_lock(&mgs_obd->obd_dev_lock);
+       mgs_obd->obd_no_conn = conn_state;
+       spin_unlock(&mgs_obd->obd_dev_lock);
+
+       RETURN(rc);
+}
+
 static int record_lov_setup(const struct lu_env *env, struct llog_handle *llh,
                            char *devname, struct lov_desc *desc)
 {
@@ -2422,13 +2729,14 @@ static int mgs_write_log_mdt0(const struct lu_env *env,
 {
         char *log = mti->mti_svname;
         struct llog_handle *llh = NULL;
-        char *uuid, *lovname;
+       struct obd_uuid *uuid;
+       char *lovname;
         char mdt_index[6];
         char *ptr = mti->mti_params;
         int rc = 0, failout = 0;
         ENTRY;
 
-        OBD_ALLOC(uuid, sizeof(struct obd_uuid));
+       OBD_ALLOC_PTR(uuid);
         if (uuid == NULL)
                 RETURN(-ENOMEM);
 
@@ -2453,17 +2761,17 @@ static int mgs_write_log_mdt0(const struct lu_env *env,
        /* add MDT itself */
 
         /* FIXME this whole fn should be a single journal transaction */
-       sprintf(uuid, "%s_UUID", log);
+       sprintf(uuid->uuid, "%s_UUID", log);
        rc = record_marker(env, llh, fsdb, CM_START, log, "add mdt");
        if (rc)
                GOTO(out_lod, rc);
-       rc = record_attach(env, llh, log, LUSTRE_MDT_NAME, uuid);
+       rc = record_attach(env, llh, log, LUSTRE_MDT_NAME, uuid->uuid);
        if (rc)
                GOTO(out_end, rc);
        rc = record_mount_opt(env, llh, log, lovname, NULL);
        if (rc)
                GOTO(out_end, rc);
-       rc = record_setup(env, llh, log, uuid, mdt_index, lovname,
+       rc = record_setup(env, llh, log, uuid->uuid, mdt_index, lovname,
                         failout ? "n" : "f");
        if (rc)
                GOTO(out_end, rc);
@@ -2475,7 +2783,7 @@ out_end:
 out_lod:
        name_destroy(&lovname);
 out_free:
-        OBD_FREE(uuid, sizeof(struct obd_uuid));
+        OBD_FREE_PTR(uuid);
         RETURN(rc);
 }
 
@@ -2804,13 +3112,14 @@ out_end:
         /* 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];
+                       char mdt_index[13];
 
                        rc = name_create_mdt_and_lov(&logname, &lovname, fsdb,
                                                     i);
                        if (rc)
                                RETURN(rc);
-                        sprintf(mdt_index, "-MDT%04x", i);
+
+                       snprintf(mdt_index, sizeof(mdt_index), "-MDT%04x", i);
                        rc = mgs_write_log_osc_to_lov(env, mgs, fsdb, mti,
                                                      logname, mdt_index,
                                                      lovname, LUSTRE_SP_MDT,
@@ -2904,7 +3213,8 @@ static int mgs_write_log_add_failnid(const struct lu_env *env,
 
         /* FIXME we currently can't erase the failnids
          * given when a target first registers, since they aren't part of
-         * an "add uuid" stanza */
+        * an "add uuid" stanza
+        */
 
         /* Verify that we know about this target */
        if (mgs_log_is_empty(env, mgs, mti->mti_svname)) {
@@ -2924,12 +3234,14 @@ static int mgs_write_log_add_failnid(const struct lu_env *env,
         }
        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);
@@ -2977,8 +3289,7 @@ static int mgs_wlp_lcfg(const struct lu_env *env,
        int rc, del;
 
        /* Erase any old settings of this same parameter */
-       memcpy(comment, ptr, MTI_NAME_MAXLEN);
-       comment[MTI_NAME_MAXLEN - 1] = 0;
+       strlcpy(comment, ptr, sizeof(comment));
        /* But don't try to match the value. */
        tmp = strchr(comment, '=');
        if (tmp != NULL)
@@ -3014,22 +3325,6 @@ static int mgs_wlp_lcfg(const struct lu_env *env,
        return rc;
 }
 
-static int mgs_write_log_param2(const struct lu_env *env,
-                               struct mgs_device *mgs,
-                               struct fs_db *fsdb,
-                               struct mgs_target_info *mti, char *ptr)
-{
-       struct lustre_cfg_bufs  bufs;
-       int                     rc = 0;
-       ENTRY;
-
-       CDEBUG(D_MGS, "next param '%s'\n", ptr);
-       rc = mgs_wlp_lcfg(env, mgs, fsdb, mti, PARAMS_FILENAME, &bufs,
-                         mti->mti_svname, ptr);
-
-       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,
@@ -3073,7 +3368,14 @@ static int mgs_write_log_sys(const struct lu_env *env,
                return -ENOMEM;
 
        lcfg = &lcr->lcr_cfg;
-       lcfg->lcfg_num = convert ? simple_strtoul(tmp, NULL, 0) : 0;
+       if (convert) {
+               rc = kstrtouint(tmp, 0, &lcfg->lcfg_num);
+               if (rc)
+                       GOTO(out_rec_free, rc);
+       } else {
+               lcfg->lcfg_num = 0;
+       }
+
        /* truncate the comment to the parameter name */
        ptr = tmp - 1;
        sep = *ptr;
@@ -3097,6 +3399,7 @@ static int mgs_write_log_sys(const struct lu_env *env,
                }
        }
        *ptr = sep;
+out_rec_free:
        lustre_cfg_rec_free(lcr);
        return rc;
 }
@@ -3510,6 +3813,79 @@ out:
         RETURN(rc);
 }
 
+static int mgs_write_log_param2(const struct lu_env *env,
+                               struct mgs_device *mgs,
+                               struct fs_db *fsdb,
+                               struct mgs_target_info *mti, char *ptr)
+{
+       struct lustre_cfg_bufs bufs;
+       int rc;
+
+       ENTRY;
+       CDEBUG(D_MGS, "next param '%s'\n", ptr);
+
+       /* PARAM_MGSNODE and PARAM_NETWORK are set only when formating
+        * or during the inital mount. It can never change after that.
+        */
+       if (!class_match_param(ptr, PARAM_MGSNODE, NULL) ||
+           !class_match_param(ptr, PARAM_NETWORK, NULL)) {
+               rc = 0;
+               goto end;
+       }
+
+       /* Processed in mgs_write_log_ost. Another value that can't
+        * be changed by lctl set_param -P.
+        */
+       if (!class_match_param(ptr, PARAM_FAILMODE, NULL)) {
+               LCONSOLE_ERROR_MSG(0x169,
+                                  "%s can only be changed with tunefs.lustre and --writeconf\n",
+                                  ptr);
+               rc = -EPERM;
+               goto end;
+       }
+
+       /* FIXME !!! Support for sptlrpc is incomplete. Currently the change
+        * doesn't transmit to the client. See LU-7183.
+        */
+       if (!class_match_param(ptr, PARAM_SRPC, NULL)) {
+               rc = mgs_srpc_set_param(env, mgs, fsdb, mti, ptr);
+               goto end;
+       }
+
+       /* Can't use class_match_param since ptr doesn't start with
+        * PARAM_FAILNODE. So we look for PARAM_FAILNODE contained in ptr.
+        */
+       if (strstr(ptr, PARAM_FAILNODE)) {
+               /* Add a failover nidlist. We already processed failovers
+                * params for new targets in mgs_write_log_target.
+                */
+               const char *param;
+
+               /* can't use wildcards with failover.node */
+               if (strchr(ptr, '*')) {
+                       rc = -ENODEV;
+                       goto end;
+               }
+
+               param = strstr(ptr, PARAM_FAILNODE);
+               if (strlcpy(mti->mti_params, param, sizeof(mti->mti_params)) >=
+                   sizeof(mti->mti_params)) {
+                       rc = -E2BIG;
+                       goto end;
+               }
+
+               CDEBUG(D_MGS, "Adding failnode with param %s\n",
+                      mti->mti_params);
+               rc = mgs_write_log_add_failnid(env, mgs, fsdb, mti);
+               goto end;
+       }
+
+       rc = mgs_wlp_lcfg(env, mgs, fsdb, mti, PARAMS_FILENAME, &bufs,
+                         mti->mti_svname, ptr);
+end:
+       RETURN(rc);
+}
+
 /* Permanent settings of all parameters by writing into the appropriate
  * configuration logs.
  * A parameter with null value ("<param>='\0'") means to erase it out of
@@ -3540,16 +3916,16 @@ static int mgs_write_log_param(const struct lu_env *env,
        if (class_match_param(ptr, PARAM_NETWORK, NULL) == 0)
                GOTO(end, rc);
 
-        /* Processed in mgs_write_log_ost */
-        if (class_match_param(ptr, PARAM_FAILMODE, NULL) == 0) {
-                if (mti->mti_flags & LDD_F_PARAM) {
-                        LCONSOLE_ERROR_MSG(0x169, "%s can only be "
-                                           "changed with tunefs.lustre"
-                                           "and --writeconf\n", ptr);
-                        rc = -EPERM;
-                }
-                GOTO(end, rc);
-        }
+       /* Processed in mgs_write_log_ost */
+       if (class_match_param(ptr, PARAM_FAILMODE, NULL) == 0) {
+               if (mti->mti_flags & LDD_F_PARAM) {
+                       LCONSOLE_ERROR_MSG(0x169,
+                                          "%s can only be changed with tunefs.lustre and --writeconf\n",
+                                          ptr);
+                       rc = -EPERM;
+               }
+               GOTO(end, rc);
+       }
 
         if (class_match_param(ptr, PARAM_SRPC, NULL) == 0) {
                rc = mgs_srpc_set_param(env, mgs, fsdb, mti, ptr);
@@ -3632,18 +4008,12 @@ static int mgs_write_log_param(const struct lu_env *env,
                }
 active_err:
                if (rc < 0) {
-                       LCONSOLE_ERROR_MSG(0x145, "Couldn't find %s in"
-                                          "log (%d). No permanent "
-                                          "changes were made to the "
-                                          "config log.\n",
+                       LCONSOLE_ERROR_MSG(0x145,
+                                          "Couldn't find %s in log (%d). No permanent changes were made to the config log.\n",
                                           mti->mti_svname, rc);
                        if (test_bit(FSDB_OLDLOG14, &fsdb->fsdb_flags))
-                               LCONSOLE_ERROR_MSG(0x146, "This may be"
-                                                  " because the log"
-                                                  "is in the old 1.4"
-                                                  "style. Consider "
-                                                  " --writeconf to "
-                                                  "update the logs.\n");
+                               LCONSOLE_ERROR_MSG(0x146,
+                                                  "This may be because the log is in the old 1.4 style. Consider --writeconf to update the logs.\n");
                        GOTO(end, rc);
                }
                /* Fall through to osc/mdc proc for deactivating live
@@ -3925,6 +4295,7 @@ active_err:
 
        /* All mdd., ost. and osd. params in proc */
        if ((class_match_param(ptr, PARAM_MDD, NULL) == 0) ||
+           (class_match_param(ptr, PARAM_LOD, NULL) == 0) ||
            (class_match_param(ptr, PARAM_OST, NULL) == 0) ||
            (class_match_param(ptr, PARAM_OSD, NULL) == 0)) {
                CDEBUG(D_MGS, "%.3s param %s\n", ptr, ptr + 4);
@@ -3975,27 +4346,26 @@ int mgs_write_log_target(const struct lu_env *env, struct mgs_device *mgs,
 
        mutex_lock(&fsdb->fsdb_mutex);
 
-        if (mti->mti_flags &
-            (LDD_F_VIRGIN | LDD_F_UPGRADE14 | LDD_F_WRITECONF)) {
-                /* Generate a log from scratch */
-                if (mti->mti_flags & LDD_F_SV_TYPE_MDT) {
+       if (mti->mti_flags & (LDD_F_VIRGIN | LDD_F_WRITECONF)) {
+               /* Generate a log from scratch */
+               if (mti->mti_flags & LDD_F_SV_TYPE_MDT) {
                        rc = mgs_write_log_mdt(env, mgs, fsdb, mti);
-                } else if (mti->mti_flags & LDD_F_SV_TYPE_OST) {
+               } else if (mti->mti_flags & LDD_F_SV_TYPE_OST) {
                        rc = mgs_write_log_ost(env, mgs, fsdb, mti);
-                } else {
-                        CERROR("Unknown target type %#x, can't create log for "
-                               "%s\n", mti->mti_flags, mti->mti_svname);
-                }
-                if (rc) {
-                        CERROR("Can't write logs for %s (%d)\n",
-                               mti->mti_svname, rc);
-                        GOTO(out_up, rc);
-                }
-        } else {
-                /* Just update the params from tunefs in mgs_write_log_params */
-                CDEBUG(D_MGS, "Update params for %s\n", mti->mti_svname);
-                mti->mti_flags |= LDD_F_PARAM;
-        }
+               } else {
+                       CERROR("Unknown target type %#x, can't create log for %s\n",
+                              mti->mti_flags, mti->mti_svname);
+               }
+               if (rc) {
+                       CERROR("Can't write logs for %s (%d)\n",
+                              mti->mti_svname, rc);
+                       GOTO(out_up, rc);
+               }
+       } else {
+               /* Just update the params from tunefs in mgs_write_log_params */
+               CDEBUG(D_MGS, "Update params for %s\n", mti->mti_svname);
+               mti->mti_flags |= LDD_F_PARAM;
+       }
 
         /* allocate temporary buffer, where class_get_next_param will
            make copy of a current  parameter */
@@ -4128,8 +4498,8 @@ int mgs_list_logs(const struct lu_env *env, struct mgs_device *mgs,
                list_del_init(&dirent->mde_list);
                suffix = strrchr(dirent->mde_name, '-');
                if (suffix != NULL) {
-                       l = snprintf(out, remains, "config_log: %s\n",
-                                    dirent->mde_name);
+                       l = scnprintf(out, remains, "config_log: %s\n",
+                                     dirent->mde_name);
                        out += l;
                        remains -= l;
                }
@@ -4332,6 +4702,7 @@ static int mgs_lcfg_fork_handler(const struct lu_env *env,
                        } /* else case fall through */
                } /* else case fall through */
        }
+       /* fallthrough */
        default: {
                for (i = 1; i < cnt; i++) {
                        o_buflen = o_lcfg->lcfg_buflens[i];
@@ -4680,30 +5051,6 @@ next:
        RETURN(rc);
 }
 
-/* from llog_swab */
-static void print_lustre_cfg(struct lustre_cfg *lcfg)
-{
-        int i;
-        ENTRY;
-
-        CDEBUG(D_MGS, "lustre_cfg: %p\n", lcfg);
-        CDEBUG(D_MGS, "\tlcfg->lcfg_version: %#x\n", lcfg->lcfg_version);
-
-        CDEBUG(D_MGS, "\tlcfg->lcfg_command: %#x\n", lcfg->lcfg_command);
-        CDEBUG(D_MGS, "\tlcfg->lcfg_num: %#x\n", lcfg->lcfg_num);
-        CDEBUG(D_MGS, "\tlcfg->lcfg_flags: %#x\n", lcfg->lcfg_flags);
-        CDEBUG(D_MGS, "\tlcfg->lcfg_nid: %s\n", libcfs_nid2str(lcfg->lcfg_nid));
-
-        CDEBUG(D_MGS, "\tlcfg->lcfg_bufcount: %d\n", lcfg->lcfg_bufcount);
-        if (lcfg->lcfg_bufcount < LUSTRE_CFG_MAX_BUFCOUNT)
-                for (i = 0; i < lcfg->lcfg_bufcount; i++) {
-                        CDEBUG(D_MGS, "\tlcfg->lcfg_buflens[%d]: %d %s\n",
-                               i, lcfg->lcfg_buflens[i],
-                               lustre_cfg_string(lcfg, i));
-                }
-        EXIT;
-}
-
 /* Setup _mgs fsdb and log
  */
 int mgs__mgs_fsdb_setup(const struct lu_env *env, struct mgs_device *mgs)
@@ -4751,123 +5098,273 @@ int mgs_params_fsdb_cleanup(const struct lu_env *env, struct mgs_device *mgs)
        return rc == -ENOENT ? 0 : rc;
 }
 
-/* Set a permanent (config log) param for a target or fs
- * \param lcfg buf0 may contain the device (testfs-MDT0000) name
- *             buf1 contains the single parameter
- */
-int mgs_setparam(const struct lu_env *env, struct mgs_device *mgs,
-                struct lustre_cfg *lcfg, char *fsname)
+/**
+ * Fill in the mgs_target_info based on data devname and param provide.
+ *
+ * @env                thread context
+ * @mgs                mgs device
+ * @mti                mgs target info. We want to set this based other paramters
+ *             passed to this function. Once setup we write it to the config
+ *             logs.
+ * @devname    optional OBD device name
+ * @param      string that contains both what tunable to set and the value to
+ *             set it to.
+ *
+ * RETURN      0 for success
+ *             negative error number on failure
+ **/
+static int mgs_set_conf_param(const struct lu_env *env, struct mgs_device *mgs,
+                             struct mgs_target_info *mti, const char *devname,
+                             const char *param)
 {
        struct fs_db *fsdb = NULL;
-       struct mgs_target_info *mti = NULL;
-       char *devname, *param;
-       char *ptr;
-       const char *tmp;
-       __u32 index;
+       int dev_type;
        int rc = 0;
-       bool free = false;
+
        ENTRY;
+       /* lustre, lustre-mdtlov, lustre-client, lustre-MDT0000 */
+       if (!devname) {
+               size_t len;
+
+               /* We have two possible cases here:
+                *
+                * 1) the device name embedded in the param:
+                *    lustre-OST0000.osc.max_dirty_mb=32
+                *
+                * 2) the file system name is embedded in
+                *    the param: lustre.sys.at.min=0
+                */
+               len = strcspn(param, ".=");
+               if (!len || param[len] == '=')
+                       RETURN(-EINVAL);
 
-        print_lustre_cfg(lcfg);
+               if (len >= sizeof(mti->mti_svname))
+                       RETURN(-E2BIG);
 
-        /* lustre, lustre-mdtlov, lustre-client, lustre-MDT0000 */
-        devname = lustre_cfg_string(lcfg, 0);
-        param = lustre_cfg_string(lcfg, 1);
-        if (!devname) {
-                /* Assume device name embedded in param:
-                   lustre-OST0000.osc.max_dirty_mb=32 */
-                ptr = strchr(param, '.');
-                if (ptr) {
-                        devname = param;
-                        *ptr = 0;
-                        param = ptr + 1;
-                }
-        }
-        if (!devname) {
-                LCONSOLE_ERROR_MSG(0x14d, "No target specified: %s\n", param);
-                RETURN(-ENOSYS);
-        }
+               snprintf(mti->mti_svname, sizeof(mti->mti_svname),
+                        "%.*s", (int)len, param);
+               param += len + 1;
+       } else {
+               if (strlcpy(mti->mti_svname, devname, sizeof(mti->mti_svname)) >=
+                   sizeof(mti->mti_svname))
+                       RETURN(-E2BIG);
+       }
 
-       rc = mgs_parse_devname(devname, fsname, NULL);
-       if (rc == 0 && !mgs_parse_devname(devname, NULL, &index)) {
-                /* param related to llite isn't allowed to set by OST or MDT */
-               if (rc == 0 && strncmp(param, PARAM_LLITE,
-                                      sizeof(PARAM_LLITE) - 1) == 0)
-                        RETURN(-EINVAL);
-        } else {
-                /* assume devname is the fsname */
-               strlcpy(fsname, devname, MTI_NAME_MAXLEN);
-        }
-        CDEBUG(D_MGS, "setparam fs='%s' device='%s'\n", fsname, devname);
+       if (!strlen(mti->mti_svname)) {
+               LCONSOLE_ERROR_MSG(0x14d, "No target specified: %s\n", param);
+               RETURN(-ENOSYS);
+       }
+
+       dev_type = mgs_parse_devname(mti->mti_svname, mti->mti_fsname,
+                                    &mti->mti_stripe_index);
+       switch (dev_type) {
+       /* For this case we have an invalid obd device name */
+       case -ENXIO:
+               CDEBUG(D_MGS, "%s don't contain an index\n", mti->mti_svname);
+               strlcpy(mti->mti_fsname, mti->mti_svname, MTI_NAME_MAXLEN);
+               dev_type = 0;
+               break;
+       /* Not an obd device, assume devname is the fsname.
+        * User might of only provided fsname and not obd device
+        */
+       case -EINVAL:
+               CDEBUG(D_MGS, "%s is seen as a file system name\n", mti->mti_svname);
+               strlcpy(mti->mti_fsname, mti->mti_svname, MTI_NAME_MAXLEN);
+               dev_type = 0;
+               break;
+       default:
+               if (dev_type < 0)
+                       GOTO(out, rc = dev_type);
+
+               /* param related to llite isn't allowed to set by OST or MDT */
+               if (dev_type & LDD_F_SV_TYPE_OST ||
+                   dev_type & LDD_F_SV_TYPE_MDT) {
+                       /* param related to llite isn't allowed to set by OST
+                        * or MDT
+                        */
+                       if (!strncmp(param, PARAM_LLITE,
+                                    sizeof(PARAM_LLITE) - 1))
+                               GOTO(out, rc = -EINVAL);
+
+                       /* Strip -osc or -mdc suffix from svname */
+                       if (server_make_name(dev_type, mti->mti_stripe_index,
+                                            mti->mti_fsname, mti->mti_svname,
+                                            sizeof(mti->mti_svname)))
+                               GOTO(out, rc = -EINVAL);
+               }
+               break;
+       }
+
+       if (strlcpy(mti->mti_params, param, sizeof(mti->mti_params)) >=
+           sizeof(mti->mti_params))
+               GOTO(out, rc = -E2BIG);
+
+       CDEBUG(D_MGS, "set_conf_param fs='%s' device='%s' param='%s'\n",
+              mti->mti_fsname, mti->mti_svname, mti->mti_params);
 
-       rc = mgs_find_or_make_fsdb(env, mgs,
-                                  lcfg->lcfg_command == LCFG_SET_PARAM ?
-                                  PARAMS_FILENAME : fsname, &fsdb);
+       rc = mgs_find_or_make_fsdb(env, mgs, mti->mti_fsname, &fsdb);
        if (rc)
-               RETURN(rc);
+               GOTO(out, rc);
 
-       if (lcfg->lcfg_command != LCFG_SET_PARAM &&
-           !test_bit(FSDB_MGS_SELF, &fsdb->fsdb_flags) &&
+       if (!test_bit(FSDB_MGS_SELF, &fsdb->fsdb_flags) &&
            test_bit(FSDB_LOG_EMPTY, &fsdb->fsdb_flags)) {
                CERROR("No filesystem targets for %s. cfg_device from lctl "
-                      "is '%s'\n", fsname, devname);
-               free = true;
+                      "is '%s'\n", mti->mti_fsname, mti->mti_svname);
+               mgs_unlink_fsdb(mgs, fsdb);
                GOTO(out, rc = -EINVAL);
        }
 
-       /* Create a fake mti to hold everything */
-       OBD_ALLOC_PTR(mti);
-       if (!mti)
-               GOTO(out, rc = -ENOMEM);
-       if (strlcpy(mti->mti_fsname, fsname, sizeof(mti->mti_fsname))
-           >= sizeof(mti->mti_fsname))
-               GOTO(out, rc = -E2BIG);
-       if (strlcpy(mti->mti_svname, devname, sizeof(mti->mti_svname))
-           >= sizeof(mti->mti_svname))
-               GOTO(out, rc = -E2BIG);
-       if (strlcpy(mti->mti_params, param, sizeof(mti->mti_params))
-           >= sizeof(mti->mti_params))
-               GOTO(out, rc = -E2BIG);
-        rc = server_name2index(mti->mti_svname, &mti->mti_stripe_index, &tmp);
-        if (rc < 0)
-                /* Not a valid server; may be only fsname */
-                rc = 0;
-        else
-                /* Strip -osc or -mdc suffix from svname */
-                if (server_make_name(rc, mti->mti_stripe_index, mti->mti_fsname,
-                                    mti->mti_svname, sizeof(mti->mti_svname)))
-                        GOTO(out, rc = -EINVAL);
        /*
         * Revoke lock so everyone updates.  Should be alright if
         * someone was already reading while we were updating the logs,
         * so we don't really need to hold the lock while we're
         * writing (above).
         */
-       if (lcfg->lcfg_command == LCFG_SET_PARAM) {
-               mti->mti_flags = rc | LDD_F_PARAM2;
-               mutex_lock(&fsdb->fsdb_mutex);
-               rc = mgs_write_log_param2(env, mgs, fsdb, mti, mti->mti_params);
-               mutex_unlock(&fsdb->fsdb_mutex);
-               mgs_revoke_lock(mgs, fsdb, CONFIG_T_PARAMS);
+       mti->mti_flags = dev_type | LDD_F_PARAM;
+       mutex_lock(&fsdb->fsdb_mutex);
+       rc = mgs_write_log_param(env, mgs, fsdb, mti, mti->mti_params);
+       mutex_unlock(&fsdb->fsdb_mutex);
+       mgs_revoke_lock(mgs, fsdb, CONFIG_T_CONFIG);
+
+out:
+       if (fsdb)
+               mgs_put_fsdb(mgs, fsdb);
+
+       RETURN(rc);
+}
+
+static int mgs_set_param2(const struct lu_env *env, struct mgs_device *mgs,
+                         struct mgs_target_info *mti, const char *param)
+{
+       struct fs_db *fsdb = NULL;
+       int dev_type;
+       size_t len;
+       int rc;
+
+       if (strlcpy(mti->mti_params, param, sizeof(mti->mti_params)) >=
+           sizeof(mti->mti_params))
+               GOTO(out, rc = -E2BIG);
+
+       len = strcspn(param, ".=");
+       if (len && param[len] != '=') {
+               struct list_head *tmp;
+               char *ptr;
+
+               param += len + 1;
+               ptr = strchr(param, '.');
+
+               len = strlen(param);
+               if (ptr)
+                       len -= strlen(ptr);
+               if (len >= sizeof(mti->mti_svname))
+                       GOTO(out, rc = -E2BIG);
+
+               snprintf(mti->mti_svname, sizeof(mti->mti_svname), "%.*s",
+                       (int)len, param);
+
+               mutex_lock(&mgs->mgs_mutex);
+               if (unlikely(list_empty(&mgs->mgs_fs_db_list))) {
+                       mutex_unlock(&mgs->mgs_mutex);
+                       GOTO(out, rc = -ENODEV);
+               }
+
+               list_for_each(tmp, &mgs->mgs_fs_db_list) {
+                       fsdb = list_entry(tmp, struct fs_db, fsdb_list);
+                       if (fsdb->fsdb_has_lproc_entry &&
+                           strcmp(fsdb->fsdb_name, "params") != 0 &&
+                           strstr(param, fsdb->fsdb_name)) {
+                               snprintf(mti->mti_svname,
+                                        sizeof(mti->mti_svname), "%s",
+                                        fsdb->fsdb_name);
+                               break;
+                       }
+                       fsdb = NULL;
+               }
+
+               if (!fsdb) {
+                       snprintf(mti->mti_svname, sizeof(mti->mti_svname),
+                                "general");
+               }
+               mutex_unlock(&mgs->mgs_mutex);
        } else {
-               mti->mti_flags = rc | LDD_F_PARAM;
-               mutex_lock(&fsdb->fsdb_mutex);
-               rc = mgs_write_log_param(env, mgs, fsdb, mti, mti->mti_params);
-               mutex_unlock(&fsdb->fsdb_mutex);
-               mgs_revoke_lock(mgs, fsdb, CONFIG_T_CONFIG);
+               snprintf(mti->mti_svname, sizeof(mti->mti_svname), "general");
        }
 
+       CDEBUG(D_MGS, "set_param2 fs='%s' device='%s' param='%s'\n",
+              mti->mti_fsname, mti->mti_svname, mti->mti_params);
+
+       /* The return value should be the device type i.e LDD_F_SV_TYPE_XXX.
+        * A returned error tells us we don't have a target obd device.
+        */
+       dev_type = server_name2index(mti->mti_svname, &mti->mti_stripe_index,
+                                    NULL);
+       if (dev_type < 0)
+               dev_type = 0;
+
+       /* the return value should be the device type i.e LDD_F_SV_TYPE_XXX.
+        * Strip -osc or -mdc suffix from svname
+        */
+       if ((dev_type & LDD_F_SV_TYPE_OST || dev_type & LDD_F_SV_TYPE_MDT) &&
+           server_make_name(dev_type, mti->mti_stripe_index,
+                            mti->mti_fsname, mti->mti_svname,
+                            sizeof(mti->mti_svname)))
+               GOTO(out, rc = -EINVAL);
+
+       rc = mgs_find_or_make_fsdb(env, mgs, PARAMS_FILENAME, &fsdb);
+       if (rc)
+               GOTO(out, rc);
+       /*
+        * Revoke lock so everyone updates.  Should be alright if
+        * someone was already reading while we were updating the logs,
+        * so we don't really need to hold the lock while we're
+        * writing (above).
+        */
+       mti->mti_flags = dev_type | LDD_F_PARAM2;
+       mutex_lock(&fsdb->fsdb_mutex);
+       rc = mgs_write_log_param2(env, mgs, fsdb, mti, mti->mti_params);
+       mutex_unlock(&fsdb->fsdb_mutex);
+       mgs_revoke_lock(mgs, fsdb, CONFIG_T_PARAMS);
+       mgs_put_fsdb(mgs, fsdb);
 out:
-       if (mti)
-               OBD_FREE_PTR(mti);
+       RETURN(rc);
+}
 
-       if (fsdb) {
-               if (free)
-                       mgs_unlink_fsdb(mgs, fsdb);
-               mgs_put_fsdb(mgs, fsdb);
+/* Set a permanent (config log) param for a target or fs
+ *
+ * @lcfg buf0 may contain the device (testfs-MDT0000) name
+ *       buf1 contains the single parameter
+ */
+int mgs_set_param(const struct lu_env *env, struct mgs_device *mgs,
+                 struct lustre_cfg *lcfg)
+{
+       const char *param = lustre_cfg_string(lcfg, 1);
+       struct mgs_target_info *mti;
+       int rc;
+
+       /* Create a fake mti to hold everything */
+       OBD_ALLOC_PTR(mti);
+       if (!mti)
+               return -ENOMEM;
+
+       print_lustre_cfg(lcfg);
+
+       if (lcfg->lcfg_command == LCFG_PARAM) {
+               /* For the case of lctl conf_param devname can be
+                * lustre, lustre-mdtlov, lustre-client, lustre-MDT0000
+                */
+               const char *devname = lustre_cfg_string(lcfg, 0);
+
+               rc = mgs_set_conf_param(env, mgs, mti, devname, param);
+       } else {
+               /* In the case of lctl set_param -P lcfg[0] will always
+                * be 'general'. At least for now.
+                */
+               rc = mgs_set_param2(env, mgs, mti, param);
        }
 
-       RETURN(rc);
+       OBD_FREE_PTR(mti);
+
+       return rc;
 }
 
 static int mgs_write_log_pool(const struct lu_env *env,
@@ -4900,13 +5397,13 @@ int mgs_nodemap_cmd(const struct lu_env *env, struct mgs_device *mgs,
                    enum lcfg_command_type cmd, const char *nodemap_name,
                    char *param)
 {
-       lnet_nid_t      nid[2];
-       __u32           idmap[2];
-       bool            bool_switch;
-       __u32           int_id;
-       int             rc = 0;
-       ENTRY;
+       lnet_nid_t nid[2];
+       u32 idmap[2];
+       bool bool_switch;
+       u32 int_id;
+       int rc = 0;
 
+       ENTRY;
        switch (cmd) {
        case LCFG_NODEMAP_ADD:
                rc = nodemap_add(nodemap_name);
@@ -4927,13 +5424,22 @@ int mgs_nodemap_cmd(const struct lu_env *env, struct mgs_device *mgs,
                rc = nodemap_del_range(nodemap_name, nid);
                break;
        case LCFG_NODEMAP_ADMIN:
-               bool_switch = simple_strtoul(param, NULL, 10);
+               rc = kstrtobool(param, &bool_switch);
+               if (rc)
+                       break;
                rc = nodemap_set_allow_root(nodemap_name, bool_switch);
                break;
        case LCFG_NODEMAP_DENY_UNKNOWN:
-               bool_switch = simple_strtoul(param, NULL, 10);
+               rc = kstrtobool(param, &bool_switch);
+               if (rc)
+                       break;
                rc = nodemap_set_deny_unknown(nodemap_name, bool_switch);
                break;
+       case LCFG_NODEMAP_AUDIT_MODE:
+               rc = kstrtoul(param, 10, (unsigned long *)&bool_switch);
+               if (rc == 0)
+                       rc = nodemap_set_audit_mode(nodemap_name, bool_switch);
+               break;
        case LCFG_NODEMAP_MAP_MODE:
                if (strcmp("both", param) == 0)
                        rc = nodemap_set_mapping_mode(nodemap_name,
@@ -4948,15 +5454,21 @@ int mgs_nodemap_cmd(const struct lu_env *env, struct mgs_device *mgs,
                        rc = -EINVAL;
                break;
        case LCFG_NODEMAP_TRUSTED:
-               bool_switch = simple_strtoul(param, NULL, 10);
+               rc = kstrtobool(param, &bool_switch);
+               if (rc)
+                       break;
                rc = nodemap_set_trust_client_ids(nodemap_name, bool_switch);
                break;
        case LCFG_NODEMAP_SQUASH_UID:
-               int_id = simple_strtoul(param, NULL, 10);
+               rc = kstrtouint(param, 10, &int_id);
+               if (rc)
+                       break;
                rc = nodemap_set_squash_uid(nodemap_name, int_id);
                break;
        case LCFG_NODEMAP_SQUASH_GID:
-               int_id = simple_strtoul(param, NULL, 10);
+               rc = kstrtouint(param, 10, &int_id);
+               if (rc)
+                       break;
                rc = nodemap_set_squash_gid(nodemap_name, int_id);
                break;
        case LCFG_NODEMAP_ADD_UIDMAP:
@@ -4986,6 +5498,9 @@ int mgs_nodemap_cmd(const struct lu_env *env, struct mgs_device *mgs,
        case LCFG_NODEMAP_SET_FILESET:
                rc = nodemap_set_fileset(nodemap_name, param);
                break;
+       case LCFG_NODEMAP_SET_SEPOL:
+               rc = nodemap_set_sepol(nodemap_name, param);
+               break;
        default:
                rc = -EINVAL;
        }