Whamcloud - gitweb
LU-8727 mgs: remove skip records from config file 45/34045/4
authorVladimir Saveliev <c17830@cray.com>
Mon, 19 Feb 2018 13:14:28 +0000 (16:14 +0300)
committerOleg Drokin <green@whamcloud.com>
Sat, 23 Feb 2019 05:10:08 +0000 (05:10 +0000)
Configuration logs are append-only files of limited size.  Over the
course of time the logs may grow over the limit size.  Usually,
configuration logs keep needless records marked as SKIP. The new lctl
command "clear_conf" is added to allow administartors to clear
configuration files by removing mentioned SKIP records. lctl man page
is updated.
conf-sanity test (for ldiskfs only) is added to test the new command.

Lustre-change: https://review.whamcloud.com/23245
Lustre-commit: 2a9518b1f820f833cbfcff42c6606413a1f5d3e7

Change-Id: I274cb48138c16e536cfca56836c3313e944eba56
Signed-off-by: Vladimir Saveliev <c17830@cray.com>
Signed-off-by: Arshad Hussain <arshad.super@gmail.com>
Cray-bug-id: MRP-2091
Reviewed-by: Artem Blagodarenko <c17828@cray.com>
Reviewed-by: Alexey Leonidovich Lyashkov <c17817@cray.com>
Tested-by: Elena V. Gryaznova <c17455@cray.com>
Signed-off-by: Minh Diep <mdiep@whamcloud.com>
Reviewed-on: https://review.whamcloud.com/34045
Tested-by: Jenkins
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Alexey Lyashkov <c17817@cray.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/doc/lctl.8
lustre/include/uapi/linux/lustre_ioctl.h
lustre/mgs/mgs_handler.c
lustre/mgs/mgs_internal.h
lustre/mgs/mgs_llog.c
lustre/tests/conf-sanity.sh
lustre/utils/lctl.c
lustre/utils/obd.c
lustre/utils/obdctl.h

index bfb7949..5a8bea2 100644 (file)
@@ -355,7 +355,16 @@ Delete an existing UID or GID mapping from a nodemap.
 .RS 4
 Modify a nodemap property.
 .RE
-
+.SS Configuration logs
+.TP
+.BI clear_conf " <device|fsname>"
+This command runs on MGS node having MGS device mounted with -o
+nosvc. It cleans up configuration files stored in the CONFIGS/ directory
+of any records marked SKIP. If the device name is given, then the
+specific logs for that filesystem (e.g. testfs-MDT0000) is processed.
+Otherwise, if a filesystem name is given then all configuration files for the
+specified filesystem are cleared.
+.PP
 .SS LFSCK
 An on-line Lustre consistency check and repair tool. It is used for totally
 replacing the old lfsck tool for kinds of Lustre inconsistency verification,
index cb4ec46..9fddf2b 100644 (file)
@@ -217,6 +217,7 @@ static inline __u32 obd_ioctl_packlen(struct obd_ioctl_data *data)
 #define OBD_IOC_LLOG_CHECK     _IOWR('f', 195, OBD_IOC_DATA_TYPE)
 /*     OBD_IOC_LLOG_CATINFO    _IOWR('f', 196, OBD_IOC_DATA_TYPE) */
 #define OBD_IOC_NODEMAP                _IOWR('f', 197, OBD_IOC_DATA_TYPE)
+#define OBD_IOC_CLEAR_CONFIGS   _IOWR('f', 198, OBD_IOC_DATA_TYPE)
 
 /*     ECHO_IOC_GET_STRIPE     _IOWR('f', 200, OBD_IOC_DATA_TYPE) */
 /*     ECHO_IOC_SET_STRIPE     _IOWR('f', 201, OBD_IOC_DATA_TYPE) */
index 46c0720..99c4f73 100644 (file)
@@ -1045,32 +1045,37 @@ out_free:
 
        case OBD_IOC_REPLACE_NIDS: {
                if (!data->ioc_inllen1 || !data->ioc_inlbuf1) {
-                       CERROR("No device name specified!\n");
                        rc = -EINVAL;
+                       CERROR("%s: no device or fsname specified: rc = %d\n",
+                              exp->exp_obd->obd_name, rc);
                        break;
                }
 
-               if (data->ioc_inlbuf1[data->ioc_inllen1 - 1] != 0) {
-                       CERROR("Device name is not NUL terminated!\n");
-                       rc = -EINVAL;
+               if (data->ioc_inllen1 > MTI_NAME_MAXLEN) {
+                       rc = -EOVERFLOW;
+                       CERROR("%s: device or fsname is too long: rc = %d\n",
+                              exp->exp_obd->obd_name, rc);
                        break;
                }
 
-               if (data->ioc_plen1 > MTI_NAME_MAXLEN) {
-                       CERROR("Device name is too long\n");
-                       rc = -EOVERFLOW;
+               if (data->ioc_inlbuf1[data->ioc_inllen1 - 1] != 0) {
+                       rc = -EINVAL;
+                       CERROR("%s: device or fsname is not NUL terminated: "
+                              "rc = %d\n", exp->exp_obd->obd_name, rc);
                        break;
                }
 
                if (!data->ioc_inllen2 || !data->ioc_inlbuf2) {
-                       CERROR("No NIDs were specified!\n");
                        rc = -EINVAL;
+                       CERROR("%s: no NIDs specified: rc = %d\n",
+                              exp->exp_obd->obd_name, rc);
                        break;
                }
 
                if (data->ioc_inlbuf2[data->ioc_inllen2 - 1] != 0) {
-                       CERROR("NID list is not NUL terminated!\n");
                        rc = -EINVAL;
+                       CERROR("%s: NID list is not NUL terminated: "
+                              "rc = %d\n", exp->exp_obd->obd_name, rc);
                        break;
                }
 
@@ -1084,6 +1089,37 @@ out_free:
                break;
        }
 
+       case OBD_IOC_CLEAR_CONFIGS: {
+               if (!data->ioc_inllen1 || !data->ioc_inlbuf1) {
+                       rc = -EINVAL;
+                       CERROR("%s: no device or fsname specified: rc = %d\n",
+                              exp->exp_obd->obd_name, rc);
+                       break;
+               }
+
+               if (data->ioc_inllen1 > MTI_NAME_MAXLEN) {
+                       rc = -EOVERFLOW;
+                       CERROR("%s: device or fsname is too long: rc = %d\n",
+                              exp->exp_obd->obd_name, rc);
+                       break;
+               }
+
+               if (data->ioc_inlbuf1[data->ioc_inllen1 - 1] != 0) {
+                       rc = -EINVAL;
+                       CERROR("%s: device or fsname is not NUL terminated: "
+                              "rc = %d\n", exp->exp_obd->obd_name, rc);
+                       break;
+               }
+
+               /* remove records marked SKIP from config logs */
+               rc = mgs_clear_configs(&env, mgs, data->ioc_inlbuf1);
+               if (rc)
+                       CERROR("%s: error clearing config log: rc = %d\n",
+                              exp->exp_obd->obd_name, rc);
+
+               break;
+       }
+
        case OBD_IOC_POOL:
                rc = mgs_iocontrol_pool(&env, mgs, data);
                break;
index 5eb9ea7..7c0c5d2 100644 (file)
@@ -214,6 +214,8 @@ int mgs_write_log_target(const struct lu_env *env, struct mgs_device *mgs,
                         struct mgs_target_info *mti, struct fs_db *fsdb);
 int mgs_replace_nids(const struct lu_env *env, struct mgs_device *mgs,
                     char *devname, char *nids);
+int mgs_clear_configs(const struct lu_env *env, struct mgs_device *mgs,
+                     const char *devname);
 int mgs_erase_log(const struct lu_env *env, struct mgs_device *mgs,
                  char *name);
 int mgs_erase_logs(const struct lu_env *env, struct mgs_device *mgs,
index d9d110c..0e1c958 100644 (file)
@@ -46,6 +46,7 @@
 #include <uapi/linux/lustre_param.h>
 #include <lustre_sec.h>
 #include <lustre_quota.h>
+#include <lustre_sec.h>
 
 #include "mgs_internal.h"
 
@@ -969,7 +970,7 @@ out_pop:
 }
 
 /** 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 */
@@ -987,13 +988,13 @@ 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;
 
@@ -1005,24 +1006,24 @@ static int check_markers(struct lustre_cfg *lcfg,
                   and can be restored if needed */
                if ((marker->cm_flags & (CM_EXCLUDE | CM_START)) ==
                    (CM_EXCLUDE | CM_START)) {
-                       mrul->skip_it = 1;
+                       mrd->skip_it = 1;
                        return 1;
                }
 
                if ((marker->cm_flags & (CM_EXCLUDE | CM_END)) ==
                    (CM_EXCLUDE | CM_END)) {
-                       mrul->skip_it = 0;
+                       mrd->skip_it = 0;
                        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->in_target_device = 1;
+                               mrd->device_nids_added = 0;
                        } else if (marker->cm_flags & CM_END)
-                               mrul->in_target_device = 0;
+                               mrd->in_target_device = 0;
                }
        }
 
@@ -1103,7 +1104,7 @@ 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;
@@ -1113,15 +1114,15 @@ static int process_command(const struct lu_env *env, struct lustre_cfg *lcfg,
        if (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) {
                        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->target.mti_svname);
                        rc = record_add_uuid(env,
-                                            mrul->temp_llh, nid,
-                                            mrul->target.mti_params);
+                                            mrd->temp_llh, nid,
+                                            mrd->target.mti_params);
                        if (!rc)
                                nids_added++;
                }
@@ -1129,27 +1130,27 @@ static int process_command(const struct lu_env *env, struct lustre_cfg *lcfg,
                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);
+                              mrd->target.mti_params,
+                              mrd->target.mti_svname);
                        RETURN(-ENXIO);
                } else {
-                       mrul->device_nids_added = 1;
+                       mrd->device_nids_added = 1;
                }
 
                return nids_added;
        }
 
-       if (mrul->device_nids_added && lcfg->lcfg_command == LCFG_SETUP) {
+       if (mrd->device_nids_added && 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->target.mti_params,
                                  /* s3 is not changed */
                                  lustre_cfg_string(lcfg, 3),
                                  /* s4 is not changed */
@@ -1167,22 +1168,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",
@@ -1198,23 +1199,23 @@ 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->skip_it)
                GOTO(skip_out, rc = 0);
 
        /* Write to new log all commands outside target device block */
-       if (!mrul->in_target_device)
+       if (!mrd->in_target_device)
                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->device_nids_added &&
            (lcfg->lcfg_command == LCFG_ADD_UUID ||
             lcfg->lcfg_command == LCFG_ADD_CONN))
                GOTO(skip_out, rc = 0);
 
-       rc = process_command(env, lcfg, mrul);
+       rc = process_command(env, lcfg, mrd);
        if (rc < 0)
                RETURN(rc);
 
@@ -1222,7 +1223,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,
@@ -1250,21 +1251,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);
 
@@ -1273,11 +1274,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) {
@@ -1314,20 +1319,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)
@@ -1349,18 +1357,27 @@ 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
  *
@@ -1504,7 +1521,7 @@ 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 = 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",
@@ -1517,7 +1534,7 @@ int mgs_replace_nids(const struct lu_env *env,
                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 = mgs_replace_nids_log(env, mgs_obd, logname, devname, nids);
                name_destroy(&logname);
                if (rc)
                        GOTO(out, rc);
@@ -1534,6 +1551,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->skip_it = 1;
+                       if (marker->cm_flags & CM_END)
+                               mrd->skip_it = 0;
+                       /* 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->skip_it) {
+                       /* 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)
 {
index 93f698f..3e71424 100644 (file)
@@ -130,8 +130,8 @@ reformat() {
 }
 
 start_mgs () {
-       echo "start mgs"
-       start mgs $(mgsdevname) $MGS_MOUNT_OPTS
+       echo "start mgs service on $(facet_active_host mgs)"
+       start mgs $(mgsdevname) $MGS_MOUNT_OPTS $@
 }
 
 start_mdt() {
@@ -7562,6 +7562,188 @@ test_107() {
 }
 run_test 107 "Unknown config param should not fail target mounting"
 
+#
+# set number of permanent parameters
+#
+test_109_set_params() {
+       local fsname=$1
+
+       set_conf_param_and_check mds                                \
+           "$LCTL get_param -n mdd.$fsname-MDT0000.atime_diff"     \
+           "$fsname-MDT0000.mdd.atime_diff"                        \
+           "62"
+       set_conf_param_and_check mds                                \
+           "$LCTL get_param -n mdd.$fsname-MDT0000.atime_diff"     \
+           "$fsname-MDT0000.mdd.atime_diff"                        \
+           "63"
+       set_conf_param_and_check client                             \
+           "$LCTL get_param -n llite.$fsname*.max_read_ahead_mb"   \
+           "$fsname.llite.max_read_ahead_mb"                       \
+           "32"
+       set_conf_param_and_check client                             \
+           "$LCTL get_param -n llite.$fsname*.max_read_ahead_mb"   \
+           "$fsname.llite.max_read_ahead_mb"                       \
+           "64"
+       create_pool $fsname.pool1 || error "create pool failed"
+       do_facet mgs $LCTL pool_add $fsname.pool1 OST0000 ||
+               error "pool_add failed"
+       do_facet mgs $LCTL pool_remove $fsname.pool1 OST0000 ||
+               error "pool_remove failed"
+       do_facet mgs $LCTL pool_add $fsname.pool1 OST0000 ||
+               error "pool_add failed"
+}
+
+#
+# check permanent parameters
+#
+test_109_test_params() {
+       local fsname=$1
+
+       local atime_diff=$(do_facet mds $LCTL \
+               get_param -n mdd.$fsname-MDT0000.atime_diff)
+       [ $atime_diff == 63 ] || error "wrong mdd parameter after clear_conf"
+       local max_read_ahead_mb=$(do_facet client $LCTL \
+               get_param -n llite.$fsname*.max_read_ahead_mb)
+       [ $max_read_ahead_mb == 64 ] ||
+               error "wrong llite parameter after clear_conf"
+       local ost_in_pool=$(do_facet mds $LCTL pool_list $fsname.pool1 |
+               grep -v "^Pool:" | sed 's/_UUID//')
+       [ $ost_in_pool = "$fsname-OST0000" ] ||
+               error "wrong pool after clear_conf"
+}
+
+#
+# run lctl clear_conf, store CONFIGS before and after that
+#
+test_109_clear_conf()
+{
+       local clear_conf_arg=$1
+
+       local mgsdev
+       if ! combined_mgs_mds ; then
+               mgsdev=$MGSDEV
+               stop_mgs || error "stop_mgs failed"
+               start_mgs "-o nosvc" || error "start_mgs nosvc failed"
+       else
+               mgsdev=$(mdsdevname 1)
+               start_mdt 1 "-o nosvc" || error "start_mdt 1 nosvc failed"
+       fi
+
+       do_facet mgs "rm -rf $TMP/${tdir}/conf1; mkdir -p $TMP/${tdir}/conf1;" \
+               "$DEBUGFS -c -R \\\"rdump CONFIGS $TMP/${tdir}/conf1\\\" \
+               $mgsdev"
+
+       #
+       # the command being tested
+       #
+       do_facet mgs $LCTL clear_conf $clear_conf_arg ||
+               error "clear_conf failed"
+       if ! combined_mgs_mds ; then
+               stop_mgs || error "stop_mgs failed"
+       else
+               stop_mdt 1 || error "stop_mdt 1 failed"
+       fi
+
+       do_facet mgs "rm -rf $TMP/${tdir}/conf2; mkdir -p $TMP/${tdir}/conf2;" \
+               "$DEBUGFS -c -R \\\"rdump CONFIGS $TMP/${tdir}/conf2\\\" \
+               $mgsdev"
+}
+
+test_109_file_shortened() {
+       local file=$1
+       local sizes=($(do_facet mgs "stat -c %s " \
+               "$TMP/${tdir}/conf1/CONFIGS/$file" \
+               "$TMP/${tdir}/conf2/CONFIGS/$file"))
+       [ ${sizes[1]} -lt ${sizes[0]} ] && return 0
+       return 1
+}
+
+test_109a()
+{
+       [ "$(facet_fstype mgs)" == "zfs" ] &&
+               skip "LU-8727: no implementation for ZFS" && return
+       stopall
+       reformat
+       setup_noconfig
+       client_up || error "client_up failed"
+
+       #
+       # set number of permanent parameters
+       #
+       test_109_set_params $FSNAME
+
+       umount_client $MOUNT || error "umount_client failed"
+       stop_ost || error "stop_ost failed"
+       stop_mds || error "stop_mds failed"
+
+       test_109_clear_conf $FSNAME
+       #
+       # make sure that all configs are cleared
+       #
+       test_109_file_shortened $FSNAME-MDT0000 ||
+               error "failed to clear MDT0000 config"
+       test_109_file_shortened $FSNAME-client ||
+               error "failed to clear client config"
+
+       setup_noconfig
+
+       #
+       # check that configurations are intact
+       #
+       test_109_test_params $FSNAME
+
+       #
+       # Destroy pool.
+       #
+       destroy_test_pools || error "destroy test pools failed"
+
+       cleanup
+}
+run_test 109a "test lctl clear_conf fsname"
+
+test_109b()
+{
+       [ "$(facet_fstype mgs)" == "zfs" ] &&
+               skip "LU-8727: no implementation for ZFS" && return
+       stopall
+       reformat
+       setup_noconfig
+       client_up || error "client_up failed"
+
+       #
+       # set number of permanent parameters
+       #
+       test_109_set_params $FSNAME
+
+       umount_client $MOUNT || error "umount_client failed"
+       stop_ost || error "stop_ost failed"
+       stop_mds || error "stop_mds failed"
+
+       test_109_clear_conf $FSNAME-MDT0000
+       #
+       # make sure that only one config is cleared
+       #
+       test_109_file_shortened $FSNAME-MDT0000 ||
+               error "failed to clear MDT0000 config"
+       test_109_file_shortened $FSNAME-client &&
+               error "failed to clear client config"
+
+       setup_noconfig
+
+       #
+       # check that configurations are intact
+       #
+       test_109_test_params $FSNAME
+
+       #
+       # Destroy pool.
+       #
+       destroy_test_pools || error "destroy test pools failed"
+
+       cleanup
+}
+run_test 109b "test lctl clear_conf one config"
+
 test_122() {
        [ $MDSCOUNT -lt 2 ] && skip "needs >= 2 MDTs" && return
        [[ $(lustre_version_code ost1) -ge $(version_code 2.10.6) ]] ||
index 788fc53..44b03fa 100644 (file)
@@ -114,7 +114,7 @@ command_t cmdlist[] = {
         "usage: net_drop_add <-s | --source NID>\n"
         "                    <-d | --dest NID>\n"
         "                    <<-r | --rate DROP_RATE> |\n"
-        "                     <-i | --interval SECONDS>>\n"
+        "                    <-i | --interval SECONDS>>\n"
         "                    [<-p | --portal> PORTAL...]\n"
         "                    [<-m | --message> <PUT|ACK|GET|REPLY>...]\n"},
        {"net_drop_del", jt_ptl_drop_del, 0, "remove LNet drop rule\n"
@@ -355,6 +355,9 @@ command_t cmdlist[] = {
         "usage: setup <args...>"},
        {"cleanup", jt_obd_cleanup, 0, "cleanup previously setup device\n"
         "usage: cleanup [force | failover]"},
+       {"clear_conf", jt_lcfg_clear, 0,
+        "drop unused config logs for a device or filesystem\n"
+        "usage: clear_conf <device|fsname>"},
        {"fork_lcfg", jt_lcfg_fork, 0,
         "copy configuration files for named filesystem with given name\n"
         "usage: fork_lcfg <fsname> <newname>"},
index 0492046..5043b05 100644 (file)
@@ -2340,8 +2340,8 @@ static int do_activate(int argc, char **argv, int flag)
  * are skipped and recorded with new nids and uuid.
  *
  * \see mgs_replace_nids
- * \see mgs_replace_nids_log
- * \see mgs_replace_handler
+ * \see mgs_replace_log
+ * \see mgs_replace_nids_handler
  */
 int jt_replace_nids(int argc, char **argv)
 {
@@ -2376,6 +2376,52 @@ int jt_replace_nids(int argc, char **argv)
        return rc;
 }
 
+/**
+ * Clear config logs for given device or filesystem.
+ * lctl clear_conf <devicename|fsname>
+ * Command has to be run on MGS node having MGS device mounted with -o
+ * nosvc.
+ *
+ * Configuration logs for filesystem or one particular log is
+ * processed. New log is created, original log is read, its records
+ * marked SKIP do not get copied to new log. Others are copied as-is.
+ * Original file is renamed to log.${time}.bak.
+ *
+ * \see mgs_clear_configs
+ * \see mgs_replace_log
+ * \see mgs_clear_config_handler
+ **/
+int jt_lcfg_clear(int argc, char **argv)
+{
+       int rc;
+       char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
+       struct obd_ioctl_data data;
+
+       memset(&data, 0, sizeof(data));
+       data.ioc_dev = get_mgs_device();
+       if (argc != 2)
+               return CMD_HELP;
+
+       data.ioc_inllen1 = strlen(argv[1]) + 1;
+       data.ioc_inlbuf1 = argv[1];
+
+       memset(buf, 0, sizeof(rawbuf));
+       rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
+       if (rc) {
+               fprintf(stderr, "error: %s: invalid ioctl\n",
+                       jt_cmdname(argv[0]));
+               return rc;
+       }
+
+       rc = l2_ioctl(OBD_DEV_ID, OBD_IOC_CLEAR_CONFIGS, buf);
+       if (rc < 0) {
+               fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
+                       strerror(rc = errno));
+       }
+
+       return rc;
+}
+
 int jt_obd_deactivate(int argc, char **argv)
 {
         return do_activate(argc, argv, 0);
index ad2c56a..7387bd2 100644 (file)
@@ -127,6 +127,7 @@ int jt_obd_deactivate(int argc, char **argv);
 int jt_obd_recover(int argc, char **argv);
 int jt_obd_mdc_lookup(int argc, char **argv);
 int jt_get_version(int argc, char **argv);
+int jt_lcfg_clear(int argc, char **argv);
 int jt_lcfg_fork(int argc, char **argv);
 int jt_lcfg_erase(int argc, char **argv);
 int jt_get_obj_version(int argc, char **argv);