Whamcloud - gitweb
LU-17744 ldiskfs: mballoc stats fixes
[fs/lustre-release.git] / lustre / obdclass / obd_config.c
index e7457ff..ed6fa85 100644 (file)
@@ -27,7 +27,6 @@
  */
 /*
  * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
  *
  * lustre/obdclass/obd_config.c
  *
 
 #include "llog_internal.h"
 
-static struct cfs_hash_ops nid_hash_ops;
+#ifdef HAVE_SERVER_SUPPORT
 static struct cfs_hash_ops nid_stat_hash_ops;
 static struct cfs_hash_ops gen_hash_ops;
+#endif /* HAVE_SERVER_SUPPORT */
 
 /*
  * uuid<->export lustre hash operations
@@ -85,7 +85,6 @@ static const struct rhashtable_params uuid_hash_params = {
        .key_offset     = offsetof(struct obd_export, exp_client_uuid),
        .head_offset    = offsetof(struct obd_export, exp_uuid_hash),
        .obj_cmpfn      = uuid_keycmp,
-       .max_size       = MAX_OBD_DEVICES,
        .automatic_shrinking = true,
 };
 
@@ -146,6 +145,118 @@ struct obd_export *obd_uuid_lookup(struct obd_device *obd,
        return export;
 }
 EXPORT_SYMBOL(obd_uuid_lookup);
+
+/*
+ * nid<->export hash operations
+ */
+static u32 nid_keyhash(const void *data, u32 key_len, u32 seed)
+{
+       const struct obd_export *exp = data;
+       void *key;
+
+       if (!exp->exp_connection)
+               return 0;
+
+       key = &exp->exp_connection->c_peer.nid;
+       return jhash2(key, key_len / sizeof(u32), seed);
+}
+
+/*
+ * NOTE: It is impossible to find an export that is in failed
+ *      state with this function
+ */
+static int
+nid_keycmp(struct rhashtable_compare_arg *arg, const void *obj)
+{
+       const struct lnet_nid *nid = arg->key;
+       const struct obd_export *exp = obj;
+
+       if (nid_same(&exp->exp_connection->c_peer.nid, nid))
+               return 0;
+
+       return -ESRCH;
+}
+
+static void
+nid_export_exit(void *vexport, void *data)
+{
+       struct obd_export *exp = vexport;
+
+       class_export_put(exp);
+}
+
+static const struct rhashtable_params nid_hash_params = {
+       .key_len                = sizeof(struct lnet_nid),
+       .head_offset            = offsetof(struct obd_export, exp_nid_hash),
+       .obj_hashfn             = nid_keyhash,
+       .obj_cmpfn              = nid_keycmp,
+       .automatic_shrinking    = true,
+};
+
+int obd_nid_add(struct obd_device *obd, struct obd_export *exp)
+{
+       int rc;
+
+       if (exp == exp->exp_obd->obd_self_export || exp->exp_hashed)
+               return 0;
+
+       class_export_get(exp);
+       rc = rhltable_insert_key(&obd->obd_nid_hash,
+                                &exp->exp_connection->c_peer.nid,
+                                &exp->exp_nid_hash,
+                                nid_hash_params);
+       if (rc) {
+               class_export_put(exp);
+               /* map obscure error codes to -ENOMEM */
+               rc = -ENOMEM;
+       } else {
+               exp->exp_hashed = 1;
+       }
+       return rc;
+}
+EXPORT_SYMBOL(obd_nid_add);
+
+void obd_nid_del(struct obd_device *obd, struct obd_export *exp)
+{
+       int rc;
+
+       if (exp == exp->exp_obd->obd_self_export || !exp->exp_hashed)
+               return;
+
+       rc = rhltable_remove(&obd->obd_nid_hash, &exp->exp_nid_hash,
+                            nid_hash_params);
+       if (rc == 0) {
+               class_export_put(exp);
+               exp->exp_hashed = 0;
+       }
+}
+EXPORT_SYMBOL(obd_nid_del);
+
+int obd_nid_export_for_each(struct obd_device *obd, struct lnet_nid *nid,
+                           int cb(struct obd_export *exp, void *data),
+                           void *data)
+{
+       struct rhlist_head *exports, *tmp;
+       struct obd_export *exp;
+       int ret = 0;
+
+       rcu_read_lock();
+       exports = rhltable_lookup(&obd->obd_nid_hash, nid, nid_hash_params);
+       if (!exports) {
+               ret = -ENODEV;
+               goto out_unlock;
+       }
+
+       rhl_for_each_entry_rcu(exp, tmp, exports, exp_nid_hash) {
+               if (!exp->exp_failed && cb(exp, data))
+                       ret++;
+       }
+
+out_unlock:
+       rcu_read_unlock();
+       return ret;
+}
+EXPORT_SYMBOL(obd_nid_export_for_each);
 #endif /* HAVE_SERVER_SUPPORT */
 
 /*********** string parsing utils *********/
@@ -298,10 +409,9 @@ EXPORT_SYMBOL(class_match_param);
 
 static int parse_nid(char *buf, void *value, int quiet)
 {
-       lnet_nid_t *nid = (lnet_nid_t *)value;
+       struct lnet_nid *nid = value;
 
-       *nid = libcfs_str2nid(buf);
-       if (*nid != LNET_NID_ANY)
+       if (libcfs_strnid(nid, buf) == 0)
                return 0;
 
        if (!quiet)
@@ -333,18 +443,41 @@ static int class_parse_value(char *buf, int opc, void *value, char **endh,
                             int quiet)
 {
        char *endp;
-       char  tmp;
-       int   rc = 0;
+       char tmp;
+       int rc = 0;
+       int ncolons = 0;
 
        if (!buf)
                return 1;
-       while (*buf == ',' || *buf == ':')
+
+       while (*buf == ',' || *buf == ':') {
+               if (*buf == ':')
+                       ncolons++;
+               else
+                       ncolons = 0;
                buf++;
+       }
+
+       /* IPv6 addresses can start with '::' */
+       if (opc == CLASS_PARSE_NID && ncolons >= 2)
+               buf = buf - 2;
+
        if (*buf == ' ' || *buf == '/' || *buf == '\0')
                return 1;
 
-       /* NID separators or end of NIDs */
-       endp = strpbrk(buf, ",: /");
+       /* NID separators or end of NIDs. Large NIDs can contain ':' so
+        * skip ahead to @ and then look for one of the delimiters.
+        */
+       if (opc == CLASS_PARSE_NID) {
+               endp = strchr(buf, '@');
+               if (!endp)
+                       return 1;
+
+               endp = strpbrk(endp, ",: /");
+       } else {
+               endp = strpbrk(buf, ",: /");
+       }
+
        if (!endp)
                endp = buf + strlen(buf);
 
@@ -368,13 +501,13 @@ static int class_parse_value(char *buf, int opc, void *value, char **endh,
        return 0;
 }
 
-int class_parse_nid(char *buf, lnet_nid_t *nid, char **endh)
+int class_parse_nid(char *buf, struct lnet_nid *nid, char **endh)
 {
        return class_parse_value(buf, CLASS_PARSE_NID, (void *)nid, endh, 0);
 }
 EXPORT_SYMBOL(class_parse_nid);
 
-int class_parse_nid_quiet(char *buf, lnet_nid_t *nid, char **endh)
+int class_parse_nid_quiet(char *buf, struct lnet_nid *nid, char **endh)
 {
        return class_parse_value(buf, CLASS_PARSE_NID, (void *)nid, endh, 1);
 }
@@ -390,9 +523,9 @@ int class_parse_net(char *buf, __u32 *net, char **endh)
  * 0 param contains key and not match
  * -1 param does not contain key
  */
-int class_match_nid(char *buf, char *key, lnet_nid_t nid)
+int class_match_nid(char *buf, char *key, struct lnet_nid *nid)
 {
-       lnet_nid_t tmp;
+       struct lnet_nid tmp;
        int rc = -1;
 
        while (class_find_param(buf, key, &buf) == 0) {
@@ -401,13 +534,14 @@ int class_match_nid(char *buf, char *key, lnet_nid_t nid)
                 * the specified NIDs
                 */
                while (class_parse_nid(buf, &tmp, &buf) == 0) {
-                       if (tmp == nid)
+                       if (nid_same(&tmp, nid))
                                return 1;
                }
                rc = 0;
        }
        return rc;
 }
+EXPORT_SYMBOL(class_match_nid);
 
 int class_match_net(char *buf, char *key, __u32 net)
 {
@@ -427,6 +561,7 @@ int class_match_net(char *buf, char *key, __u32 net)
        }
        return rc;
 }
+EXPORT_SYMBOL(class_match_net);
 
 char *lustre_cfg_string(struct lustre_cfg *lcfg, u32 index)
 {
@@ -509,10 +644,10 @@ int class_attach(struct lustre_cfg *lcfg)
                RETURN(rc);
        }
        LASSERTF(obd->obd_magic == OBD_DEVICE_MAGIC,
-                "obd %p obd_magic %08X != %08X\n",
+                "obd %px obd_magic %08X != %08X\n",
                 obd, obd->obd_magic, OBD_DEVICE_MAGIC);
        LASSERTF(strncmp(obd->obd_name, name, strlen(name)) == 0,
-                "%p obd_name %s != %s\n", obd, obd->obd_name, name);
+                "%px obd_name %s != %s\n", obd, obd->obd_name, name);
 
        exp = class_new_export_self(obd, &obd->obd_uuid);
        if (IS_ERR(exp)) {
@@ -533,7 +668,7 @@ int class_attach(struct lustre_cfg *lcfg)
 
        obd->obd_attached = 1;
        CDEBUG(D_IOCTL, "OBD: dev %d attached type %s with refcount %d\n",
-              obd->obd_minor, typename, atomic_read(&obd->obd_refcount));
+              obd->obd_minor, typename, kref_read(&obd->obd_refcount));
 
        RETURN(0);
 }
@@ -551,10 +686,10 @@ int class_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
 
        LASSERT(obd != NULL);
        LASSERTF(obd == class_num2obd(obd->obd_minor),
-                "obd %p != obd_devs[%d] %p\n",
+                "obd %px != obd_devs[%d] %px\n",
                 obd, obd->obd_minor, class_num2obd(obd->obd_minor));
        LASSERTF(obd->obd_magic == OBD_DEVICE_MAGIC,
-                "obd %p obd_magic %08x != %08x\n",
+                "obd %px obd_magic %08x != %08x\n",
                 obd, obd->obd_magic, OBD_DEVICE_MAGIC);
 
        /* have we attached a type to this device? */
@@ -582,7 +717,6 @@ int class_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
         * other fns check that status, and we're not actually set up yet.
         */
        obd->obd_starting = 1;
-       obd->obd_nid_hash = NULL;
        obd->obd_nid_stats_hash = NULL;
        obd->obd_gen_hash = NULL;
        spin_unlock(&obd->obd_dev_lock);
@@ -592,15 +726,10 @@ int class_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
        if (err)
                GOTO(err_starting, err);
 
+#ifdef HAVE_SERVER_SUPPORT
        /* create a nid-export lustre hash */
-       obd->obd_nid_hash = cfs_hash_create("NID_HASH",
-                                           HASH_NID_CUR_BITS,
-                                           HASH_NID_MAX_BITS,
-                                           HASH_NID_BKT_BITS, 0,
-                                           CFS_HASH_MIN_THETA,
-                                           CFS_HASH_MAX_THETA,
-                                           &nid_hash_ops, CFS_HASH_DEFAULT);
-       if (!obd->obd_nid_hash)
+       err = rhltable_init(&obd->obd_nid_hash, &nid_hash_params);
+       if (err)
                GOTO(err_uuid_hash, err = -ENOMEM);
 
        /* create a nid-stats lustre hash */
@@ -625,10 +754,15 @@ int class_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
                                            &gen_hash_ops, CFS_HASH_DEFAULT);
        if (!obd->obd_gen_hash)
                GOTO(err_nid_stats_hash, err = -ENOMEM);
+#endif /* HAVE_SERVER_SUPPORT */
 
        err = obd_setup(obd, lcfg);
        if (err)
+#ifdef HAVE_SERVER_SUPPORT
                GOTO(err_gen_hash, err);
+#else
+               GOTO(err_uuid_hash, err);
+#endif /* ! HAVE_SERVER_SUPPORT */
 
        obd->obd_set_up = 1;
 
@@ -642,6 +776,7 @@ int class_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
 
        RETURN(0);
 
+#ifdef HAVE_SERVER_SUPPORT
 err_gen_hash:
        if (obd->obd_gen_hash) {
                cfs_hash_putref(obd->obd_gen_hash);
@@ -653,10 +788,8 @@ err_nid_stats_hash:
                obd->obd_nid_stats_hash = NULL;
        }
 err_nid_hash:
-       if (obd->obd_nid_hash) {
-               cfs_hash_putref(obd->obd_nid_hash);
-               obd->obd_nid_hash = NULL;
-       }
+       rhltable_destroy(&obd->obd_nid_hash);
+#endif /* HAVE_SERVER_SUPPORT */
 err_uuid_hash:
        rhashtable_destroy(&obd->obd_uuid_hash);
 err_starting:
@@ -686,10 +819,10 @@ int class_detach(struct obd_device *obd, struct lustre_cfg *lcfg)
                RETURN(-ENODEV);
        }
        obd->obd_attached = 0;
-       spin_unlock(&obd->obd_dev_lock);
 
        /* cleanup in progress. we don't like to find this device after now */
        class_unregister_device(obd);
+       spin_unlock(&obd->obd_dev_lock);
 
        CDEBUG(D_IOCTL, "detach on obd %s (uuid %s)\n",
               obd->obd_name, obd->obd_uuid.uuid);
@@ -711,7 +844,7 @@ int class_cleanup(struct obd_device *obd, struct lustre_cfg *lcfg)
        char *flag;
        ENTRY;
 
-       OBD_RACE(OBD_FAIL_LDLM_RECOV_CLIENTS);
+       CFS_RACE(OBD_FAIL_LDLM_RECOV_CLIENTS);
 
        if (!obd->obd_set_up) {
                CERROR("Device %d not setup\n", obd->obd_minor);
@@ -726,16 +859,11 @@ int class_cleanup(struct obd_device *obd, struct lustre_cfg *lcfg)
        }
        /* Leave this on forever */
        obd->obd_stopping = 1;
-       /*
-        * function can't return error after that point, so clear setup flag
-        * as early as possible to avoid finding via obd_devs / hash
-        */
-       obd->obd_set_up = 0;
        spin_unlock(&obd->obd_dev_lock);
 
        /* wait for already-arrived-connections to finish. */
-       while (obd->obd_conn_inprogress > 0)
-               yield();
+       wait_var_event(&obd->obd_conn_inprogress,
+                      atomic_read(&obd->obd_conn_inprogress) == 0);
        smp_rmb();
 
        if (lcfg->lcfg_bufcount >= 2 && LUSTRE_CFG_BUFLEN(lcfg, 1) > 0) {
@@ -745,12 +873,16 @@ int class_cleanup(struct obd_device *obd, struct lustre_cfg *lcfg)
                                obd->obd_force = 1;
                                break;
                        case 'A':
-                               LCONSOLE_WARN("Failing over %s\n",
-                                             obd->obd_name);
+                               LCONSOLE(D_WARNING, "Failing over %s\n",
+                                        obd->obd_name);
+                               spin_lock(&obd->obd_dev_lock);
                                obd->obd_fail = 1;
+#ifdef HAVE_SERVER_SUPPORT
                                obd->obd_no_transno = 1;
+#endif
                                obd->obd_no_recov = 1;
-                               if (OBP(obd, iocontrol)) {
+                               spin_unlock(&obd->obd_dev_lock);
+                               if (obd->obd_type->typ_dt_ops->o_iocontrol) {
                                        obd_iocontrol(OBD_IOC_SYNC,
                                                      obd->obd_self_export,
                                                      0, NULL, NULL);
@@ -765,7 +897,7 @@ int class_cleanup(struct obd_device *obd, struct lustre_cfg *lcfg)
 
        CDEBUG(D_IOCTL, "%s: forcing exports to disconnect: %d/%d\n",
               obd->obd_name, obd->obd_num_exports,
-              atomic_read(&obd->obd_refcount) - 2);
+              kref_read(&obd->obd_refcount) - 2);
        dump_exports(obd, 0, D_HA);
        class_disconnect_exports(obd);
 
@@ -778,12 +910,9 @@ int class_cleanup(struct obd_device *obd, struct lustre_cfg *lcfg)
        /* destroy an uuid-export hash body */
        rhashtable_free_and_destroy(&obd->obd_uuid_hash, obd_export_exit,
                                    NULL);
-
+#ifdef HAVE_SERVER_SUPPORT
        /* destroy a nid-export hash body */
-       if (obd->obd_nid_hash) {
-               cfs_hash_putref(obd->obd_nid_hash);
-               obd->obd_nid_hash = NULL;
-       }
+       rhltable_free_and_destroy(&obd->obd_nid_hash, nid_export_exit, NULL);
 
        /* destroy a nid-stats hash body */
        if (obd->obd_nid_stats_hash) {
@@ -796,7 +925,7 @@ int class_cleanup(struct obd_device *obd, struct lustre_cfg *lcfg)
                cfs_hash_putref(obd->obd_gen_hash);
                obd->obd_gen_hash = NULL;
        }
-
+#endif /* HAVE_SERVER_SUPPORT */
        class_decref(obd, "setup", obd);
        obd->obd_set_up = 0;
 
@@ -808,40 +937,40 @@ struct obd_device *class_incref(struct obd_device *obd,
                                const void *source)
 {
        lu_ref_add_atomic(&obd->obd_reference, scope, source);
-       atomic_inc(&obd->obd_refcount);
-       CDEBUG(D_INFO, "incref %s (%p) now %d\n", obd->obd_name, obd,
-              atomic_read(&obd->obd_refcount));
+       kref_get(&obd->obd_refcount);
+       CDEBUG(D_INFO, "incref %s (%p) now %d - %s\n", obd->obd_name, obd,
+              kref_read(&obd->obd_refcount), scope);
 
        return obd;
 }
 EXPORT_SYMBOL(class_incref);
 
-void class_decref(struct obd_device *obd, const char *scope, const void *source)
+static void class_decref_free(struct kref *kref)
 {
-       int last;
+       struct obd_device *obd;
+       struct obd_export *exp;
 
-       CDEBUG(D_INFO, "Decref %s (%p) now %d - %s\n", obd->obd_name, obd,
-              atomic_read(&obd->obd_refcount), scope);
+       obd = container_of(kref, struct obd_device, obd_refcount);
+       LASSERT(!obd->obd_attached);
+       /*
+        * All exports have been destroyed; there should
+        * be no more in-progress ops by this point.
+        */
+       exp = obd->obd_self_export;
 
+       if (exp) {
+               exp->exp_flags |= exp_flags_from_obd(obd);
+               class_unlink_export(exp);
+       }
+}
+
+void class_decref(struct obd_device *obd, const char *scope, const void *source)
+{
+       CDEBUG(D_INFO, "Decref %s (%p) now %d - %s\n", obd->obd_name, obd,
+              kref_read(&obd->obd_refcount), scope);
        LASSERT(obd->obd_num_exports >= 0);
-       last = atomic_dec_and_test(&obd->obd_refcount);
+       kref_put(&obd->obd_refcount, class_decref_free);
        lu_ref_del(&obd->obd_reference, scope, source);
-
-       if (last) {
-               struct obd_export *exp;
-
-               LASSERT(!obd->obd_attached);
-               /*
-                * All exports have been destroyed; there should
-                * be no more in-progress ops by this point.
-                */
-               exp = obd->obd_self_export;
-
-               if (exp) {
-                       exp->exp_flags |= exp_flags_from_obd(obd);
-                       class_unlink_export(exp);
-               }
-       }
 }
 EXPORT_SYMBOL(class_decref);
 
@@ -882,6 +1011,7 @@ int class_add_conn(struct obd_device *obd, struct lustre_cfg *lcfg)
 
        RETURN(rc);
 }
+EXPORT_SYMBOL(class_add_conn);
 
 /** Remove a failover NID location. */
 static int class_del_conn(struct obd_device *obd, struct lustre_cfg *lcfg)
@@ -918,22 +1048,30 @@ static int class_del_conn(struct obd_device *obd, struct lustre_cfg *lcfg)
 static LIST_HEAD(lustre_profile_list);
 static DEFINE_SPINLOCK(lustre_profile_list_lock);
 
-struct lustre_profile *class_get_profile(const char *prof)
+static struct lustre_profile *class_get_profile_nolock(const char *prof)
 {
        struct lustre_profile *lprof;
 
        ENTRY;
-       spin_lock(&lustre_profile_list_lock);
        list_for_each_entry(lprof, &lustre_profile_list, lp_list) {
-               if (!strcmp(lprof->lp_profile, prof)) {
+               if (strcmp(lprof->lp_profile, prof) == 0) {
                        lprof->lp_refs++;
-                       spin_unlock(&lustre_profile_list_lock);
                        RETURN(lprof);
                }
        }
-       spin_unlock(&lustre_profile_list_lock);
        RETURN(NULL);
 }
+
+struct lustre_profile *class_get_profile(const char *prof)
+{
+       struct lustre_profile *lprof;
+
+       ENTRY;
+       spin_lock(&lustre_profile_list_lock);
+       lprof = class_get_profile_nolock(prof);
+       spin_unlock(&lustre_profile_list_lock);
+       RETURN(lprof);
+}
 EXPORT_SYMBOL(class_get_profile);
 
 /**
@@ -1003,9 +1141,9 @@ void class_del_profile(const char *prof)
 
        CDEBUG(D_CONFIG, "Del profile %s\n", prof);
 
-       lprof = class_get_profile(prof);
+       spin_lock(&lustre_profile_list_lock);
+       lprof = class_get_profile_nolock(prof);
        if (lprof) {
-               spin_lock(&lustre_profile_list_lock);
                /* because get profile increments the ref counter */
                lprof->lp_refs--;
                list_del(&lprof->lp_list);
@@ -1013,6 +1151,8 @@ void class_del_profile(const char *prof)
                spin_unlock(&lustre_profile_list_lock);
 
                class_put_profile(lprof);
+       } else {
+               spin_unlock(&lustre_profile_list_lock);
        }
        EXIT;
 }
@@ -1117,7 +1257,7 @@ struct lustre_cfg *lustre_cfg_rename(struct lustre_cfg *cfg,
        if (!new_param)
                GOTO(out_nocfg, new_cfg = ERR_PTR(-ENOMEM));
 
-       strlcpy(new_param, new_name, new_len);
+       strscpy(new_param, new_name, new_len);
        if (value)
                strcat(new_param, value);
 
@@ -1155,6 +1295,7 @@ static ssize_t process_param2_config(struct lustre_cfg *lcfg)
        char *upcall = lustre_cfg_string(lcfg, 2);
        struct kobject *kobj = NULL;
        const char *subsys = param;
+       char *newparam = NULL;
        char *argv[] = {
                [0] = "/usr/sbin/lctl",
                [1] = "set_param",
@@ -1171,15 +1312,15 @@ static ssize_t process_param2_config(struct lustre_cfg *lcfg)
 
        len = strcspn(param, ".=");
        if (!len)
-               return -EINVAL;
+               RETURN(-EINVAL);
 
        /* If we find '=' then its the top level sysfs directory */
        if (param[len] == '=')
-               return class_set_global(param);
+               RETURN(class_set_global(param));
 
        subsys = kstrndup(param, len, GFP_KERNEL);
        if (!subsys)
-               return -ENOMEM;
+               RETURN(-ENOMEM);
 
        kobj = kset_find_obj(lustre_kset, subsys);
        kfree(subsys);
@@ -1210,6 +1351,22 @@ static ssize_t process_param2_config(struct lustre_cfg *lcfg)
                RETURN(-EINVAL);
        }
 
+       /* root_squash and nosquash_nids settings must be applied to
+        * global subsystem (*.) so that it is taken into account by
+        * both client and server sides. So do the equivalent of a
+        * 's / mdt. / *. /'.
+        */
+       if ((strstr(param, PARAM_NOSQUASHNIDS) ||
+            strstr(param, PARAM_ROOTSQUASH)) &&
+           (param[0] != '*' || param[1] != '.')) {
+               newparam = kmalloc(strlen(param) + 1, GFP_NOFS);
+               if (!newparam)
+                       RETURN(-ENOMEM);
+
+               snprintf(newparam, strlen(param) + 1, "*%s", param + len);
+               argv[2] = (char *)newparam;
+       }
+
        start = ktime_get();
        rc = call_usermodehelper(argv[0], argv, NULL, UMH_WAIT_PROC);
        end = ktime_get();
@@ -1225,6 +1382,7 @@ static ssize_t process_param2_config(struct lustre_cfg *lcfg)
                       rc = 0;
        }
 
+       kfree(newparam);
        RETURN(rc);
 }
 
@@ -1244,6 +1402,7 @@ EXPORT_SYMBOL(lustre_register_quota_process_config);
 int class_process_config(struct lustre_cfg *lcfg)
 {
        struct obd_device *obd;
+       struct lnet_nid nid;
        int err;
 
        LASSERT(lcfg && !IS_ERR(lcfg));
@@ -1261,8 +1420,19 @@ int class_process_config(struct lustre_cfg *lcfg)
                       lustre_cfg_string(lcfg, 1), lcfg->lcfg_nid,
                       libcfs_nid2str(lcfg->lcfg_nid));
 
-               err = class_add_uuid(lustre_cfg_string(lcfg, 1),
-                                    lcfg->lcfg_nid);
+               err = 0;
+               if (lcfg->lcfg_nid) {
+                       lnet_nid4_to_nid(lcfg->lcfg_nid, &nid);
+               } else {
+                       char *nidstr = lustre_cfg_string(lcfg, 2);
+
+                       if (nidstr)
+                               err = libcfs_strnid(&nid, nidstr);
+                       else
+                               err = -EINVAL;
+               }
+               if (!err)
+                       err = class_add_uuid(lustre_cfg_string(lcfg, 1), &nid);
                GOTO(out, err);
        }
        case LCFG_DEL_UUID: {
@@ -1300,6 +1470,7 @@ int class_process_config(struct lustre_cfg *lcfg)
                CDEBUG(D_IOCTL, "changing lustre timeout from %d to %d\n",
                       obd_timeout, lcfg->lcfg_num);
                obd_timeout = max(lcfg->lcfg_num, 1U);
+               ping_interval = max(obd_timeout / 4, 1U);
                obd_timeout_set = 1;
                GOTO(out, err = 0);
        }
@@ -1489,7 +1660,7 @@ EXPORT_SYMBOL(class_process_config);
 ssize_t class_modify_config(struct lustre_cfg *lcfg, const char *prefix,
                            struct kobject *kobj)
 {
-       struct kobj_type *typ;
+       const struct kobj_type *typ;
        ssize_t count = 0;
        int i;
 
@@ -1499,7 +1670,7 @@ ssize_t class_modify_config(struct lustre_cfg *lcfg, const char *prefix,
        }
 
        typ = get_ktype(kobj);
-       if (!typ || !typ->default_attrs)
+       if (!typ || !typ->default_groups)
                return -ENODEV;
 
        print_lustre_cfg(lcfg);
@@ -1510,11 +1681,10 @@ ssize_t class_modify_config(struct lustre_cfg *lcfg, const char *prefix,
         * or   lctl conf_param lustre-OST0000.osc.max_dirty_mb=36
         */
        for (i = 1; i < lcfg->lcfg_bufcount; i++) {
-               struct attribute *attr;
+               struct attribute *attr = NULL;
                size_t keylen;
                char *value;
                char *key;
-               int j;
 
                key = lustre_cfg_buf(lcfg, i);
                /* Strip off prefix */
@@ -1536,15 +1706,7 @@ ssize_t class_modify_config(struct lustre_cfg *lcfg, const char *prefix,
                keylen = value - key;
                value++;
 
-               attr = NULL;
-               for (j = 0; typ->default_attrs[j]; j++) {
-                       if (!strncmp(typ->default_attrs[j]->name, key,
-                                    keylen)) {
-                               attr = typ->default_attrs[j];
-                               break;
-                       }
-               }
-
+               attr = get_attr_starts_with(typ, key, keylen);
                if (!attr) {
                        char *envp[4], *param, *path;
 
@@ -1828,31 +1990,10 @@ int class_config_llog_handler(const struct lu_env *env,
                        }
                }
 
-               /*
-                * Skip add_conn command if uuid is
-                * not on restricted net
-                */
-               if (cfg && cfg->cfg_sb && s2lsi(cfg->cfg_sb) &&
-                   !IS_SERVER(s2lsi(cfg->cfg_sb))) {
-                       struct lustre_sb_info *lsi = s2lsi(cfg->cfg_sb);
-                       char *uuid_str = lustre_cfg_string(lcfg, 1);
-
-                       if (lcfg->lcfg_command == LCFG_ADD_CONN &&
-                           lsi->lsi_lmd->lmd_nidnet &&
-                           LNET_NIDNET(libcfs_str2nid(uuid_str)) !=
-                           libcfs_str2net(lsi->lsi_lmd->lmd_nidnet)) {
-                               CDEBUG(D_CONFIG, "skipping add_conn for %s\n",
-                                      uuid_str);
-                               rc = 0;
-                               /* No processing! */
-                               break;
-                       }
-               }
-
                OBD_ALLOC(lcfg_new, lustre_cfg_len(bufs.lcfg_bufcount,
                                                   bufs.lcfg_buflen));
                if (!lcfg_new)
-                       GOTO(out, rc = -ENOMEM);
+                       GOTO(out_inst, rc = -ENOMEM);
 
                lustre_cfg_init(lcfg_new, lcfg->lcfg_command, &bufs);
                lcfg_new->lcfg_num   = lcfg->lcfg_num;
@@ -1880,6 +2021,7 @@ int class_config_llog_handler(const struct lu_env *env,
                rc = class_process_config(lcfg_new);
                OBD_FREE(lcfg_new, lustre_cfg_len(lcfg_new->lcfg_bufcount,
                                                  lcfg_new->lcfg_buflens));
+out_inst:
                if (inst_name)
                        OBD_FREE(inst_name, inst_len);
                break;
@@ -1904,6 +2046,7 @@ int class_config_parse_llog(const struct lu_env *env, struct llog_ctxt *ctxt,
 {
        struct llog_process_cat_data cd = {
                .lpcd_first_idx = 0,
+               .lpcd_read_mode = LLOG_READ_MODE_NORMAL,
        };
        struct llog_handle *llh;
        llog_cb_t callback;
@@ -1944,6 +2087,29 @@ parse_out:
 EXPORT_SYMBOL(class_config_parse_llog);
 
 /**
+ * Get marker cfg_flag
+ */
+void llog_get_marker_cfg_flags(struct llog_rec_hdr *rec,
+                              unsigned int *cfg_flags)
+{
+       struct lustre_cfg *lcfg = (struct lustre_cfg *)(rec + 1);
+       struct cfg_marker *marker;
+
+       if (lcfg->lcfg_command == LCFG_MARKER) {
+               marker = lustre_cfg_buf(lcfg, 1);
+               if (marker->cm_flags & CM_START) {
+                       *cfg_flags = CFG_F_MARKER;
+                       if (marker->cm_flags & CM_SKIP)
+                               *cfg_flags = CFG_F_SKIP;
+               } else if (marker->cm_flags & CM_END) {
+                       *cfg_flags = 0;
+               }
+               CDEBUG(D_INFO, "index=%d, cm_flags=%#08x cfg_flags=%#08x\n",
+                      rec->lrh_index, marker->cm_flags, *cfg_flags);
+       }
+}
+
+/**
  * Parse config record and output dump in supplied buffer.
  *
  * This is separated from class_config_dump_handler() to use
@@ -1953,15 +2119,23 @@ EXPORT_SYMBOL(class_config_parse_llog);
  * - { index: 4, event: attach, device: lustrewt-clilov, type: lov,
  *     UUID: lustrewt-clilov_UUID }
  */
-int class_config_yaml_output(struct llog_rec_hdr *rec, char *buf, int size)
+int class_config_yaml_output(struct llog_rec_hdr *rec, char *buf, int size,
+                            unsigned int *cfg_flags, bool raw)
 {
        struct lustre_cfg *lcfg = (struct lustre_cfg *)(rec + 1);
        char *ptr = buf;
        char *end = buf + size;
        int rc = 0, i;
        struct lcfg_type_data *ldata;
+       int swab = 0;
 
        LASSERT(rec->lrh_type == OBD_CFG_REC);
+
+       if (lcfg->lcfg_version == __swab32(LUSTRE_CFG_VERSION)) {
+               lustre_swab_lustre_cfg(lcfg);
+               swab = 1;
+       }
+
        rc = lustre_cfg_sanity_check(lcfg, rec->lrh_len);
        if (rc < 0)
                return rc;
@@ -1970,7 +2144,14 @@ int class_config_yaml_output(struct llog_rec_hdr *rec, char *buf, int size)
        if (!ldata)
                return -ENOTTY;
 
-       if (lcfg->lcfg_command == LCFG_MARKER)
+       llog_get_marker_cfg_flags(rec, cfg_flags);
+       if ((lcfg->lcfg_command == LCFG_MARKER) && likely(!raw))
+               return 0;
+       /* entries outside marker are skipped */
+       if (!(*cfg_flags & CFG_F_MARKER) && !raw)
+               return 0;
+       /* inside skipped marker */
+       if ((*cfg_flags & CFG_F_SKIP) && !raw)
                return 0;
 
        /* form YAML entity */
@@ -2032,6 +2213,25 @@ int class_config_yaml_output(struct llog_rec_hdr *rec, char *buf, int size)
                goto out_done;
        }
 
+       if (lcfg->lcfg_command == LCFG_MARKER) {
+               struct cfg_marker *marker;
+
+               marker = lustre_cfg_buf(lcfg, 1);
+               ptr += snprintf(ptr, end - ptr, ", flags: %#04x",
+                               marker->cm_flags);
+               ptr += snprintf(ptr, end - ptr, ", version: %d.%d.%d.%d",
+                               OBD_OCD_VERSION_MAJOR(marker->cm_vers),
+                               OBD_OCD_VERSION_MINOR(marker->cm_vers),
+                               OBD_OCD_VERSION_PATCH(marker->cm_vers),
+                               OBD_OCD_VERSION_FIX(marker->cm_vers));
+               ptr += snprintf(ptr, end - ptr, ", createtime: %lld",
+                               marker->cm_createtime);
+               ptr += snprintf(ptr, end - ptr, ", canceltime: %lld",
+                               marker->cm_canceltime);
+
+               goto out_done;
+       }
+
        for (i = 1; i < lcfg->lcfg_bufcount; i++) {
                if (LUSTRE_CFG_BUFLEN(lcfg, i) > 0) {
                        ptr += snprintf(ptr, end - ptr, ", %s: %s",
@@ -2185,80 +2385,17 @@ out:
 }
 EXPORT_SYMBOL(class_manual_cleanup);
 
+#ifdef HAVE_SERVER_SUPPORT
 /*
- * nid<->export hash operations
- */
-static unsigned
-nid_hash(struct cfs_hash *hs, const void *key, unsigned mask)
-{
-       return cfs_hash_djb2_hash(key, sizeof(lnet_nid_t), mask);
-}
-
-static void *
-nid_key(struct hlist_node *hnode)
-{
-       struct obd_export *exp;
-
-       exp = hlist_entry(hnode, struct obd_export, exp_nid_hash);
-
-       RETURN(&exp->exp_connection->c_peer.nid);
-}
-
-/*
- * NOTE: It is impossible to find an export that is in failed
- *       state with this function
+ * nid<->nidstats hash operations
  */
-static int
-nid_kepcmp(const void *key, struct hlist_node *hnode)
+static unsigned int
+nidstats_hash(struct cfs_hash *hs, const void *key, const unsigned int bits)
 {
-       struct obd_export *exp;
-
-       LASSERT(key);
-       exp = hlist_entry(hnode, struct obd_export, exp_nid_hash);
-
-       RETURN(exp->exp_connection->c_peer.nid == *(lnet_nid_t *)key &&
-              !exp->exp_failed);
+       return cfs_hash_djb2_hash(key, sizeof(struct lnet_nid), bits);
 }
 
 static void *
-nid_export_object(struct hlist_node *hnode)
-{
-       return hlist_entry(hnode, struct obd_export, exp_nid_hash);
-}
-
-static void
-nid_export_get(struct cfs_hash *hs, struct hlist_node *hnode)
-{
-       struct obd_export *exp;
-
-       exp = hlist_entry(hnode, struct obd_export, exp_nid_hash);
-       class_export_get(exp);
-}
-
-static void
-nid_export_put_locked(struct cfs_hash *hs, struct hlist_node *hnode)
-{
-       struct obd_export *exp;
-
-       exp = hlist_entry(hnode, struct obd_export, exp_nid_hash);
-       class_export_put(exp);
-}
-
-static struct cfs_hash_ops nid_hash_ops = {
-       .hs_hash        = nid_hash,
-       .hs_key         = nid_key,
-       .hs_keycmp      = nid_kepcmp,
-       .hs_object      = nid_export_object,
-       .hs_get         = nid_export_get,
-       .hs_put_locked  = nid_export_put_locked,
-};
-
-
-/*
- * nid<->nidstats hash operations
- */
-
-static void *
 nidstats_key(struct hlist_node *hnode)
 {
        struct nid_stat *ns;
@@ -2271,7 +2408,8 @@ nidstats_key(struct hlist_node *hnode)
 static int
 nidstats_keycmp(const void *key, struct hlist_node *hnode)
 {
-       return *(lnet_nid_t *)nidstats_key(hnode) == *(lnet_nid_t *)key;
+       return nid_same((struct lnet_nid *)nidstats_key(hnode),
+                        (struct lnet_nid *)key);
 }
 
 static void *
@@ -2299,23 +2437,23 @@ nidstats_put_locked(struct cfs_hash *hs, struct hlist_node *hnode)
 }
 
 static struct cfs_hash_ops nid_stat_hash_ops = {
-       .hs_hash        = nid_hash,
-       .hs_key         = nidstats_key,
-       .hs_keycmp      = nidstats_keycmp,
-       .hs_object      = nidstats_object,
-       .hs_get         = nidstats_get,
-       .hs_put_locked  = nidstats_put_locked,
+       .hs_hash        = nidstats_hash,
+       .hs_key         = nidstats_key,
+       .hs_keycmp      = nidstats_keycmp,
+       .hs_object      = nidstats_object,
+       .hs_get         = nidstats_get,
+       .hs_put_locked  = nidstats_put_locked,
 };
 
-
 /*
  * client_generation<->export hash operations
  */
 
-static unsigned
-gen_hash(struct cfs_hash *hs, const void *key, unsigned mask)
+static unsigned int
+gen_hash(struct cfs_hash *hs, const void *key, const unsigned int bits)
 {
-       return cfs_hash_djb2_hash(key, sizeof(__u32), mask);
+       /* XXX did hash needs ? */
+       return cfs_hash_djb2_hash(key, sizeof(__u32), bits);
 }
 
 static void *
@@ -2376,3 +2514,5 @@ static struct cfs_hash_ops gen_hash_ops = {
        .hs_get         = gen_export_get,
        .hs_put_locked  = gen_export_put_locked,
 };
+
+#endif /* HAVE_SERVER_SUPPORT */