Whamcloud - gitweb
LU-1399 config: check lustre_cfg_new() return
[fs/lustre-release.git] / lustre / obdclass / obd_config.c
index e7222da..05505c3 100644 (file)
@@ -27,7 +27,7 @@
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  *
- * Copyright (c) 2011, Whamcloud, Inc.
+ * Copyright (c) 2011, 2013, Intel Corporation.
  */
 /*
  * This file is part of Lustre, http://www.lustre.org/
  */
 
 #define DEBUG_SUBSYSTEM S_CLASS
-#ifdef __KERNEL__
 #include <obd_class.h>
 #include <linux/string.h>
-#else
-#include <liblustre.h>
-#include <obd_class.h>
-#include <obd.h>
-#endif
+#include <lustre_disk.h>
+#include <lustre_ioctl.h>
 #include <lustre_log.h>
 #include <lprocfs_status.h>
-#include <libcfs/list.h>
 #include <lustre_param.h>
 
+#include "llog_internal.h"
+
 static cfs_hash_ops_t uuid_hash_ops;
 static cfs_hash_ops_t nid_hash_ops;
 static cfs_hash_ops_t nid_stat_hash_ops;
@@ -77,6 +74,47 @@ int class_find_param(char *buf, char *key, char **valp)
 EXPORT_SYMBOL(class_find_param);
 
 /**
+ * Check whether the proc parameter \a param is an old parameter or not from
+ * the array \a ptr which contains the mapping from old parameters to new ones.
+ * If it's an old one, then return the pointer to the cfg_interop_param struc-
+ * ture which contains both the old and new parameters.
+ *
+ * \param param                        proc parameter
+ * \param ptr                  an array which contains the mapping from
+ *                             old parameters to new ones
+ *
+ * \retval valid-pointer       pointer to the cfg_interop_param structure
+ *                             which contains the old and new parameters
+ * \retval NULL                        \a param or \a ptr is NULL,
+ *                             or \a param is not an old parameter
+ */
+struct cfg_interop_param *class_find_old_param(const char *param,
+                                              struct cfg_interop_param *ptr)
+{
+       char *value = NULL;
+       int   name_len = 0;
+
+       if (param == NULL || ptr == NULL)
+               RETURN(NULL);
+
+       value = strchr(param, '=');
+       if (value == NULL)
+               name_len = strlen(param);
+       else
+               name_len = value - param;
+
+       while (ptr->old_param != NULL) {
+               if (strncmp(param, ptr->old_param, name_len) == 0 &&
+                   name_len == strlen(ptr->old_param))
+                       RETURN(ptr);
+               ptr++;
+       }
+
+       RETURN(NULL);
+}
+EXPORT_SYMBOL(class_find_old_param);
+
+/**
  * Finds a parameter in \a params and copies it to \a copy.
  *
  * Leading spaces are skipped. Next space or end of string is the
@@ -160,7 +198,7 @@ int class_match_param(char *buf, char *key, char **valp)
 }
 EXPORT_SYMBOL(class_match_param);
 
-static int parse_nid(char *buf, void *value)
+static int parse_nid(char *buf, void *value, int quiet)
 {
         lnet_nid_t *nid = (lnet_nid_t *)value;
 
@@ -168,7 +206,8 @@ static int parse_nid(char *buf, void *value)
         if (*nid != LNET_NID_ANY)
                 return 0;
 
-        LCONSOLE_ERROR_MSG(0x159, "Can't parse NID '%s'\n", buf);
+       if (!quiet)
+               LCONSOLE_ERROR_MSG(0x159, "Can't parse NID '%s'\n", buf);
         return -EINVAL;
 }
 
@@ -190,7 +229,8 @@ enum {
    1 not found
    < 0 error
    endh is set to next separator */
-static int class_parse_value(char *buf, int opc, void *value, char **endh)
+static int class_parse_value(char *buf, int opc, void *value, char **endh,
+                            int quiet)
 {
         char *endp;
         char  tmp;
@@ -214,7 +254,7 @@ static int class_parse_value(char *buf, int opc, void *value, char **endh)
         default:
                 LBUG();
         case CLASS_PARSE_NID:
-                rc = parse_nid(buf, value);
+               rc = parse_nid(buf, value, quiet);
                 break;
         case CLASS_PARSE_NET:
                 rc = parse_net(buf, value);
@@ -230,13 +270,19 @@ static int class_parse_value(char *buf, int opc, void *value, char **endh)
 
 int class_parse_nid(char *buf, lnet_nid_t *nid, char **endh)
 {
-        return class_parse_value(buf, CLASS_PARSE_NID, (void *)nid, 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)
+{
+       return class_parse_value(buf, CLASS_PARSE_NID, (void *)nid, endh, 1);
+}
+EXPORT_SYMBOL(class_parse_nid_quiet);
+
 int class_parse_net(char *buf, __u32 *net, char **endh)
 {
-        return class_parse_value(buf, CLASS_PARSE_NET, (void *)net, endh);
+       return class_parse_value(buf, CLASS_PARSE_NET, (void *)net, endh, 0);
 }
 EXPORT_SYMBOL(class_parse_net);
 
@@ -331,36 +377,37 @@ int class_attach(struct lustre_cfg *lcfg)
         LASSERTF(strncmp(obd->obd_name, name, strlen(name)) == 0,
                  "%p obd_name %s != %s\n", obd, obd->obd_name, name);
 
-        cfs_rwlock_init(&obd->obd_pool_lock);
-        obd->obd_pool_limit = 0;
-        obd->obd_pool_slv = 0;
-
-        CFS_INIT_LIST_HEAD(&obd->obd_exports);
-        CFS_INIT_LIST_HEAD(&obd->obd_unlinked_exports);
-        CFS_INIT_LIST_HEAD(&obd->obd_delayed_exports);
-        CFS_INIT_LIST_HEAD(&obd->obd_exports_timed);
-        CFS_INIT_LIST_HEAD(&obd->obd_nid_stats);
-        cfs_spin_lock_init(&obd->obd_nid_lock);
-        cfs_spin_lock_init(&obd->obd_dev_lock);
-        cfs_mutex_init(&obd->obd_dev_mutex);
-        cfs_spin_lock_init(&obd->obd_osfs_lock);
-        /* obd->obd_osfs_age must be set to a value in the distant
-         * past to guarantee a fresh statfs is fetched on mount. */
-        obd->obd_osfs_age = cfs_time_shift_64(-1000);
-
-        /* XXX belongs in setup not attach  */
-        cfs_init_rwsem(&obd->obd_observer_link_sem);
-        /* recovery data */
-        cfs_init_timer(&obd->obd_recovery_timer);
-        cfs_spin_lock_init(&obd->obd_recovery_task_lock);
-        cfs_waitq_init(&obd->obd_next_transno_waitq);
-        cfs_waitq_init(&obd->obd_evict_inprogress_waitq);
-        CFS_INIT_LIST_HEAD(&obd->obd_req_replay_queue);
-        CFS_INIT_LIST_HEAD(&obd->obd_lock_replay_queue);
-        CFS_INIT_LIST_HEAD(&obd->obd_final_req_queue);
-        CFS_INIT_LIST_HEAD(&obd->obd_evict_list);
-
-        llog_group_init(&obd->obd_olg, FID_SEQ_LLOG);
+       rwlock_init(&obd->obd_pool_lock);
+       obd->obd_pool_limit = 0;
+       obd->obd_pool_slv = 0;
+
+       INIT_LIST_HEAD(&obd->obd_exports);
+       INIT_LIST_HEAD(&obd->obd_unlinked_exports);
+       INIT_LIST_HEAD(&obd->obd_delayed_exports);
+       INIT_LIST_HEAD(&obd->obd_exports_timed);
+       INIT_LIST_HEAD(&obd->obd_nid_stats);
+       spin_lock_init(&obd->obd_nid_lock);
+       spin_lock_init(&obd->obd_dev_lock);
+       mutex_init(&obd->obd_dev_mutex);
+       spin_lock_init(&obd->obd_osfs_lock);
+       /* obd->obd_osfs_age must be set to a value in the distant
+        * past to guarantee a fresh statfs is fetched on mount. */
+       obd->obd_osfs_age = cfs_time_shift_64(-1000);
+
+       /* XXX belongs in setup not attach  */
+       init_rwsem(&obd->obd_observer_link_sem);
+       /* recovery data */
+       cfs_init_timer(&obd->obd_recovery_timer);
+       spin_lock_init(&obd->obd_recovery_task_lock);
+       init_waitqueue_head(&obd->obd_next_transno_waitq);
+       init_waitqueue_head(&obd->obd_evict_inprogress_waitq);
+       INIT_LIST_HEAD(&obd->obd_req_replay_queue);
+       INIT_LIST_HEAD(&obd->obd_lock_replay_queue);
+       INIT_LIST_HEAD(&obd->obd_final_req_queue);
+       INIT_LIST_HEAD(&obd->obd_evict_list);
+       INIT_LIST_HEAD(&obd->obd_lwp_list);
+
+       llog_group_init(&obd->obd_olg);
 
        obd->obd_conn_inprogress = 0;
 
@@ -372,23 +419,16 @@ int class_attach(struct lustre_cfg *lcfg)
         }
         memcpy(obd->obd_uuid.uuid, uuid, len);
 
-        /* do the attach */
-        if (OBP(obd, attach)) {
-                rc = OBP(obd,attach)(obd, sizeof *lcfg, lcfg);
-                if (rc)
-                        GOTO(out, rc = -EINVAL);
-        }
-
         /* Detach drops this */
-        cfs_spin_lock(&obd->obd_dev_lock);
-        cfs_atomic_set(&obd->obd_refcount, 1);
-        cfs_spin_unlock(&obd->obd_dev_lock);
+       spin_lock(&obd->obd_dev_lock);
+       atomic_set(&obd->obd_refcount, 1);
+       spin_unlock(&obd->obd_dev_lock);
         lu_ref_init(&obd->obd_reference);
         lu_ref_add(&obd->obd_reference, "attach", obd);
 
         obd->obd_attached = 1;
         CDEBUG(D_IOCTL, "OBD: dev %d attached type %s with refcount %d\n",
-               obd->obd_minor, typename, cfs_atomic_read(&obd->obd_refcount));
+              obd->obd_minor, typename, atomic_read(&obd->obd_refcount));
         RETURN(0);
  out:
         if (obd != NULL) {
@@ -428,9 +468,9 @@ int class_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
         }
 
         /* is someone else setting us up right now? (attach inits spinlock) */
-        cfs_spin_lock(&obd->obd_dev_lock);
-        if (obd->obd_starting) {
-                cfs_spin_unlock(&obd->obd_dev_lock);
+       spin_lock(&obd->obd_dev_lock);
+       if (obd->obd_starting) {
+               spin_unlock(&obd->obd_dev_lock);
                 CERROR("Device %d setup in progress (type %s)\n",
                        obd->obd_minor, obd->obd_type->typ_name);
                 RETURN(-EEXIST);
@@ -441,7 +481,7 @@ int class_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
         obd->obd_uuid_hash = NULL;
         obd->obd_nid_hash = NULL;
         obd->obd_nid_stats_hash = NULL;
-        cfs_spin_unlock(&obd->obd_dev_lock);
+       spin_unlock(&obd->obd_dev_lock);
 
         /* create an uuid-export lustre hash */
         obd->obd_uuid_hash = cfs_hash_create("UUID_HASH",
@@ -481,7 +521,7 @@ int class_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
                 GOTO(err_hash, err = PTR_ERR(exp));
 
         obd->obd_self_export = exp;
-        cfs_list_del_init(&exp->exp_obd_chain_timed);
+       list_del_init(&exp->exp_obd_chain_timed);
         class_export_put(exp);
 
         err = obd_setup(obd, lcfg);
@@ -490,10 +530,10 @@ int class_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
 
         obd->obd_set_up = 1;
 
-        cfs_spin_lock(&obd->obd_dev_lock);
-        /* cleanup drops this */
-        class_incref(obd, "setup", obd);
-        cfs_spin_unlock(&obd->obd_dev_lock);
+       spin_lock(&obd->obd_dev_lock);
+       /* cleanup drops this */
+       class_incref(obd, "setup", obd);
+       spin_unlock(&obd->obd_dev_lock);
 
         CDEBUG(D_IOCTL, "finished setup of obd %s (uuid %s)\n",
                obd->obd_name, obd->obd_uuid.uuid);
@@ -535,14 +575,14 @@ int class_detach(struct obd_device *obd, struct lustre_cfg *lcfg)
                 RETURN(-EBUSY);
         }
 
-        cfs_spin_lock(&obd->obd_dev_lock);
-        if (!obd->obd_attached) {
-                cfs_spin_unlock(&obd->obd_dev_lock);
-                CERROR("OBD device %d not attached\n", obd->obd_minor);
-                RETURN(-ENODEV);
-        }
-        obd->obd_attached = 0;
-        cfs_spin_unlock(&obd->obd_dev_lock);
+       spin_lock(&obd->obd_dev_lock);
+       if (!obd->obd_attached) {
+               spin_unlock(&obd->obd_dev_lock);
+               CERROR("OBD device %d not attached\n", obd->obd_minor);
+               RETURN(-ENODEV);
+       }
+       obd->obd_attached = 0;
+       spin_unlock(&obd->obd_dev_lock);
 
         CDEBUG(D_IOCTL, "detach on obd %s (uuid %s)\n",
                obd->obd_name, obd->obd_uuid.uuid);
@@ -569,24 +609,20 @@ int class_cleanup(struct obd_device *obd, struct lustre_cfg *lcfg)
                 RETURN(-ENODEV);
         }
 
-        cfs_spin_lock(&obd->obd_dev_lock);
-        if (obd->obd_stopping) {
-                cfs_spin_unlock(&obd->obd_dev_lock);
-                CERROR("OBD %d already stopping\n", obd->obd_minor);
-                RETURN(-ENODEV);
-        }
-        /* Leave this on forever */
-        obd->obd_stopping = 1;
+       spin_lock(&obd->obd_dev_lock);
+       if (obd->obd_stopping) {
+               spin_unlock(&obd->obd_dev_lock);
+               CERROR("OBD %d already stopping\n", obd->obd_minor);
+               RETURN(-ENODEV);
+       }
+       /* Leave this on forever */
+       obd->obd_stopping = 1;
+       spin_unlock(&obd->obd_dev_lock);
 
        /* wait for already-arrived-connections to finish. */
-       while (obd->obd_conn_inprogress > 0) {
-               cfs_spin_unlock(&obd->obd_dev_lock);
-
-               cfs_cond_resched();
-
-               cfs_spin_lock(&obd->obd_dev_lock);
-       }
-       cfs_spin_unlock(&obd->obd_dev_lock);
+       while (obd->obd_conn_inprogress > 0)
+               yield();
+       smp_rmb();
 
         if (lcfg->lcfg_bufcount >= 2 && LUSTRE_CFG_BUFLEN(lcfg, 1) > 0) {
                 for (flag = lustre_cfg_string(lcfg, 1); *flag != 0; flag++)
@@ -615,12 +651,12 @@ int class_cleanup(struct obd_device *obd, struct lustre_cfg *lcfg)
 
         /* The three references that should be remaining are the
          * obd_self_export and the attach and setup references. */
-        if (cfs_atomic_read(&obd->obd_refcount) > 3) {
+       if (atomic_read(&obd->obd_refcount) > 3) {
                 /* refcounf - 3 might be the number of real exports
                    (excluding self export). But class_incref is called
                    by other things as well, so don't count on it. */
                 CDEBUG(D_IOCTL, "%s: forcing exports to disconnect: %d\n",
-                       obd->obd_name, cfs_atomic_read(&obd->obd_refcount) - 3);
+                      obd->obd_name, atomic_read(&obd->obd_refcount) - 3);
                 dump_exports(obd, 0);
                 class_disconnect_exports(obd);
         }
@@ -660,9 +696,9 @@ struct obd_device *class_incref(struct obd_device *obd,
                                 const char *scope, const void *source)
 {
         lu_ref_add_atomic(&obd->obd_reference, scope, source);
-        cfs_atomic_inc(&obd->obd_refcount);
+       atomic_inc(&obd->obd_refcount);
         CDEBUG(D_INFO, "incref %s (%p) now %d\n", obd->obd_name, obd,
-               cfs_atomic_read(&obd->obd_refcount));
+              atomic_read(&obd->obd_refcount));
 
         return obd;
 }
@@ -670,24 +706,24 @@ EXPORT_SYMBOL(class_incref);
 
 void class_decref(struct obd_device *obd, const char *scope, const void *source)
 {
-        int err;
-        int refs;
+       int err;
+       int refs;
 
-        cfs_spin_lock(&obd->obd_dev_lock);
-        cfs_atomic_dec(&obd->obd_refcount);
-        refs = cfs_atomic_read(&obd->obd_refcount);
-        cfs_spin_unlock(&obd->obd_dev_lock);
-        lu_ref_del(&obd->obd_reference, scope, source);
+       spin_lock(&obd->obd_dev_lock);
+       atomic_dec(&obd->obd_refcount);
+       refs = atomic_read(&obd->obd_refcount);
+       spin_unlock(&obd->obd_dev_lock);
+       lu_ref_del(&obd->obd_reference, scope, source);
 
-        CDEBUG(D_INFO, "Decref %s (%p) now %d\n", obd->obd_name, obd, refs);
+       CDEBUG(D_INFO, "Decref %s (%p) now %d\n", obd->obd_name, obd, refs);
 
-        if ((refs == 1) && obd->obd_stopping) {
-                /* All exports have been destroyed; there should
-                   be no more in-progress ops by this point.*/
+       if ((refs == 1) && obd->obd_stopping) {
+               /* All exports have been destroyed; there should
+                  be no more in-progress ops by this point.*/
 
-                cfs_spin_lock(&obd->obd_self_export->exp_lock);
-                obd->obd_self_export->exp_flags |= exp_flags_from_obd(obd);
-                cfs_spin_unlock(&obd->obd_self_export->exp_lock);
+               spin_lock(&obd->obd_self_export->exp_lock);
+               obd->obd_self_export->exp_flags |= exp_flags_from_obd(obd);
+               spin_unlock(&obd->obd_self_export->exp_lock);
 
                 /* note that we'll recurse into class_decref again */
                 class_unlink_export(obd->obd_self_export);
@@ -705,11 +741,7 @@ void class_decref(struct obd_device *obd, const char *scope, const void *source)
                                 CERROR("Cleanup %s returned %d\n",
                                        obd->obd_name, err);
                 }
-                if (OBP(obd, detach)) {
-                        err = OBP(obd, detach)(obd);
-                        if (err)
-                                CERROR("Detach returned %d\n", err);
-                }
+
                 class_release_dev(obd);
         }
 }
@@ -732,6 +764,8 @@ int class_add_conn(struct obd_device *obd, struct lustre_cfg *lcfg)
         }
         if (strcmp(obd->obd_type->typ_name, LUSTRE_MDC_NAME) &&
             strcmp(obd->obd_type->typ_name, LUSTRE_OSC_NAME) &&
+           strcmp(obd->obd_type->typ_name, LUSTRE_OSP_NAME) &&
+           strcmp(obd->obd_type->typ_name, LUSTRE_LWP_NAME) &&
             strcmp(obd->obd_type->typ_name, LUSTRE_MGC_NAME)) {
                 CERROR("can't add connection on non-client dev\n");
                 RETURN(-EINVAL);
@@ -748,10 +782,11 @@ int class_add_conn(struct obd_device *obd, struct lustre_cfg *lcfg)
 
         RETURN(rc);
 }
+EXPORT_SYMBOL(class_add_conn);
 
 /** Remove a failover nid location.
  */
-int class_del_conn(struct obd_device *obd, struct lustre_cfg *lcfg)
+static int class_del_conn(struct obd_device *obd, struct lustre_cfg *lcfg)
 {
         struct obd_import *imp;
         struct obd_uuid uuid;
@@ -781,14 +816,15 @@ int class_del_conn(struct obd_device *obd, struct lustre_cfg *lcfg)
         RETURN(rc);
 }
 
-CFS_LIST_HEAD(lustre_profile_list);
+static struct list_head lustre_profile_list =
+       LIST_HEAD_INIT(lustre_profile_list);
 
 struct lustre_profile *class_get_profile(const char * prof)
 {
         struct lustre_profile *lprof;
 
         ENTRY;
-        cfs_list_for_each_entry(lprof, &lustre_profile_list, lp_list) {
+       list_for_each_entry(lprof, &lustre_profile_list, lp_list) {
                 if (!strcmp(lprof->lp_profile, prof)) {
                         RETURN(lprof);
                 }
@@ -801,8 +837,8 @@ EXPORT_SYMBOL(class_get_profile);
  * This defines the mdc and osc names to use for a client.
  * This also is used to define the lov to be used by a mdt.
  */
-int class_add_profile(int proflen, char *prof, int osclen, char *osc,
-                      int mdclen, char *mdc)
+static int class_add_profile(int proflen, char *prof, int osclen, char *osc,
+                            int mdclen, char *mdc)
 {
         struct lustre_profile *lprof;
         int err = 0;
@@ -813,7 +849,7 @@ int class_add_profile(int proflen, char *prof, int osclen, char *osc,
         OBD_ALLOC(lprof, sizeof(*lprof));
         if (lprof == NULL)
                 RETURN(-ENOMEM);
-        CFS_INIT_LIST_HEAD(&lprof->lp_list);
+       INIT_LIST_HEAD(&lprof->lp_list);
 
         LASSERT(proflen == (strlen(prof) + 1));
         OBD_ALLOC(lprof->lp_profile, proflen);
@@ -835,7 +871,7 @@ int class_add_profile(int proflen, char *prof, int osclen, char *osc,
                 memcpy(lprof->lp_md, mdc, mdclen);
         }
 
-        cfs_list_add(&lprof->lp_list, &lustre_profile_list);
+       list_add(&lprof->lp_list, &lustre_profile_list);
         RETURN(err);
 
 out:
@@ -858,7 +894,7 @@ void class_del_profile(const char *prof)
 
         lprof = class_get_profile(prof);
         if (lprof) {
-                cfs_list_del(&lprof->lp_list);
+               list_del(&lprof->lp_list);
                 OBD_FREE(lprof->lp_profile, strlen(lprof->lp_profile) + 1);
                 OBD_FREE(lprof->lp_dt, strlen(lprof->lp_dt) + 1);
                 if (lprof->lp_md)
@@ -875,8 +911,8 @@ void class_del_profiles(void)
         struct lustre_profile *lprof, *n;
         ENTRY;
 
-        cfs_list_for_each_entry_safe(lprof, n, &lustre_profile_list, lp_list) {
-                cfs_list_del(&lprof->lp_list);
+       list_for_each_entry_safe(lprof, n, &lustre_profile_list, lp_list) {
+               list_del(&lprof->lp_list);
                 OBD_FREE(lprof->lp_profile, strlen(lprof->lp_profile) + 1);
                 OBD_FREE(lprof->lp_dt, strlen(lprof->lp_dt) + 1);
                 if (lprof->lp_md)
@@ -900,11 +936,10 @@ static int class_set_global(char *ptr, int val, struct lustre_cfg *lcfg)
                at_early_margin = val;
        else if (class_match_param(ptr, PARAM_AT_HISTORY, NULL) == 0)
                at_history = val;
-       else if (class_match_param(ptr, PARAM_JOBID_VAR, NULL) == 0) {
-               memset(obd_jobid_var, 0, JOBSTATS_JOBID_VAR_MAX_LEN + 1);
-               memcpy(obd_jobid_var, lustre_cfg_string(lcfg, 2),
-                      JOBSTATS_JOBID_VAR_MAX_LEN + 1);
-       } else
+       else if (class_match_param(ptr, PARAM_JOBID_VAR, NULL) == 0)
+               strlcpy(obd_jobid_var, lustre_cfg_string(lcfg, 2),
+                       JOBSTATS_JOBID_VAR_MAX_LEN + 1);
+       else
                RETURN(-EINVAL);
 
        CDEBUG(D_IOCTL, "global %s = %d\n", ptr, val);
@@ -912,9 +947,10 @@ static int class_set_global(char *ptr, int val, struct lustre_cfg *lcfg)
 }
 
 
-/* We can't call ll_process_config directly because it lives in a module that
  must be loaded after this one. */
+/* We can't call ll_process_config or lquota_process_config directly because
* it lives in a module that must be loaded after this one. */
 static int (*client_process_config)(struct lustre_cfg *lcfg) = NULL;
+static int (*quota_process_config)(struct lustre_cfg *lcfg) = NULL;
 
 void lustre_register_client_process_config(int (*cpc)(struct lustre_cfg *lcfg))
 {
@@ -980,7 +1016,6 @@ struct lustre_cfg *lustre_cfg_rename(struct lustre_cfg *cfg,
        lustre_cfg_bufs_set_string(bufs, 1, new_param);
 
        new_cfg = lustre_cfg_new(cfg->lcfg_command, bufs);
-
        OBD_FREE(new_param, new_len);
        OBD_FREE_PTR(bufs);
        if (new_cfg == NULL)
@@ -995,6 +1030,51 @@ struct lustre_cfg *lustre_cfg_rename(struct lustre_cfg *cfg,
 }
 EXPORT_SYMBOL(lustre_cfg_rename);
 
+static int process_param2_config(struct lustre_cfg *lcfg)
+{
+       char *param = lustre_cfg_string(lcfg, 1);
+       char *upcall = lustre_cfg_string(lcfg, 2);
+       char *argv[] = {
+               [0] = "/usr/sbin/lctl",
+               [1] = "set_param",
+               [2] = param,
+               [3] = NULL
+       };
+       struct timeval  start;
+       struct timeval  end;
+       int             rc;
+       ENTRY;
+
+       /* Add upcall processing here. Now only lctl is supported */
+       if (strcmp(upcall, LCTL_UPCALL) != 0) {
+               CERROR("Unsupported upcall %s\n", upcall);
+               RETURN(-EINVAL);
+       }
+
+       do_gettimeofday(&start);
+       rc = call_usermodehelper(argv[0], argv, NULL, 0);
+       do_gettimeofday(&end);
+
+       if (rc < 0) {
+               CERROR("lctl: error invoking upcall %s %s %s: rc = %d; "
+                      "time %ldus\n", argv[0], argv[1], argv[2], rc,
+                      cfs_timeval_sub(&end, &start, NULL));
+       } else {
+               CDEBUG(D_HA, "lctl: invoked upcall %s %s %s, time %ldus\n",
+                      argv[0], argv[1], argv[2],
+                      cfs_timeval_sub(&end, &start, NULL));
+                      rc = 0;
+       }
+
+       RETURN(rc);
+}
+
+void lustre_register_quota_process_config(int (*qpc)(struct lustre_cfg *lcfg))
+{
+       quota_process_config = qpc;
+}
+EXPORT_SYMBOL(lustre_register_quota_process_config);
+
 /** Process configuration commands given in lustre_cfg form.
  * These may come from direct calls (e.g. class_manual_cleanup)
  * or processing the config llog, or ioctl from lctl.
@@ -1090,18 +1170,28 @@ int class_process_config(struct lustre_cfg *lcfg)
                                               PARAM_SYS, &tmp) == 0)) {
                         /* Global param settings */
                        err = class_set_global(tmp, lcfg->lcfg_num, lcfg);
-                        /* Note that since LCFG_PARAM is LCFG_REQUIRED, new
-                           unknown globals would cause config to fail */
-                        if (err)
-                                CWARN("Ignoring unknown param %s\n", tmp);
-                        GOTO(out, 0);
-                }
-
-                /* Fall through */
-                break;
-        }
-        }
-
+                       /*
+                        * Client or server should not fail to mount if
+                        * it hits an unknown configuration parameter.
+                        */
+                       if (err != 0)
+                               CWARN("Ignoring unknown param %s\n", tmp);
+
+                       GOTO(out, err = 0);
+               } else if ((class_match_param(lustre_cfg_string(lcfg, 1),
+                                             PARAM_QUOTA, &tmp) == 0) &&
+                          quota_process_config) {
+                       err = (*quota_process_config)(lcfg);
+                       GOTO(out, err);
+               }
+
+               break;
+       }
+       case LCFG_SET_PARAM: {
+               err = process_param2_config(lcfg);
+               GOTO(out, err = 0);
+       }
+       }
         /* Commands that require a device */
         obd = class_name2obd(lustre_cfg_string(lcfg, 0));
         if (obd == NULL) {
@@ -1114,11 +1204,11 @@ int class_process_config(struct lustre_cfg *lcfg)
                 GOTO(out, err = -EINVAL);
         }
 
-        switch(lcfg->lcfg_command) {
-        case LCFG_SETUP: {
-                err = class_setup(obd, lcfg);
-                GOTO(out, err);
-        }
+       switch(lcfg->lcfg_command) {
+       case LCFG_SETUP: {
+               err = class_setup(obd, lcfg);
+               GOTO(out, err);
+       }
         case LCFG_DETACH: {
                 err = class_detach(obd, lcfg);
                 GOTO(out, err = 0);
@@ -1138,24 +1228,20 @@ int class_process_config(struct lustre_cfg *lcfg)
         case LCFG_POOL_NEW: {
                 err = obd_pool_new(obd, lustre_cfg_string(lcfg, 2));
                 GOTO(out, err = 0);
-                break;
         }
         case LCFG_POOL_ADD: {
                 err = obd_pool_add(obd, lustre_cfg_string(lcfg, 2),
                                    lustre_cfg_string(lcfg, 3));
                 GOTO(out, err = 0);
-                break;
         }
         case LCFG_POOL_REM: {
                 err = obd_pool_rem(obd, lustre_cfg_string(lcfg, 2),
                                    lustre_cfg_string(lcfg, 3));
                 GOTO(out, err = 0);
-                break;
         }
         case LCFG_POOL_DEL: {
                 err = obd_pool_del(obd, lustre_cfg_string(lcfg, 2));
                 GOTO(out, err = 0);
-                break;
         }
         default: {
                 err = obd_process_config(obd, sizeof(*lcfg), lcfg);
@@ -1173,110 +1259,138 @@ out:
 }
 EXPORT_SYMBOL(class_process_config);
 
-int class_process_proc_param(char *prefix, struct lprocfs_vars *lvars,
-                             struct lustre_cfg *lcfg, void *data)
+int class_process_proc_param(char *prefix, struct lprocfs_seq_vars *lvars,
+                            struct lustre_cfg *lcfg, void *data)
 {
-#ifdef __KERNEL__
-        struct lprocfs_vars *var;
-        char *key, *sval;
-        int i, keylen, vallen;
-        int matched = 0, j = 0;
-        int rc = 0;
-        int skip = 0;
-        ENTRY;
+       struct lprocfs_seq_vars *var;
+       struct file fakefile;
+       struct seq_file fake_seqfile;
+       char *key, *sval;
+       int i, keylen, vallen;
+       int matched = 0, j = 0;
+       int rc = 0;
+       int skip = 0;
+       ENTRY;
 
-        if (lcfg->lcfg_command != LCFG_PARAM) {
-                CERROR("Unknown command: %d\n", lcfg->lcfg_command);
-                RETURN(-EINVAL);
-        }
+       if (lcfg->lcfg_command != LCFG_PARAM) {
+               CERROR("Unknown command: %d\n", lcfg->lcfg_command);
+               RETURN(-EINVAL);
+       }
 
-        /* e.g. tunefs.lustre --param mdt.group_upcall=foo /r/tmp/lustre-mdt
-           or   lctl conf_param lustre-MDT0000.mdt.group_upcall=bar
-           or   lctl conf_param lustre-OST0000.osc.max_dirty_mb=36 */
-        for (i = 1; i < lcfg->lcfg_bufcount; i++) {
-                key = lustre_cfg_buf(lcfg, i);
-                /* Strip off prefix */
-                class_match_param(key, prefix, &key);
-                sval = strchr(key, '=');
-                if (!sval || (*(sval + 1) == 0)) {
-                        CERROR("Can't parse param %s (missing '=')\n", key);
-                        /* rc = -EINVAL;        continue parsing other params */
-                        continue;
-                }
-                keylen = sval - key;
-                sval++;
-                vallen = strlen(sval);
-                matched = 0;
-                j = 0;
-                /* Search proc entries */
-                while (lvars[j].name) {
-                        var = &lvars[j];
-                        if (class_match_param(key, (char *)var->name, 0) == 0 &&
-                            keylen == strlen(var->name)) {
-                                matched++;
-                                rc = -EROFS;
-                                if (var->write_fptr) {
-                                        mm_segment_t oldfs;
-                                        oldfs = get_fs();
-                                        set_fs(KERNEL_DS);
-                                        rc = (var->write_fptr)(NULL, sval,
-                                                               vallen, data);
-                                        set_fs(oldfs);
-                                }
-                                break;
-                        }
-                        j++;
-                }
-                if (!matched) {
-                        /* If the prefix doesn't match, return error so we
-                           can pass it down the stack */
-                        if (strnchr(key, keylen, '.'))
-                            RETURN(-ENOSYS);
-                        CERROR("%s: unknown param %s\n",
-                               (char *)lustre_cfg_string(lcfg, 0), key);
-                        /* rc = -EINVAL;        continue parsing other params */
-                        skip++;
-                } else if (rc < 0) {
-                        CERROR("writing proc entry %s err %d\n",
-                               var->name, rc);
-                        rc = 0;
-                } else {
-                        CDEBUG(D_CONFIG, "%s.%.*s: set parameter %.*s=%s\n",
-                                      lustre_cfg_string(lcfg, 0),
-                                      (int)strlen(prefix) - 1, prefix,
-                                      (int)(sval - key - 1), key, sval);
-                }
-        }
+       /* fake a seq file so that var->fops->write can work... */
+       fakefile.private_data = &fake_seqfile;
+       fake_seqfile.private = data;
+       /* e.g. tunefs.lustre --param mdt.group_upcall=foo /r/tmp/lustre-mdt
+          or   lctl conf_param lustre-MDT0000.mdt.group_upcall=bar
+          or   lctl conf_param lustre-OST0000.osc.max_dirty_mb=36 */
+       for (i = 1; i < lcfg->lcfg_bufcount; i++) {
+               key = lustre_cfg_buf(lcfg, i);
+               /* Strip off prefix */
+               if (class_match_param(key, prefix, &key))
+                       /* If the prefix doesn't match, return error so we
+                        * can pass it down the stack */
+                       RETURN(-ENOSYS);
+               sval = strchr(key, '=');
+               if (!sval || (*(sval + 1) == 0)) {
+                       CERROR("Can't parse param %s (missing '=')\n", key);
+                       /* rc = -EINVAL;        continue parsing other params */
+                       continue;
+               }
+               keylen = sval - key;
+               sval++;
+               vallen = strlen(sval);
+               matched = 0;
+               j = 0;
+               /* Search proc entries */
+               while (lvars[j].name) {
+                       var = &lvars[j];
+                       if (class_match_param(key, (char *)var->name, 0) == 0 &&
+                           keylen == strlen(var->name)) {
+                               matched++;
+                               rc = -EROFS;
+
+                               if (var->fops && var->fops->write) {
+                                       mm_segment_t oldfs;
+                                       oldfs = get_fs();
+                                       set_fs(KERNEL_DS);
+                                       rc = (var->fops->write)(&fakefile, sval,
+                                                               vallen, NULL);
+                                       set_fs(oldfs);
+                               }
+                               break;
+                       }
+                       j++;
+               }
+               if (!matched) {
+                       CERROR("%.*s: %s unknown param %s\n",
+                              (int)strlen(prefix) - 1, prefix,
+                              (char *)lustre_cfg_string(lcfg, 0), key);
+                       /* rc = -EINVAL;        continue parsing other params */
+                       skip++;
+               } else if (rc < 0) {
+                       CERROR("%s: error writing proc entry '%s': rc = %d\n",
+                              prefix, var->name, rc);
+                       rc = 0;
+               } else {
+                       CDEBUG(D_CONFIG, "%s.%.*s: Set parameter %.*s=%s\n",
+                                        lustre_cfg_string(lcfg, 0),
+                                        (int)strlen(prefix) - 1, prefix,
+                                        (int)(sval - key - 1), key, sval);
+               }
+       }
 
-        if (rc > 0)
-                rc = 0;
-        if (!rc && skip)
-                rc = skip;
-        RETURN(rc);
-#else
-        CDEBUG(D_CONFIG, "liblustre can't process params.\n");
-        /* Don't throw config error */
-        RETURN(0);
-#endif
+       if (rc > 0)
+               rc = 0;
+       if (!rc && skip)
+               rc = skip;
+       RETURN(rc);
 }
 EXPORT_SYMBOL(class_process_proc_param);
 
-int class_config_dump_handler(struct llog_handle * handle,
-                              struct llog_rec_hdr *rec, void *data);
+/*
+ * Supplemental functions for config logs, it allocates lustre_cfg
+ * buffers plus initialized llog record header at the beginning.
+ */
+struct llog_cfg_rec *lustre_cfg_rec_new(int cmd, struct lustre_cfg_bufs *bufs)
+{
+       struct llog_cfg_rec     *lcr;
+       int                      reclen;
+
+       ENTRY;
+
+       reclen = lustre_cfg_len(bufs->lcfg_bufcount, bufs->lcfg_buflen);
+       reclen = llog_data_len(reclen) + sizeof(struct llog_rec_hdr) +
+                sizeof(struct llog_rec_tail);
+
+       OBD_ALLOC(lcr, reclen);
+       if (lcr == NULL)
+               RETURN(NULL);
+
+       lustre_cfg_init(&lcr->lcr_cfg, cmd, bufs);
 
-#ifdef __KERNEL__
-extern int lustre_check_exclusion(struct super_block *sb, char *svname);
-#else
-#define lustre_check_exclusion(a,b)  0
-#endif
+       lcr->lcr_hdr.lrh_len = reclen;
+       lcr->lcr_hdr.lrh_type = OBD_CFG_REC;
+
+       RETURN(lcr);
+}
+EXPORT_SYMBOL(lustre_cfg_rec_new);
+
+void lustre_cfg_rec_free(struct llog_cfg_rec *lcr)
+{
+       ENTRY;
+       OBD_FREE(lcr, lcr->lcr_hdr.lrh_len);
+       EXIT;
+}
+EXPORT_SYMBOL(lustre_cfg_rec_free);
 
 /** Parse a configuration llog, doing various manipulations on them
  * for various reasons, (modifications for compatibility, skip obsolete
  * records, change uuids, etc), then class_process_config() resulting
  * net records.
  */
-static int class_config_llog_handler(struct llog_handle * handle,
-                                     struct llog_rec_hdr *rec, void *data)
+int class_config_llog_handler(const struct lu_env *env,
+                             struct llog_handle *handle,
+                             struct llog_rec_hdr *rec, void *data)
 {
         struct config_llog_instance *clli = data;
         int cfg_len = rec->lrh_len;
@@ -1314,6 +1428,8 @@ static int class_config_llog_handler(struct llog_handle * handle,
                         if (marker->cm_flags & CM_START) {
                                 /* all previous flags off */
                                 clli->cfg_flags = CFG_F_MARKER;
+                               server_name2index(marker->cm_tgtname,
+                                                 &clli->cfg_lwp_idx, NULL);
                                 if (marker->cm_flags & CM_SKIP) {
                                         clli->cfg_flags |= CFG_F_SKIP;
                                         CDEBUG(D_CONFIG, "SKIP #%d\n",
@@ -1372,10 +1488,39 @@ static int class_config_llog_handler(struct llog_handle * handle,
                         }
                 }
 
-                if ((clli->cfg_flags & CFG_F_EXCLUDE) &&
-                    (lcfg->lcfg_command == LCFG_LOV_ADD_OBD))
-                        /* Add inactive instead */
-                        lcfg->lcfg_command = LCFG_LOV_ADD_INA;
+#ifdef HAVE_SERVER_SUPPORT
+               /* newer MDS replaces LOV/OSC with LOD/OSP */
+               {
+                       char *typename = lustre_cfg_string(lcfg, 1);
+
+                       if ((lcfg->lcfg_command == LCFG_ATTACH && typename &&
+                           strcmp(typename, LUSTRE_LOV_NAME) == 0) &&
+                           IS_MDT(s2lsi(clli->cfg_sb))) {
+                               CDEBUG(D_CONFIG,
+                                      "For 2.x interoperability, rename obd "
+                                      "type from lov to lod (%s)\n",
+                                      s2lsi(clli->cfg_sb)->lsi_svname);
+                               strcpy(typename, LUSTRE_LOD_NAME);
+                       }
+                       if ((lcfg->lcfg_command == LCFG_ATTACH && typename &&
+                           strcmp(typename, LUSTRE_OSC_NAME) == 0) &&
+                           IS_MDT(s2lsi(clli->cfg_sb))) {
+                               CDEBUG(D_CONFIG,
+                                      "For 2.x interoperability, rename obd "
+                                      "type from osc to osp (%s)\n",
+                                      s2lsi(clli->cfg_sb)->lsi_svname);
+                               strcpy(typename, LUSTRE_OSP_NAME);
+                       }
+               }
+#endif /* HAVE_SERVER_SUPPORT */
+
+               if (clli->cfg_flags & CFG_F_EXCLUDE) {
+                       CDEBUG(D_CONFIG, "cmd: %x marked EXCLUDED\n",
+                              lcfg->lcfg_command);
+                       if (lcfg->lcfg_command == LCFG_LOV_ADD_OBD)
+                               /* Add inactive instead */
+                               lcfg->lcfg_command = LCFG_LOV_ADD_INA;
+               }
 
                 lustre_cfg_bufs_init(&bufs, lcfg);
 
@@ -1420,6 +1565,8 @@ static int class_config_llog_handler(struct llog_handle * handle,
                 }
 
                 lcfg_new = lustre_cfg_new(lcfg->lcfg_command, &bufs);
+               if (lcfg_new == NULL)
+                       GOTO(out, rc = -ENOMEM);
 
                 lcfg_new->lcfg_num   = lcfg->lcfg_num;
                 lcfg_new->lcfg_flags = lcfg->lcfg_flags;
@@ -1441,7 +1588,7 @@ static int class_config_llog_handler(struct llog_handle * handle,
 
                 lcfg_new->lcfg_nal = 0; /* illegal value for obsolete field */
 
-                rc = class_process_config(lcfg_new);
+               rc = class_process_config(lcfg_new);
                 lustre_cfg_free(lcfg_new);
 
                 if (inst)
@@ -1455,137 +1602,265 @@ static int class_config_llog_handler(struct llog_handle * handle,
         }
 out:
         if (rc) {
-                CERROR("Err %d on cfg command:\n", rc);
-                class_config_dump_handler(handle, rec, data);
+               CERROR("%s: cfg command failed: rc = %d\n",
+                      handle->lgh_ctxt->loc_obd->obd_name, rc);
+               class_config_dump_handler(NULL, handle, rec, data);
         }
         RETURN(rc);
 }
+EXPORT_SYMBOL(class_config_llog_handler);
 
-int class_config_parse_llog(struct llog_ctxt *ctxt, char *name,
-                            struct config_llog_instance *cfg)
+int class_config_parse_llog(const struct lu_env *env, struct llog_ctxt *ctxt,
+                           char *name, struct config_llog_instance *cfg)
 {
-        struct llog_process_cat_data cd = {0, 0};
-        struct llog_handle *llh;
-        int rc, rc2;
-        ENTRY;
-
-        CDEBUG(D_INFO, "looking up llog %s\n", name);
-        rc = llog_create(ctxt, &llh, NULL, name);
-        if (rc)
-                RETURN(rc);
-
-        rc = llog_init_handle(llh, LLOG_F_IS_PLAIN, NULL);
-        if (rc)
-                GOTO(parse_out, rc);
+       struct llog_process_cat_data     cd = {0, 0};
+       struct llog_handle              *llh;
+       llog_cb_t                        callback;
+       int                              rc;
+       ENTRY;
 
-        /* continue processing from where we last stopped to end-of-log */
-        if (cfg)
-                cd.lpcd_first_idx = cfg->cfg_last_idx;
-        cd.lpcd_last_idx = 0;
+       CDEBUG(D_INFO, "looking up llog %s\n", name);
+       rc = llog_open(env, ctxt, &llh, NULL, name, LLOG_OPEN_EXISTS);
+       if (rc)
+               RETURN(rc);
+
+       rc = llog_init_handle(env, llh, LLOG_F_IS_PLAIN, NULL);
+       if (rc)
+               GOTO(parse_out, rc);
+
+       /* continue processing from where we last stopped to end-of-log */
+       if (cfg) {
+               cd.lpcd_first_idx = cfg->cfg_last_idx;
+               callback = cfg->cfg_callback;
+               LASSERT(callback != NULL);
+       } else {
+               callback = class_config_llog_handler;
+       }
 
-        rc = llog_process(llh, class_config_llog_handler, cfg, &cd);
+       cd.lpcd_last_idx = 0;
 
-        CDEBUG(D_CONFIG, "Processed log %s gen %d-%d (rc=%d)\n", name,
-               cd.lpcd_first_idx + 1, cd.lpcd_last_idx, rc);
+       rc = llog_process(env, llh, callback, cfg, &cd);
 
-        if (cfg)
-                cfg->cfg_last_idx = cd.lpcd_last_idx;
+       CDEBUG(D_CONFIG, "Processed log %s gen %d-%d (rc=%d)\n", name,
+              cd.lpcd_first_idx + 1, cd.lpcd_last_idx, rc);
+       if (cfg)
+               cfg->cfg_last_idx = cd.lpcd_last_idx;
 
 parse_out:
-        rc2 = llog_close(llh);
-        if (rc == 0)
-                rc = rc2;
-
+       llog_close(env, llh);
         RETURN(rc);
 }
 EXPORT_SYMBOL(class_config_parse_llog);
 
-int class_config_dump_handler(struct llog_handle * handle,
-                              struct llog_rec_hdr *rec, void *data)
+static struct lcfg_type_data {
+       __u32    ltd_type;
+       char    *ltd_name;
+       char    *ltd_bufs[4];
+} lcfg_data_table[] = {
+       { LCFG_ATTACH, "attach", { "type", "UUID", "3", "4" } },
+       { LCFG_DETACH, "detach", { "1", "2", "3", "4" } },
+       { LCFG_SETUP, "setup", { "UUID", "node", "options", "failout" } },
+       { LCFG_CLEANUP, "cleanup", { "1", "2", "3", "4" } },
+       { LCFG_ADD_UUID, "add_uuid", { "node", "2", "3", "4" }  },
+       { LCFG_DEL_UUID, "del_uuid", { "1", "2", "3", "4" }  },
+       { LCFG_MOUNTOPT, "new_profile", { "name", "lov", "lmv", "4" }  },
+       { LCFG_DEL_MOUNTOPT, "del_mountopt", { "1", "2", "3", "4" } , },
+       { LCFG_SET_TIMEOUT, "set_timeout", { "parameter", "2", "3", "4" }  },
+       { LCFG_SET_UPCALL, "set_upcall", { "1", "2", "3", "4" }  },
+       { LCFG_ADD_CONN, "add_conn", { "node", "2", "3", "4" }  },
+       { LCFG_DEL_CONN, "del_conn", { "1", "2", "3", "4" }  },
+       { LCFG_LOV_ADD_OBD, "add_osc", { "ost", "index", "gen", "UUID" } },
+       { LCFG_LOV_DEL_OBD, "del_osc", { "1", "2", "3", "4" } },
+       { LCFG_PARAM, "set_param", { "parameter", "value", "3", "4" } },
+       { LCFG_MARKER, "marker", { "1", "2", "3", "4" } },
+       { LCFG_LOG_START, "log_start", { "1", "2", "3", "4" } },
+       { LCFG_LOG_END, "log_end", { "1", "2", "3", "4" } },
+       { LCFG_LOV_ADD_INA, "add_osc_inactive", { "1", "2", "3", "4" }  },
+       { LCFG_ADD_MDC, "add_mdc", { "mdt", "index", "gen", "UUID" } },
+       { LCFG_DEL_MDC, "del_mdc", { "1", "2", "3", "4" } },
+       { LCFG_SPTLRPC_CONF, "security", { "parameter", "2", "3", "4" } },
+       { LCFG_POOL_NEW, "new_pool", { "fsname", "pool", "3", "4" }  },
+       { LCFG_POOL_ADD, "add_pool", { "fsname", "pool", "ost", "4" } },
+       { LCFG_POOL_REM, "remove_pool", { "fsname", "pool", "ost", "4" } },
+       { LCFG_POOL_DEL, "del_pool", { "fsname", "pool", "3", "4" } },
+       { LCFG_SET_LDLM_TIMEOUT, "set_ldlm_timeout",
+         { "parameter", "2", "3", "4" } },
+       { 0, NULL, { NULL, NULL, NULL, NULL } }
+};
+
+static struct lcfg_type_data *lcfg_cmd2data(__u32 cmd)
 {
-        int cfg_len = rec->lrh_len;
-        char *cfg_buf = (char*) (rec + 1);
-        char *outstr, *ptr, *end;
-        int rc = 0;
-        ENTRY;
+       int i = 0;
 
-        OBD_ALLOC(outstr, 256);
-        end = outstr + 256;
-        ptr = outstr;
-        if (!outstr) {
-                RETURN(-ENOMEM);
-        }
-        if (rec->lrh_type == OBD_CFG_REC) {
-                struct lustre_cfg *lcfg;
-                int i;
+       while (lcfg_data_table[i].ltd_type != 0) {
+               if (lcfg_data_table[i].ltd_type == cmd)
+                       return &lcfg_data_table[i];
+               i++;
+       }
+       return NULL;
+}
 
-                rc = lustre_cfg_sanity_check(cfg_buf, cfg_len);
-                if (rc)
-                        GOTO(out, rc);
-                lcfg = (struct lustre_cfg *)cfg_buf;
+/**
+ * parse config record and output dump in supplied buffer.
+ * This is separated from class_config_dump_handler() to use
+ * for ioctl needs as well
+ *
+ * Sample Output:
+ * - { 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)
+{
+       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;
+
+       LASSERT(rec->lrh_type == OBD_CFG_REC);
+       rc = lustre_cfg_sanity_check(lcfg, rec->lrh_len);
+       if (rc < 0)
+               return rc;
+
+       ldata = lcfg_cmd2data(lcfg->lcfg_command);
+       if (ldata == NULL)
+               return -ENOTTY;
+
+       if (lcfg->lcfg_command == LCFG_MARKER)
+               return 0;
+
+       /* form YAML entity */
+       ptr += snprintf(ptr, end - ptr, "- { event: %s", ldata->ltd_name);
+
+       if (lcfg->lcfg_flags)
+               ptr += snprintf(ptr, end - ptr, ", flags: %#08x",
+                               lcfg->lcfg_flags);
+       if (lcfg->lcfg_num)
+               ptr += snprintf(ptr, end - ptr, ", num: %#08x",
+                               lcfg->lcfg_num);
+       if (lcfg->lcfg_nid)
+               ptr += snprintf(ptr, end - ptr, ", nid: %s("LPX64")",
+                               libcfs_nid2str(lcfg->lcfg_nid),
+                               lcfg->lcfg_nid);
+
+       if (LUSTRE_CFG_BUFLEN(lcfg, 0) > 0)
+               ptr += snprintf(ptr, end - ptr, ", device: %s",
+                               lustre_cfg_string(lcfg, 0));
+
+       for (i = 1; i < lcfg->lcfg_bufcount; i++) {
+               if (LUSTRE_CFG_BUFLEN(lcfg, i) > 0)
+                       ptr += snprintf(ptr, end - ptr, ", %s: %s",
+                                       ldata->ltd_bufs[i - 1],
+                                       lustre_cfg_string(lcfg, i));
+       }
 
-                ptr += snprintf(ptr, end-ptr, "cmd=%05x ",
-                                lcfg->lcfg_command);
-                if (lcfg->lcfg_flags) {
-                        ptr += snprintf(ptr, end-ptr, "flags=%#08x ",
-                                        lcfg->lcfg_flags);
-                }
-                if (lcfg->lcfg_num) {
-                        ptr += snprintf(ptr, end-ptr, "num=%#08x ",
-                                        lcfg->lcfg_num);
-                }
-                if (lcfg->lcfg_nid) {
-                        ptr += snprintf(ptr, end-ptr, "nid=%s("LPX64")\n     ",
-                                        libcfs_nid2str(lcfg->lcfg_nid),
-                                        lcfg->lcfg_nid);
-                }
-                if (lcfg->lcfg_command == LCFG_MARKER) {
-                        struct cfg_marker *marker = lustre_cfg_buf(lcfg, 1);
-                        ptr += snprintf(ptr, end-ptr, "marker=%d(%#x)%s '%s'",
-                                        marker->cm_step, marker->cm_flags,
-                                        marker->cm_tgtname, marker->cm_comment);
-                } else {
-                        for (i = 0; i <  lcfg->lcfg_bufcount; i++) {
-                                ptr += snprintf(ptr, end-ptr, "%d:%s  ", i,
-                                                lustre_cfg_string(lcfg, i));
-                        }
-                }
-                LCONSOLE(D_WARNING, "   %s\n", outstr);
-        } else {
-                LCONSOLE(D_WARNING, "unhandled lrh_type: %#x\n", rec->lrh_type);
-                rc = -EINVAL;
-        }
-out:
-        OBD_FREE(outstr, 256);
-        RETURN(rc);
+       ptr += snprintf(ptr, end - ptr, " }\n");
+       /* return consumed bytes */
+       rc = ptr - buf;
+       return rc;
 }
 
-int class_config_dump_llog(struct llog_ctxt *ctxt, char *name,
-                           struct config_llog_instance *cfg)
+/**
+ * parse config record and output dump in supplied buffer.
+ * This is separated from class_config_dump_handler() to use
+ * for ioctl needs as well
+ */
+static int class_config_parse_rec(struct llog_rec_hdr *rec, char *buf, int size)
 {
-        struct llog_handle *llh;
-        int rc, rc2;
-        ENTRY;
+       struct lustre_cfg       *lcfg = (struct lustre_cfg *)(rec + 1);
+       char                    *ptr = buf;
+       char                    *end = buf + size;
+       int                      rc = 0;
 
-        LCONSOLE_INFO("Dumping config log %s\n", name);
+       ENTRY;
 
-        rc = llog_create(ctxt, &llh, NULL, name);
-        if (rc)
-                RETURN(rc);
+       LASSERT(rec->lrh_type == OBD_CFG_REC);
+       rc = lustre_cfg_sanity_check(lcfg, rec->lrh_len);
+       if (rc < 0)
+               RETURN(rc);
+
+       ptr += snprintf(ptr, end-ptr, "cmd=%05x ", lcfg->lcfg_command);
+       if (lcfg->lcfg_flags)
+               ptr += snprintf(ptr, end-ptr, "flags=%#08x ",
+                               lcfg->lcfg_flags);
+
+       if (lcfg->lcfg_num)
+               ptr += snprintf(ptr, end-ptr, "num=%#08x ", lcfg->lcfg_num);
+
+       if (lcfg->lcfg_nid)
+               ptr += snprintf(ptr, end-ptr, "nid=%s("LPX64")\n     ",
+                               libcfs_nid2str(lcfg->lcfg_nid),
+                               lcfg->lcfg_nid);
+
+       if (lcfg->lcfg_command == LCFG_MARKER) {
+               struct cfg_marker *marker = lustre_cfg_buf(lcfg, 1);
+
+               ptr += snprintf(ptr, end-ptr, "marker=%d(%#x)%s '%s'",
+                               marker->cm_step, marker->cm_flags,
+                               marker->cm_tgtname, marker->cm_comment);
+       } else {
+               int i;
+
+               for (i = 0; i <  lcfg->lcfg_bufcount; i++) {
+                       ptr += snprintf(ptr, end-ptr, "%d:%s  ", i,
+                                       lustre_cfg_string(lcfg, i));
+               }
+       }
+       ptr += snprintf(ptr, end - ptr, "\n");
+       /* return consumed bytes */
+       rc = ptr - buf;
+       RETURN(rc);
+}
 
-        rc = llog_init_handle(llh, LLOG_F_IS_PLAIN, NULL);
-        if (rc)
-                GOTO(parse_out, rc);
+int class_config_dump_handler(const struct lu_env *env,
+                             struct llog_handle *handle,
+                             struct llog_rec_hdr *rec, void *data)
+{
+       char    *outstr;
+       int      rc = 0;
 
-        rc = llog_process(llh, class_config_dump_handler, cfg, NULL);
-parse_out:
-        rc2 = llog_close(llh);
-        if (rc == 0)
-                rc = rc2;
+       ENTRY;
 
-        LCONSOLE_INFO("End config log %s\n", name);
-        RETURN(rc);
+       OBD_ALLOC(outstr, 256);
+       if (outstr == NULL)
+               RETURN(-ENOMEM);
 
+       if (rec->lrh_type == OBD_CFG_REC) {
+               class_config_parse_rec(rec, outstr, 256);
+               LCONSOLE(D_WARNING, "   %s\n", outstr);
+       } else {
+               LCONSOLE(D_WARNING, "unhandled lrh_type: %#x\n", rec->lrh_type);
+               rc = -EINVAL;
+       }
+
+       OBD_FREE(outstr, 256);
+       RETURN(rc);
+}
+
+int class_config_dump_llog(const struct lu_env *env, struct llog_ctxt *ctxt,
+                          char *name, struct config_llog_instance *cfg)
+{
+       struct llog_handle      *llh;
+       int                      rc;
+
+       ENTRY;
+
+       LCONSOLE_INFO("Dumping config log %s\n", name);
+
+       rc = llog_open(env, ctxt, &llh, NULL, name, LLOG_OPEN_EXISTS);
+       if (rc)
+               RETURN(rc);
+
+       rc = llog_init_handle(env, llh, LLOG_F_IS_PLAIN, NULL);
+       if (rc)
+               GOTO(parse_out, rc);
+
+       rc = llog_process(env, llh, class_config_dump_handler, cfg, NULL);
+parse_out:
+       llog_close(env, llh);
+
+       LCONSOLE_INFO("End config log %s\n", name);
+       RETURN(rc);
 }
 EXPORT_SYMBOL(class_config_dump_llog);
 
@@ -1613,11 +1888,11 @@ int class_manual_cleanup(struct obd_device *obd)
         CDEBUG(D_CONFIG, "Manual cleanup of %s (flags='%s')\n",
                obd->obd_name, flags);
 
-        lustre_cfg_bufs_reset(&bufs, obd->obd_name);
-        lustre_cfg_bufs_set_string(&bufs, 1, flags);
-        lcfg = lustre_cfg_new(LCFG_CLEANUP, &bufs);
-        if (!lcfg)
-                RETURN(-ENOMEM);
+       lustre_cfg_bufs_reset(&bufs, obd->obd_name);
+       lustre_cfg_bufs_set_string(&bufs, 1, flags);
+       lcfg = lustre_cfg_new(LCFG_CLEANUP, &bufs);
+       if (lcfg == NULL)
+               RETURN(-ENOMEM);
 
         rc = class_process_config(lcfg);
         if (rc) {
@@ -1648,13 +1923,13 @@ uuid_hash(cfs_hash_t *hs, const void *key, unsigned mask)
 }
 
 static void *
-uuid_key(cfs_hlist_node_t *hnode)
+uuid_key(struct hlist_node *hnode)
 {
-        struct obd_export *exp;
+       struct obd_export *exp;
 
-        exp = cfs_hlist_entry(hnode, struct obd_export, exp_uuid_hash);
+       exp = hlist_entry(hnode, struct obd_export, exp_uuid_hash);
 
-        return &exp->exp_client_uuid;
+       return &exp->exp_client_uuid;
 }
 
 /*
@@ -1662,38 +1937,38 @@ uuid_key(cfs_hlist_node_t *hnode)
  *       state with this function
  */
 static int
-uuid_keycmp(const void *key, cfs_hlist_node_t *hnode)
+uuid_keycmp(const void *key, struct hlist_node *hnode)
 {
         struct obd_export *exp;
 
         LASSERT(key);
-        exp = cfs_hlist_entry(hnode, struct obd_export, exp_uuid_hash);
+       exp = hlist_entry(hnode, struct obd_export, exp_uuid_hash);
 
         return obd_uuid_equals(key, &exp->exp_client_uuid) &&
                !exp->exp_failed;
 }
 
 static void *
-uuid_export_object(cfs_hlist_node_t *hnode)
+uuid_export_object(struct hlist_node *hnode)
 {
-        return cfs_hlist_entry(hnode, struct obd_export, exp_uuid_hash);
+       return hlist_entry(hnode, struct obd_export, exp_uuid_hash);
 }
 
 static void
-uuid_export_get(cfs_hash_t *hs, cfs_hlist_node_t *hnode)
+uuid_export_get(cfs_hash_t *hs, struct hlist_node *hnode)
 {
         struct obd_export *exp;
 
-        exp = cfs_hlist_entry(hnode, struct obd_export, exp_uuid_hash);
+       exp = hlist_entry(hnode, struct obd_export, exp_uuid_hash);
         class_export_get(exp);
 }
 
 static void
-uuid_export_put_locked(cfs_hash_t *hs, cfs_hlist_node_t *hnode)
+uuid_export_put_locked(cfs_hash_t *hs, struct hlist_node *hnode)
 {
         struct obd_export *exp;
 
-        exp = cfs_hlist_entry(hnode, struct obd_export, exp_uuid_hash);
+       exp = hlist_entry(hnode, struct obd_export, exp_uuid_hash);
         class_export_put(exp);
 }
 
@@ -1718,11 +1993,11 @@ nid_hash(cfs_hash_t *hs, const void *key, unsigned mask)
 }
 
 static void *
-nid_key(cfs_hlist_node_t *hnode)
+nid_key(struct hlist_node *hnode)
 {
         struct obd_export *exp;
 
-        exp = cfs_hlist_entry(hnode, struct obd_export, exp_nid_hash);
+       exp = hlist_entry(hnode, struct obd_export, exp_nid_hash);
 
         RETURN(&exp->exp_connection->c_peer.nid);
 }
@@ -1732,38 +2007,38 @@ nid_key(cfs_hlist_node_t *hnode)
  *       state with this function
  */
 static int
-nid_kepcmp(const void *key, cfs_hlist_node_t *hnode)
+nid_kepcmp(const void *key, struct hlist_node *hnode)
 {
         struct obd_export *exp;
 
         LASSERT(key);
-        exp = cfs_hlist_entry(hnode, struct obd_export, exp_nid_hash);
+       exp = hlist_entry(hnode, struct obd_export, exp_nid_hash);
 
         RETURN(exp->exp_connection->c_peer.nid == *(lnet_nid_t *)key &&
                !exp->exp_failed);
 }
 
 static void *
-nid_export_object(cfs_hlist_node_t *hnode)
+nid_export_object(struct hlist_node *hnode)
 {
-        return cfs_hlist_entry(hnode, struct obd_export, exp_nid_hash);
+       return hlist_entry(hnode, struct obd_export, exp_nid_hash);
 }
 
 static void
-nid_export_get(cfs_hash_t *hs, cfs_hlist_node_t *hnode)
+nid_export_get(cfs_hash_t *hs, struct hlist_node *hnode)
 {
         struct obd_export *exp;
 
-        exp = cfs_hlist_entry(hnode, struct obd_export, exp_nid_hash);
+       exp = hlist_entry(hnode, struct obd_export, exp_nid_hash);
         class_export_get(exp);
 }
 
 static void
-nid_export_put_locked(cfs_hash_t *hs, cfs_hlist_node_t *hnode)
+nid_export_put_locked(cfs_hash_t *hs, struct hlist_node *hnode)
 {
         struct obd_export *exp;
 
-        exp = cfs_hlist_entry(hnode, struct obd_export, exp_nid_hash);
+       exp = hlist_entry(hnode, struct obd_export, exp_nid_hash);
         class_export_put(exp);
 }
 
@@ -1782,42 +2057,42 @@ static cfs_hash_ops_t nid_hash_ops = {
  */
 
 static void *
-nidstats_key(cfs_hlist_node_t *hnode)
+nidstats_key(struct hlist_node *hnode)
 {
         struct nid_stat *ns;
 
-        ns = cfs_hlist_entry(hnode, struct nid_stat, nid_hash);
+       ns = hlist_entry(hnode, struct nid_stat, nid_hash);
 
         return &ns->nid;
 }
 
 static int
-nidstats_keycmp(const void *key, cfs_hlist_node_t *hnode)
+nidstats_keycmp(const void *key, struct hlist_node *hnode)
 {
         return *(lnet_nid_t *)nidstats_key(hnode) == *(lnet_nid_t *)key;
 }
 
 static void *
-nidstats_object(cfs_hlist_node_t *hnode)
+nidstats_object(struct hlist_node *hnode)
 {
-        return cfs_hlist_entry(hnode, struct nid_stat, nid_hash);
+       return hlist_entry(hnode, struct nid_stat, nid_hash);
 }
 
 static void
-nidstats_get(cfs_hash_t *hs, cfs_hlist_node_t *hnode)
+nidstats_get(cfs_hash_t *hs, struct hlist_node *hnode)
 {
         struct nid_stat *ns;
 
-        ns = cfs_hlist_entry(hnode, struct nid_stat, nid_hash);
+       ns = hlist_entry(hnode, struct nid_stat, nid_hash);
         nidstat_getref(ns);
 }
 
 static void
-nidstats_put_locked(cfs_hash_t *hs, cfs_hlist_node_t *hnode)
+nidstats_put_locked(cfs_hash_t *hs, struct hlist_node *hnode)
 {
         struct nid_stat *ns;
 
-        ns = cfs_hlist_entry(hnode, struct nid_stat, nid_hash);
+       ns = hlist_entry(hnode, struct nid_stat, nid_hash);
         nidstat_putref(ns);
 }