Whamcloud - gitweb
LU-13356 client: don't use OBD_CONNECT_MNE_SWAB
[fs/lustre-release.git] / lustre / obdclass / obd_mount.c
index 5037f5e..de23440 100644 (file)
  *
  * You should have received a copy of the GNU General Public License
  * version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * GPL HEADER END
  */
@@ -27,7 +23,7 @@
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  *
- * Copyright (c) 2011, 2014, Intel Corporation.
+ * Copyright (c) 2011, 2017, Intel Corporation.
  */
 /*
  * This file is part of Lustre, http://www.lustre.org/
 
 #include <obd.h>
 #include <obd_class.h>
-#include <lustre/lustre_user.h>
+#include <linux/random.h>
+#include <libcfs/linux/linux-uuid.h>
 #include <linux/version.h>
 #include <lustre_log.h>
 #include <lustre_disk.h>
-#include <lustre_param.h>
+#include <uapi/linux/lustre/lustre_param.h>
 
-static int (*client_fill_super)(struct super_block *sb,
-                               struct vfsmount *mnt);
+static DEFINE_SPINLOCK(client_lock);
+static struct module *client_mod;
+static int (*client_fill_super)(struct super_block *sb);
 
 static void (*kill_super_cb)(struct super_block *sb);
 
 /**************** config llog ********************/
 
-/** Get a config log from the MGS and process it.
+/**
+ * Get a config log from the MGS and process it.
  * This func is called for both clients and servers.
  * Continue to process new statements appended to the logs
  * (whenever the config lock is revoked) until lustre_end_log
  * is called.
+ *
  * @param sb The superblock is used by the MGC to write to the local copy of
  *   the config log
  * @param logname The name of the llog to replicate from the MGS
- * @param cfg Since the same mgc may be used to follow multiple config logs
+ * @param cfg Since the same MGC may be used to follow multiple config logs
  *   (e.g. ost1, ost2, client), the config_llog_instance keeps the state for
  *   this log, and is added to the mgc's list of logs to follow.
  */
 int lustre_process_log(struct super_block *sb, char *logname,
-                     struct config_llog_instance *cfg)
+                      struct config_llog_instance *cfg)
 {
-        struct lustre_cfg *lcfg;
-        struct lustre_cfg_bufs *bufs;
-        struct lustre_sb_info *lsi = s2lsi(sb);
-        struct obd_device *mgc = lsi->lsi_mgc;
-        int rc;
-        ENTRY;
-
-        LASSERT(mgc);
-        LASSERT(cfg);
-
-        OBD_ALLOC_PTR(bufs);
-        if (bufs == NULL)
-                RETURN(-ENOMEM);
-
-        /* mgc_process_config */
-        lustre_cfg_bufs_reset(bufs, mgc->obd_name);
-        lustre_cfg_bufs_set_string(bufs, 1, logname);
-        lustre_cfg_bufs_set(bufs, 2, cfg, sizeof(*cfg));
-        lustre_cfg_bufs_set(bufs, 3, &sb, sizeof(sb));
-        lcfg = lustre_cfg_new(LCFG_LOG_START, bufs);
-       if (lcfg == NULL)
+       struct lustre_cfg *lcfg;
+       struct lustre_cfg_bufs *bufs;
+       struct lustre_sb_info *lsi = s2lsi(sb);
+       struct obd_device *mgc = lsi->lsi_mgc;
+       int rc;
+
+       ENTRY;
+
+       LASSERT(mgc);
+       LASSERT(cfg);
+
+       OBD_ALLOC_PTR(bufs);
+       if (bufs == NULL)
+               RETURN(-ENOMEM);
+
+       /* mgc_process_config */
+       lustre_cfg_bufs_reset(bufs, mgc->obd_name);
+       lustre_cfg_bufs_set_string(bufs, 1, logname);
+       lustre_cfg_bufs_set(bufs, 2, cfg, sizeof(*cfg));
+       lustre_cfg_bufs_set(bufs, 3, &sb, sizeof(sb));
+       OBD_ALLOC(lcfg, lustre_cfg_len(bufs->lcfg_bufcount, bufs->lcfg_buflen));
+       if (!lcfg)
                GOTO(out, rc = -ENOMEM);
+       lustre_cfg_init(lcfg, LCFG_LOG_START, bufs);
+
        rc = obd_process_config(mgc, sizeof(*lcfg), lcfg);
-       lustre_cfg_free(lcfg);
+       OBD_FREE(lcfg, lustre_cfg_len(lcfg->lcfg_bufcount, lcfg->lcfg_buflens));
 out:
-        OBD_FREE_PTR(bufs);
-
-        if (rc == -EINVAL)
-                LCONSOLE_ERROR_MSG(0x15b, "%s: The configuration from log '%s'"
-                                   "failed from the MGS (%d).  Make sure this "
-                                   "client and the MGS are running compatible "
-                                   "versions of Lustre.\n",
-                                   mgc->obd_name, logname, rc);
+       OBD_FREE_PTR(bufs);
+
+       if (rc == -EINVAL)
+               LCONSOLE_ERROR_MSG(0x15b,
+                                  "%s: Configuration from log %s failed from MGS %d. Check client and MGS are on compatible version.\n",
+                                  mgc->obd_name, logname, rc);
        else if (rc != 0)
-                LCONSOLE_ERROR_MSG(0x15c, "%s: The configuration from log '%s' "
-                                   "failed (%d). This may be the result of "
-                                   "communication errors between this node and "
-                                   "the MGS, a bad configuration, or other "
-                                   "errors. See the syslog for more "
-                                   "information.\n", mgc->obd_name, logname,
-                                   rc);
-
-        /* class_obd_list(); */
-        RETURN(rc);
+               LCONSOLE_ERROR_MSG(0x15c,
+                                  "%s: Confguration from log %s failed from MGS %d. Communication error between node & MGS, a bad configuration, or other errors. See syslog for more info\n",
+                                  mgc->obd_name, logname, rc);
+
+       /* class_obd_list(); */
+       RETURN(rc);
 }
 EXPORT_SYMBOL(lustre_process_log);
 
 /* Stop watching this config log for updates */
 int lustre_end_log(struct super_block *sb, char *logname,
-                       struct config_llog_instance *cfg)
+                  struct config_llog_instance *cfg)
 {
-        struct lustre_cfg *lcfg;
-        struct lustre_cfg_bufs bufs;
-        struct lustre_sb_info *lsi = s2lsi(sb);
-        struct obd_device *mgc = lsi->lsi_mgc;
-        int rc;
-        ENTRY;
-
-        if (!mgc)
-                RETURN(-ENOENT);
-
-        /* mgc_process_config */
-        lustre_cfg_bufs_reset(&bufs, mgc->obd_name);
-        lustre_cfg_bufs_set_string(&bufs, 1, logname);
-        if (cfg)
-                lustre_cfg_bufs_set(&bufs, 2, cfg, sizeof(*cfg));
-        lcfg = lustre_cfg_new(LCFG_LOG_END, &bufs);
-       if (lcfg == NULL)
+       struct lustre_cfg *lcfg;
+       struct lustre_cfg_bufs bufs;
+       struct lustre_sb_info *lsi = s2lsi(sb);
+       struct obd_device *mgc = lsi->lsi_mgc;
+       int rc;
+
+       ENTRY;
+
+       if (!mgc)
+               RETURN(-ENOENT);
+
+       /* mgc_process_config */
+       lustre_cfg_bufs_reset(&bufs, mgc->obd_name);
+       lustre_cfg_bufs_set_string(&bufs, 1, logname);
+       if (cfg)
+               lustre_cfg_bufs_set(&bufs, 2, cfg, sizeof(*cfg));
+       OBD_ALLOC(lcfg, lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
+       if (!lcfg)
                RETURN(-ENOMEM);
-        rc = obd_process_config(mgc, sizeof(*lcfg), lcfg);
-        lustre_cfg_free(lcfg);
-        RETURN(rc);
+       lustre_cfg_init(lcfg, LCFG_LOG_END, &bufs);
+       rc = obd_process_config(mgc, sizeof(*lcfg), lcfg);
+       OBD_FREE(lcfg, lustre_cfg_len(lcfg->lcfg_bufcount, lcfg->lcfg_buflens));
+       RETURN(rc);
 }
 EXPORT_SYMBOL(lustre_end_log);
 
-/**************** obd start *******************/
+/**************** OBD start *******************/
 
-/** lustre_cfg_bufs are a holdover from 1.4; we can still set these up from
+/**
+ * lustre_cfg_bufs are a holdover from 1.4; we can still set these up from
  * lctl (and do for echo cli/srv.
  */
-int do_lcfg(char *cfgname, lnet_nid_t nid, int cmd,
-            char *s1, char *s2, char *s3, char *s4)
+static int do_lcfg(char *cfgname, lnet_nid_t nid, int cmd,
+                  char *s1, char *s2, char *s3, char *s4)
 {
-        struct lustre_cfg_bufs bufs;
-        struct lustre_cfg    * lcfg = NULL;
-        int rc;
-
-        CDEBUG(D_TRACE, "lcfg %s %#x %s %s %s %s\n", cfgname,
-               cmd, s1, s2, s3, s4);
-
-        lustre_cfg_bufs_reset(&bufs, cfgname);
-        if (s1)
-                lustre_cfg_bufs_set_string(&bufs, 1, s1);
-        if (s2)
-                lustre_cfg_bufs_set_string(&bufs, 2, s2);
-        if (s3)
-                lustre_cfg_bufs_set_string(&bufs, 3, s3);
-        if (s4)
-                lustre_cfg_bufs_set_string(&bufs, 4, s4);
-
-        lcfg = lustre_cfg_new(cmd, &bufs);
-       if (lcfg == NULL)
+       struct lustre_cfg_bufs bufs;
+       struct lustre_cfg *lcfg = NULL;
+       int rc;
+
+       CDEBUG(D_TRACE, "lcfg %s %#x %s %s %s %s\n", cfgname,
+              cmd, s1, s2, s3, s4);
+
+       lustre_cfg_bufs_reset(&bufs, cfgname);
+       if (s1)
+               lustre_cfg_bufs_set_string(&bufs, 1, s1);
+       if (s2)
+               lustre_cfg_bufs_set_string(&bufs, 2, s2);
+       if (s3)
+               lustre_cfg_bufs_set_string(&bufs, 3, s3);
+       if (s4)
+               lustre_cfg_bufs_set_string(&bufs, 4, s4);
+
+       OBD_ALLOC(lcfg, lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
+       if (!lcfg)
                return -ENOMEM;
-        lcfg->lcfg_nid = nid;
-        rc = class_process_config(lcfg);
-        lustre_cfg_free(lcfg);
-        return(rc);
+       lustre_cfg_init(lcfg, cmd, &bufs);
+       lcfg->lcfg_nid = nid;
+       rc = class_process_config(lcfg);
+       OBD_FREE(lcfg, lustre_cfg_len(lcfg->lcfg_bufcount, lcfg->lcfg_buflens));
+       return rc;
 }
 
-/** Call class_attach and class_setup.  These methods in turn call
- * obd type-specific methods.
+/**
+ * Call class_attach and class_setup.  These methods in turn call
+ * OBD type-specific methods.
  */
 int lustre_start_simple(char *obdname, char *type, char *uuid,
                        char *s1, char *s2, char *s3, char *s4)
 {
        int rc;
-       CDEBUG(D_MOUNT, "Starting obd %s (typ=%s)\n", obdname, type);
+
+       CDEBUG(D_MOUNT, "Starting OBD %s (typ=%s)\n", obdname, type);
 
        rc = do_lcfg(obdname, 0, LCFG_ATTACH, type, uuid, NULL, NULL);
        if (rc) {
@@ -208,31 +211,33 @@ int lustre_start_simple(char *obdname, char *type, char *uuid,
 
 static DEFINE_MUTEX(mgc_start_lock);
 
-/** Set up a mgc obd to process startup logs
+/**
+ * Set up a MGC OBD to process startup logs
  *
- * \param sb [in] super block of the mgc obd
+ * \param sb [in] super block of the MGC OBD
  *
  * \retval 0 success, otherwise error code
  */
 int lustre_start_mgc(struct super_block *sb)
 {
-        struct obd_connect_data *data = NULL;
-        struct lustre_sb_info *lsi = s2lsi(sb);
-        struct obd_device *obd;
-        struct obd_export *exp;
-        struct obd_uuid *uuid;
-        class_uuid_t uuidc;
-        lnet_nid_t nid;
+       struct obd_connect_data *data = NULL;
+       struct lustre_sb_info *lsi = s2lsi(sb);
+       struct obd_device *obd;
+       struct obd_export *exp;
+       struct obd_uuid *uuid = NULL;
+       uuid_t uuidc;
+       lnet_nid_t nid;
        char nidstr[LNET_NIDSTR_SIZE];
-        char *mgcname = NULL, *niduuid = NULL, *mgssec = NULL;
-        char *ptr;
+       char *mgcname = NULL, *niduuid = NULL, *mgssec = NULL;
+       char *ptr;
        int rc = 0, i = 0, j;
        size_t len;
+
        ENTRY;
 
        LASSERT(lsi->lsi_lmd);
 
-       /* Find the first non-lo MGS nid for our MGC name */
+       /* Find the first non-lo MGS NID for our MGC name */
        if (IS_SERVER(lsi)) {
                /* mount -o mgsnode=nid */
                ptr = lsi->lsi_lmd->lmd_mgs;
@@ -240,25 +245,26 @@ int lustre_start_mgc(struct super_block *sb)
                    (class_parse_nid(lsi->lsi_lmd->lmd_mgs, &nid, &ptr) == 0)) {
                        i++;
                } else if (IS_MGS(lsi)) {
-                        lnet_process_id_t id;
-                        while ((rc = LNetGetId(i++, &id)) != -ENOENT) {
-                                if (LNET_NETTYP(LNET_NIDNET(id.nid)) == LOLND)
-                                        continue;
-                                nid = id.nid;
-                                i++;
-                                break;
-                        }
-                }
-        } else { /* client */
-                /* Use nids from mount line: uml1,1@elan:uml2,2@elan:/lustre */
-                ptr = lsi->lsi_lmd->lmd_dev;
-                if (class_parse_nid(ptr, &nid, &ptr) == 0)
-                        i++;
-        }
-        if (i == 0) {
-                CERROR("No valid MGS nids found.\n");
-                RETURN(-EINVAL);
-        }
+                       struct lnet_process_id id;
+
+                       while ((rc = LNetGetId(i++, &id)) != -ENOENT) {
+                               if (LNET_NETTYP(LNET_NIDNET(id.nid)) == LOLND)
+                                       continue;
+                               nid = id.nid;
+                               i++;
+                               break;
+                       }
+               }
+       } else { /* client */
+               /* Use NIDs from mount line: uml1,1@elan:uml2,2@elan:/lustre */
+               ptr = lsi->lsi_lmd->lmd_dev;
+               if (class_parse_nid(ptr, &nid, &ptr) == 0)
+                       i++;
+       }
+       if (i == 0) {
+               CERROR("No valid MGS NIDs found.\n");
+               RETURN(-EINVAL);
+       }
 
        mutex_lock(&mgc_start_lock);
 
@@ -270,83 +276,85 @@ int lustre_start_mgc(struct super_block *sb)
                GOTO(out_free, rc = -ENOMEM);
        snprintf(mgcname, len, "%s%s", LUSTRE_MGC_OBDNAME, nidstr);
 
-        mgssec = lsi->lsi_lmd->lmd_mgssec ? lsi->lsi_lmd->lmd_mgssec : "";
+       mgssec = lsi->lsi_lmd->lmd_mgssec ? lsi->lsi_lmd->lmd_mgssec : "";
 
-        OBD_ALLOC_PTR(data);
-        if (data == NULL)
-                GOTO(out_free, rc = -ENOMEM);
+       OBD_ALLOC_PTR(data);
+       if (data == NULL)
+               GOTO(out_free, rc = -ENOMEM);
 
-        obd = class_name2obd(mgcname);
-        if (obd && !obd->obd_stopping) {
+       obd = class_name2obd(mgcname);
+       if (obd && !obd->obd_stopping) {
                int recov_bk;
 
-                rc = obd_set_info_async(NULL, obd->obd_self_export,
-                                        strlen(KEY_MGSSEC), KEY_MGSSEC,
-                                        strlen(mgssec), mgssec, NULL);
-                if (rc)
-                        GOTO(out_free, rc);
+               rc = obd_set_info_async(NULL, obd->obd_self_export,
+                                       strlen(KEY_MGSSEC), KEY_MGSSEC,
+                                       strlen(mgssec), mgssec, NULL);
+               if (rc)
+                       GOTO(out_free, rc);
 
-                /* Re-using an existing MGC */
+               /* Re-using an existing MGC */
                atomic_inc(&obd->u.cli.cl_mgc_refcount);
 
-                /* IR compatibility check, only for clients */
-                if (lmd_is_client(lsi->lsi_lmd)) {
-                        int has_ir;
-                        int vallen = sizeof(*data);
-                        __u32 *flags = &lsi->lsi_lmd->lmd_flags;
+               /* IR compatibility check, only for clients */
+               if (lmd_is_client(lsi->lsi_lmd)) {
+                       int has_ir;
+                       int vallen = sizeof(*data);
+                       __u32 *flags = &lsi->lsi_lmd->lmd_flags;
 
                        rc = obd_get_info(NULL, obd->obd_self_export,
                                          strlen(KEY_CONN_DATA), KEY_CONN_DATA,
                                          &vallen, data);
-                        LASSERT(rc == 0);
-                        has_ir = OCD_HAS_FLAG(data, IMP_RECOV);
-                        if (has_ir ^ !(*flags & LMD_FLG_NOIR)) {
-                                /* LMD_FLG_NOIR is for test purpose only */
-                                LCONSOLE_WARN(
-                                    "Trying to mount a client with IR setting "
-                                    "not compatible with current mgc. "
-                                    "Force to use current mgc setting that is "
-                                    "IR %s.\n",
-                                    has_ir ? "enabled" : "disabled");
-                                if (has_ir)
-                                        *flags &= ~LMD_FLG_NOIR;
-                                else
-                                        *flags |= LMD_FLG_NOIR;
-                        }
-                }
-
-                recov_bk = 0;
-                /* If we are restarting the MGS, don't try to keep the MGC's
-                   old connection, or registration will fail. */
+                       LASSERT(rc == 0);
+                       has_ir = OCD_HAS_FLAG(data, IMP_RECOV);
+                       if (has_ir ^ !(*flags & LMD_FLG_NOIR)) {
+                               /* LMD_FLG_NOIR is for test purpose only */
+                               LCONSOLE_WARN(
+                                             "Mounting client with IR setting not compatible with current MGC. Using MGC setting that is IR %s",
+                                             has_ir ? "enabled" : "disabled");
+                               if (has_ir)
+                                       *flags &= ~LMD_FLG_NOIR;
+                               else
+                                       *flags |= LMD_FLG_NOIR;
+                       }
+               }
+
+               recov_bk = 0;
+               /*
+                * If we are restarting the MGS, don't try to keep the MGC's
+                * old connection, or registration will fail.
+                */
                if (IS_MGS(lsi)) {
-                        CDEBUG(D_MOUNT, "New MGS with live MGC\n");
-                        recov_bk = 1;
-                }
-
-                /* Try all connections, but only once (again).
-                   We don't want to block another target from starting
-                   (using its local copy of the log), but we do want to connect
-                   if at all possible. */
-                recov_bk++;
-                CDEBUG(D_MOUNT, "%s: Set MGC reconnect %d\n", mgcname,recov_bk);
-                rc = obd_set_info_async(NULL, obd->obd_self_export,
-                                        sizeof(KEY_INIT_RECOV_BACKUP),
-                                        KEY_INIT_RECOV_BACKUP,
-                                        sizeof(recov_bk), &recov_bk, NULL);
-                GOTO(out, rc = 0);
-        }
-
-        CDEBUG(D_MOUNT, "Start MGC '%s'\n", mgcname);
-
-        /* Add the primary nids for the MGS */
-        i = 0;
+                       CDEBUG(D_MOUNT, "New MGS with live MGC\n");
+                       recov_bk = 1;
+               }
+
+               /*
+                * Try all connections, but only once (again).
+                * We don't want to block another target from starting
+                * (using its local copy of the log), but we do want to connect
+                * if at all possible.
+                */
+               recov_bk++;
+               CDEBUG(D_MOUNT, "%s:Set MGC reconnect %d\n", mgcname, recov_bk);
+               rc = obd_set_info_async(NULL, obd->obd_self_export,
+                                       sizeof(KEY_INIT_RECOV_BACKUP),
+                                       KEY_INIT_RECOV_BACKUP,
+                                       sizeof(recov_bk), &recov_bk, NULL);
+               GOTO(out, rc = 0);
+       }
+
+       CDEBUG(D_MOUNT, "Start MGC '%s'\n", mgcname);
+
+       /* Add the primary NIDs for the MGS */
+       i = 0;
        snprintf(niduuid, len + 2, "%s_%x", mgcname, i);
        if (IS_SERVER(lsi)) {
                ptr = lsi->lsi_lmd->lmd_mgs;
-               CDEBUG(D_MOUNT, "mgs nids %s.\n", ptr);
+               CDEBUG(D_MOUNT, "mgs NIDs %s.\n", ptr);
                if (IS_MGS(lsi)) {
-                       /* Use local nids (including LO) */
-                       lnet_process_id_t id;
+                       /* Use local NIDs (including LO) */
+                       struct lnet_process_id id;
+
                        while ((rc = LNetGetId(i++, &id)) != -ENOENT) {
                                rc = do_lcfg(mgcname, id.nid, LCFG_ADD_UUID,
                                             niduuid, NULL, NULL, NULL);
@@ -358,59 +366,60 @@ int lustre_start_mgc(struct super_block *sb)
                                ptr = lsi->lsi_lmd->lmd_mgs;
                        } else if (class_find_param(ptr, PARAM_MGSNODE,
                                                    &ptr) != 0) {
-                               CERROR("No MGS nids given.\n");
+                               CERROR("No MGS NIDs given.\n");
                                GOTO(out_free, rc = -EINVAL);
                        }
                        /*
-                        * LU-3829.
-                        * Here we only take the first mgsnid as its primary
-                        * serving mgs node, the rest mgsnid will be taken as
-                        * failover mgs node, otherwise they would be takens
-                        * as multiple nids of a single mgs node.
+                        * Add primary MGS NID(s).
+                        * Multiple NIDs on one MGS node are separated
+                        * by commas.
                         */
                        while (class_parse_nid(ptr, &nid, &ptr) == 0) {
                                rc = do_lcfg(mgcname, nid, LCFG_ADD_UUID,
                                             niduuid, NULL, NULL, NULL);
-                               if (rc == 0) {
-                                       i = 1;
+                               if (rc == 0)
+                                       ++i;
+                               /* Stop at the first failover NID */
+                               if (*ptr == ':')
                                        break;
-                               }
                        }
                }
-        } else { /* client */
-                /* Use nids from mount line: uml1,1@elan:uml2,2@elan:/lustre */
-                ptr = lsi->lsi_lmd->lmd_dev;
-                while (class_parse_nid(ptr, &nid, &ptr) == 0) {
+       } else { /* client */
+               /* Use NIDs from mount line: uml1,1@elan:uml2,2@elan:/lustre */
+               ptr = lsi->lsi_lmd->lmd_dev;
+               while (class_parse_nid(ptr, &nid, &ptr) == 0) {
                        rc = do_lcfg(mgcname, nid, LCFG_ADD_UUID,
                                     niduuid, NULL, NULL, NULL);
                        if (rc == 0)
                                ++i;
-                        /* Stop at the first failover nid */
-                        if (*ptr == ':')
-                                break;
-                }
-        }
-        if (i == 0) {
-                CERROR("No valid MGS nids found.\n");
-                GOTO(out_free, rc = -EINVAL);
-        }
-        lsi->lsi_lmd->lmd_mgs_failnodes = 1;
-
-        /* Random uuid for MGC allows easier reconnects */
-        OBD_ALLOC_PTR(uuid);
-        ll_generate_random_uuid(uuidc);
-        class_uuid_unparse(uuidc, uuid);
-
-        /* Start the MGC */
-        rc = lustre_start_simple(mgcname, LUSTRE_MGC_NAME,
+                       /* Stop at the first failover NID */
+                       if (*ptr == ':')
+                               break;
+               }
+       }
+       if (i == 0) {
+               CERROR("No valid MGS NIDs found.\n");
+               GOTO(out_free, rc = -EINVAL);
+       }
+       lsi->lsi_lmd->lmd_mgs_failnodes = 1;
+
+       /* Random uuid for MGC allows easier reconnects */
+       OBD_ALLOC_PTR(uuid);
+       if (uuid == NULL)
+               GOTO(out_free, rc = -ENOMEM);
+
+       generate_random_uuid(uuidc.b);
+       snprintf(uuid->uuid, UUID_SIZE, "%pU", uuidc.b);
+
+       /* Start the MGC */
+       rc = lustre_start_simple(mgcname, LUSTRE_MGC_NAME,
                                 (char *)uuid->uuid, LUSTRE_MGS_OBDNAME,
                                 niduuid, NULL, NULL);
-        OBD_FREE_PTR(uuid);
-        if (rc)
-                GOTO(out_free, rc);
+       if (rc)
+               GOTO(out_free, rc);
 
-        /* Add any failover MGS nids */
-        i = 1;
+       /* Add any failover MGS NIDs */
+       i = 1;
        while (ptr && ((*ptr == ':' ||
               class_find_param(ptr, PARAM_MGSNODE, &ptr) == 0))) {
                /* New failover node */
@@ -429,196 +438,213 @@ int lustre_start_mgc(struct super_block *sb)
                                     niduuid, NULL, NULL, NULL);
                        if (rc == 0)
                                ++i;
-                } else {
-                        /* at ":/fsname" */
-                        break;
-                }
-        }
-        lsi->lsi_lmd->lmd_mgs_failnodes = i;
-
-        obd = class_name2obd(mgcname);
-        if (!obd) {
-                CERROR("Can't find mgcobd %s\n", mgcname);
-                GOTO(out_free, rc = -ENOTCONN);
-        }
-
-        rc = obd_set_info_async(NULL, obd->obd_self_export,
-                                strlen(KEY_MGSSEC), KEY_MGSSEC,
-                                strlen(mgssec), mgssec, NULL);
-        if (rc)
-                GOTO(out_free, rc);
-
-        /* Keep a refcount of servers/clients who started with "mount",
-           so we know when we can get rid of the mgc. */
+               } else {
+                       /* at ":/fsname" */
+                       break;
+               }
+       }
+       lsi->lsi_lmd->lmd_mgs_failnodes = i;
+
+       obd = class_name2obd(mgcname);
+       if (!obd) {
+               CERROR("Can't find mgcobd %s\n", mgcname);
+               GOTO(out_free, rc = -ENOTCONN);
+       }
+
+       rc = obd_set_info_async(NULL, obd->obd_self_export,
+                               strlen(KEY_MGSSEC), KEY_MGSSEC,
+                               strlen(mgssec), mgssec, NULL);
+       if (rc)
+               GOTO(out_free, rc);
+
+       /*
+        * Keep a refcount of servers/clients who started with "mount",
+        * so we know when we can get rid of the mgc.
+        */
        atomic_set(&obd->u.cli.cl_mgc_refcount, 1);
 
        /* We connect to the MGS at setup, and don't disconnect until cleanup */
        data->ocd_connect_flags = OBD_CONNECT_VERSION | OBD_CONNECT_AT |
                                  OBD_CONNECT_FULL20 | OBD_CONNECT_IMP_RECOV |
-                                 OBD_CONNECT_LVB_TYPE | OBD_CONNECT_BULK_MBITS;
-
-#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
-       data->ocd_connect_flags |= OBD_CONNECT_MNE_SWAB;
-#endif
-
-        if (lmd_is_client(lsi->lsi_lmd) &&
-            lsi->lsi_lmd->lmd_flags & LMD_FLG_NOIR)
-                data->ocd_connect_flags &= ~OBD_CONNECT_IMP_RECOV;
-        data->ocd_version = LUSTRE_VERSION_CODE;
-        rc = obd_connect(NULL, &exp, obd, &(obd->obd_uuid), data, NULL);
-        if (rc) {
-                CERROR("connect failed %d\n", rc);
-                GOTO(out, rc);
-        }
+                                 OBD_CONNECT_LVB_TYPE |
+                                 OBD_CONNECT_BULK_MBITS | OBD_CONNECT_BARRIER;
+
+       if (lmd_is_client(lsi->lsi_lmd) &&
+           lsi->lsi_lmd->lmd_flags & LMD_FLG_NOIR)
+               data->ocd_connect_flags &= ~OBD_CONNECT_IMP_RECOV;
+       data->ocd_version = LUSTRE_VERSION_CODE;
+       rc = obd_connect(NULL, &exp, obd, uuid, data, NULL);
+       if (rc) {
+               CERROR("connect failed %d\n", rc);
+               GOTO(out, rc);
+       }
 
-        obd->u.cli.cl_mgc_mgsexp = exp;
+       obd->u.cli.cl_mgc_mgsexp = exp;
 
 out:
-        /* Keep the mgc info in the sb. Note that many lsi's can point
-           to the same mgc.*/
-        lsi->lsi_mgc = obd;
+       /*
+        * Keep the MGC info in the sb. Note that many lsi's can point
+        * to the same mgc.
+        */
+       lsi->lsi_mgc = obd;
 out_free:
        mutex_unlock(&mgc_start_lock);
 
-        if (data)
-                OBD_FREE_PTR(data);
-        if (mgcname)
-                OBD_FREE(mgcname, len);
-        if (niduuid)
-                OBD_FREE(niduuid, len + 2);
-        RETURN(rc);
+       if (uuid)
+               OBD_FREE_PTR(uuid);
+       if (data)
+               OBD_FREE_PTR(data);
+       if (mgcname)
+               OBD_FREE(mgcname, len);
+       if (niduuid)
+               OBD_FREE(niduuid, len + 2);
+       RETURN(rc);
 }
 
 static int lustre_stop_mgc(struct super_block *sb)
 {
-        struct lustre_sb_info *lsi = s2lsi(sb);
-        struct obd_device *obd;
+       struct lustre_sb_info *lsi = s2lsi(sb);
+       struct obd_device *obd;
        char *niduuid = NULL, *ptr = NULL;
-        int i, rc = 0, len = 0;
-        ENTRY;
+       int i, rc = 0, len = 0;
 
-        if (!lsi)
-                RETURN(-ENOENT);
-        obd = lsi->lsi_mgc;
-        if (!obd)
-                RETURN(-ENOENT);
-        lsi->lsi_mgc = NULL;
+       ENTRY;
+
+       if (!lsi)
+               RETURN(-ENOENT);
+       obd = lsi->lsi_mgc;
+       if (!obd)
+               RETURN(-ENOENT);
+       lsi->lsi_mgc = NULL;
 
        mutex_lock(&mgc_start_lock);
        LASSERT(atomic_read(&obd->u.cli.cl_mgc_refcount) > 0);
        if (!atomic_dec_and_test(&obd->u.cli.cl_mgc_refcount)) {
-                /* This is not fatal, every client that stops
-                   will call in here. */
-                CDEBUG(D_MOUNT, "mgc still has %d references.\n",
+               /*
+                * This is not fatal, every client that stops
+                * will call in here.
+                */
+               CDEBUG(D_MOUNT, "MGC still has %d references.\n",
                       atomic_read(&obd->u.cli.cl_mgc_refcount));
-                GOTO(out, rc = -EBUSY);
-        }
-
-        /* The MGC has no recoverable data in any case.
-         * force shotdown set in umount_begin */
-        obd->obd_no_recov = 1;
-
-        if (obd->u.cli.cl_mgc_mgsexp) {
-                /* An error is not fatal, if we are unable to send the
-                   disconnect mgs ping evictor cleans up the export */
-                rc = obd_disconnect(obd->u.cli.cl_mgc_mgsexp);
-                if (rc)
-                        CDEBUG(D_MOUNT, "disconnect failed %d\n", rc);
-        }
-
-        /* Save the obdname for cleaning the nid uuids, which are
-           obdname_XX */
-        len = strlen(obd->obd_name) + 6;
-        OBD_ALLOC(niduuid, len);
-        if (niduuid) {
-                strcpy(niduuid, obd->obd_name);
-                ptr = niduuid + strlen(niduuid);
-        }
-
-        rc = class_manual_cleanup(obd);
-        if (rc)
-                GOTO(out, rc);
-
-        /* Clean the nid uuids */
-        if (!niduuid)
-                GOTO(out, rc = -ENOMEM);
-
-        for (i = 0; i < lsi->lsi_lmd->lmd_mgs_failnodes; i++) {
-                sprintf(ptr, "_%x", i);
-                rc = do_lcfg(LUSTRE_MGC_OBDNAME, 0, LCFG_DEL_UUID,
+               GOTO(out, rc = -EBUSY);
+       }
+
+       /*
+        * The MGC has no recoverable data in any case.
+        * force shotdown set in umount_begin
+        */
+       obd->obd_no_recov = 1;
+
+       if (obd->u.cli.cl_mgc_mgsexp) {
+               /*
+                * An error is not fatal, if we are unable to send the
+                * disconnect mgs ping evictor cleans up the export
+                */
+               rc = obd_disconnect(obd->u.cli.cl_mgc_mgsexp);
+               if (rc)
+                       CDEBUG(D_MOUNT, "disconnect failed %d\n", rc);
+       }
+
+       /*
+        * Save the obdname for cleaning the nid uuids, which are
+        * obdname_XX
+        */
+       len = strlen(obd->obd_name) + 6;
+       OBD_ALLOC(niduuid, len);
+       if (niduuid) {
+               strcpy(niduuid, obd->obd_name);
+               ptr = niduuid + strlen(niduuid);
+       }
+
+       rc = class_manual_cleanup(obd);
+       if (rc)
+               GOTO(out, rc);
+
+       /* Clean the nid uuids */
+       if (!niduuid)
+               GOTO(out, rc = -ENOMEM);
+
+       for (i = 0; i < lsi->lsi_lmd->lmd_mgs_failnodes; i++) {
+               sprintf(ptr, "_%x", i);
+               rc = do_lcfg(LUSTRE_MGC_OBDNAME, 0, LCFG_DEL_UUID,
                             niduuid, NULL, NULL, NULL);
-                if (rc)
-                        CERROR("del MDC UUID %s failed: rc = %d\n",
-                               niduuid, rc);
-        }
+               if (rc)
+                       CERROR("del MDC UUID %s failed: rc = %d\n",
+                              niduuid, rc);
+       }
 out:
-        if (niduuid)
-                OBD_FREE(niduuid, len);
+       if (niduuid)
+               OBD_FREE(niduuid, len);
 
-        /* class_import_put will get rid of the additional connections */
+       /* class_import_put will get rid of the additional connections */
        mutex_unlock(&mgc_start_lock);
-        RETURN(rc);
+       RETURN(rc);
 }
 
 /***************** lustre superblock **************/
 
 static struct lustre_sb_info *lustre_init_lsi(struct super_block *sb)
 {
-        struct lustre_sb_info *lsi;
-        ENTRY;
-
-        OBD_ALLOC_PTR(lsi);
-        if (!lsi)
-                RETURN(NULL);
-        OBD_ALLOC_PTR(lsi->lsi_lmd);
-        if (!lsi->lsi_lmd) {
-                OBD_FREE_PTR(lsi);
-                RETURN(NULL);
-        }
-
-        lsi->lsi_lmd->lmd_exclude_count = 0;
-        lsi->lsi_lmd->lmd_recovery_time_soft = 0;
-        lsi->lsi_lmd->lmd_recovery_time_hard = 0;
-        s2lsi_nocast(sb) = lsi;
-        /* we take 1 extra ref for our setup */
+       struct lustre_sb_info *lsi;
+
+       ENTRY;
+
+       OBD_ALLOC_PTR(lsi);
+       if (!lsi)
+               RETURN(NULL);
+       OBD_ALLOC_PTR(lsi->lsi_lmd);
+       if (!lsi->lsi_lmd) {
+               OBD_FREE_PTR(lsi);
+               RETURN(NULL);
+       }
+
+       lsi->lsi_lmd->lmd_exclude_count = 0;
+       lsi->lsi_lmd->lmd_recovery_time_soft = 0;
+       lsi->lsi_lmd->lmd_recovery_time_hard = 0;
+       s2lsi_nocast(sb) = lsi;
+       /* we take 1 extra ref for our setup */
        atomic_set(&lsi->lsi_mounts, 1);
 
-        /* Default umount style */
-        lsi->lsi_flags = LSI_UMOUNT_FAILOVER;
+       /* Default umount style */
+       lsi->lsi_flags = LSI_UMOUNT_FAILOVER;
        INIT_LIST_HEAD(&lsi->lsi_lwp_list);
-       spin_lock_init(&lsi->lsi_lwp_lock);
+       mutex_init(&lsi->lsi_lwp_mutex);
 
        RETURN(lsi);
 }
 
 static int lustre_free_lsi(struct super_block *sb)
 {
-        struct lustre_sb_info *lsi = s2lsi(sb);
-        ENTRY;
+       struct lustre_sb_info *lsi = s2lsi(sb);
+
+       ENTRY;
 
-        LASSERT(lsi != NULL);
-        CDEBUG(D_MOUNT, "Freeing lsi %p\n", lsi);
+       LASSERT(lsi != NULL);
+       CDEBUG(D_MOUNT, "Freeing lsi %p\n", lsi);
 
-        /* someone didn't call server_put_mount. */
+       /* someone didn't call server_put_mount. */
        LASSERT(atomic_read(&lsi->lsi_mounts) == 0);
 
-        if (lsi->lsi_lmd != NULL) {
-                if (lsi->lsi_lmd->lmd_dev != NULL)
-                        OBD_FREE(lsi->lsi_lmd->lmd_dev,
-                                 strlen(lsi->lsi_lmd->lmd_dev) + 1);
-                if (lsi->lsi_lmd->lmd_profile != NULL)
-                        OBD_FREE(lsi->lsi_lmd->lmd_profile,
-                                 strlen(lsi->lsi_lmd->lmd_profile) + 1);
-                if (lsi->lsi_lmd->lmd_mgssec != NULL)
-                        OBD_FREE(lsi->lsi_lmd->lmd_mgssec,
-                                 strlen(lsi->lsi_lmd->lmd_mgssec) + 1);
-                if (lsi->lsi_lmd->lmd_opts != NULL)
-                        OBD_FREE(lsi->lsi_lmd->lmd_opts,
-                                 strlen(lsi->lsi_lmd->lmd_opts) + 1);
-                if (lsi->lsi_lmd->lmd_exclude_count)
-                        OBD_FREE(lsi->lsi_lmd->lmd_exclude,
-                                 sizeof(lsi->lsi_lmd->lmd_exclude[0]) *
-                                 lsi->lsi_lmd->lmd_exclude_count);
+       if (lsi->lsi_lmd != NULL) {
+               if (lsi->lsi_lmd->lmd_dev != NULL)
+                       OBD_FREE(lsi->lsi_lmd->lmd_dev,
+                               strlen(lsi->lsi_lmd->lmd_dev) + 1);
+               if (lsi->lsi_lmd->lmd_profile != NULL)
+                       OBD_FREE(lsi->lsi_lmd->lmd_profile,
+                               strlen(lsi->lsi_lmd->lmd_profile) + 1);
+               if (lsi->lsi_lmd->lmd_fileset != NULL)
+                       OBD_FREE(lsi->lsi_lmd->lmd_fileset,
+                               strlen(lsi->lsi_lmd->lmd_fileset) + 1);
+               if (lsi->lsi_lmd->lmd_mgssec != NULL)
+                       OBD_FREE(lsi->lsi_lmd->lmd_mgssec,
+                               strlen(lsi->lsi_lmd->lmd_mgssec) + 1);
+               if (lsi->lsi_lmd->lmd_opts != NULL)
+                       OBD_FREE(lsi->lsi_lmd->lmd_opts,
+                               strlen(lsi->lsi_lmd->lmd_opts) + 1);
+               if (lsi->lsi_lmd->lmd_exclude_count)
+                       OBD_FREE(lsi->lsi_lmd->lmd_exclude,
+                               sizeof(lsi->lsi_lmd->lmd_exclude[0]) *
+                               lsi->lsi_lmd->lmd_exclude_count);
                if (lsi->lsi_lmd->lmd_mgs != NULL)
                        OBD_FREE(lsi->lsi_lmd->lmd_mgs,
                                 strlen(lsi->lsi_lmd->lmd_mgs) + 1);
@@ -627,22 +653,28 @@ static int lustre_free_lsi(struct super_block *sb)
                                 strlen(lsi->lsi_lmd->lmd_osd_type) + 1);
                if (lsi->lsi_lmd->lmd_params != NULL)
                        OBD_FREE(lsi->lsi_lmd->lmd_params, 4096);
+               if (lsi->lsi_lmd->lmd_nidnet != NULL)
+                       OBD_FREE(lsi->lsi_lmd->lmd_nidnet,
+                               strlen(lsi->lsi_lmd->lmd_nidnet) + 1);
 
-                OBD_FREE(lsi->lsi_lmd, sizeof(*lsi->lsi_lmd));
-        }
+               OBD_FREE_PTR(lsi->lsi_lmd);
+       }
 
-        LASSERT(lsi->lsi_llsbi == NULL);
-        OBD_FREE(lsi, sizeof(*lsi));
-        s2lsi_nocast(sb) = NULL;
+       LASSERT(lsi->lsi_llsbi == NULL);
+       OBD_FREE_PTR(lsi);
+       s2lsi_nocast(sb) = NULL;
 
-        RETURN(0);
+       RETURN(0);
 }
 
-/* The lsi has one reference for every server that is using the disk -
-   e.g. MDT, MGS, and potentially MGC */
+/*
+ * The lsi has one reference for every server that is using the disk -
+ * e.g. MDT, MGS, and potentially MGC
+ */
 int lustre_put_lsi(struct super_block *sb)
 {
        struct lustre_sb_info *lsi = s2lsi(sb);
+
        ENTRY;
 
        LASSERT(lsi != NULL);
@@ -663,7 +695,87 @@ int lustre_put_lsi(struct super_block *sb)
        RETURN(0);
 }
 
-/*** SERVER NAME ***
+/*
+ * The goal of this function is to extract the file system name
+ * from the OBD name. This can come in two flavors. One is
+ * fsname-MDTXXXX or fsname-XXXXXXX were X is a hexadecimal
+ * number. In both cases we should return fsname. If it is
+ * not a valid OBD name it is assumed to be the file system
+ * name itself.
+ */
+void obdname2fsname(const char *tgt, char *fsname, size_t buflen)
+{
+       const char *ptr;
+       const char *tmp;
+       size_t len = 0;
+
+       /*
+        * First we have to see if the @tgt has '-' at all. It is
+        * valid for the user to request something like
+        * lctl set_param -P llite.lustre*.xattr_cache=0
+        */
+       ptr = strrchr(tgt, '-');
+       if (!ptr) {
+               /* No '-' means it could end in '*' */
+               ptr = strchr(tgt, '*');
+               if (!ptr) {
+                       /* No '*' either. Assume tgt = fsname */
+                       len = strlen(tgt);
+                       goto valid_obd_name;
+               }
+               len = ptr - tgt;
+               goto valid_obd_name;
+       }
+
+       /* tgt format fsname-MDT0000-* */
+       if ((!strncmp(ptr, "-MDT", 4) ||
+            !strncmp(ptr, "-OST", 4)) &&
+            (isxdigit(ptr[4]) && isxdigit(ptr[5]) &&
+             isxdigit(ptr[6]) && isxdigit(ptr[7]))) {
+               len = ptr - tgt;
+               goto valid_obd_name;
+       }
+
+       /*
+        * tgt_format fsname-cli'dev'-'uuid' except for the llite case
+        * which are named fsname-'uuid'. Examples:
+        *
+        * lustre-clilov-ffff88104db5b800
+        * lustre-ffff88104db5b800  (for llite device)
+        *
+        * The length of the OBD uuid can vary on different platforms.
+        * This test if any invalid characters are in string. Allow
+        * wildcards with '*' character.
+        */
+       ptr++;
+       if (!strspn(ptr, "0123456789abcdefABCDEF*")) {
+               len = 0;
+               goto no_fsname;
+       }
+
+       /*
+        * Now that we validated the device name lets extract the
+        * file system name. Most of the names in this class will
+        * have '-cli' in its name which needs to be dropped. If
+        * it doesn't have '-cli' then its a llite device which
+        * ptr already points to the start of the uuid string.
+        */
+       tmp = strstr(tgt, "-cli");
+       if (tmp)
+               ptr = tmp;
+       else
+               ptr--;
+       len = ptr - tgt;
+valid_obd_name:
+       len = min_t(size_t, len, LUSTRE_MAXFSNAME);
+       snprintf(fsname, buflen, "%.*s", (int)len, tgt);
+no_fsname:
+       fsname[len] = '\0';
+}
+EXPORT_SYMBOL(obdname2fsname);
+
+/**
+ * SERVER NAME ***
  * <FSNAME><SEPARATOR><TYPE><INDEX>
  * FSNAME is between 1 and 8 characters (inclusive).
  *     Excluded characters are '/' and ':'
@@ -672,7 +784,8 @@ int lustre_put_lsi(struct super_block *sb)
  * INDEX: Hex representation of the index
  */
 
-/** Get the fsname ("lustre") from the server name ("lustre-OST003F").
+/**
+ * Get the fsname ("lustre") from the server name ("lustre-OST003F").
  * @param [in] svname server name including type and index
  * @param [out] fsname Buffer to copy filesystem name prefix into.
  *  Must have at least 'strlen(fsname) + 1' chars.
@@ -683,7 +796,7 @@ int server_name2fsname(const char *svname, char *fsname, const char **endptr)
 {
        const char *dash;
 
-       dash = svname + strnlen(svname, 8); /* max fsname length is 8 */
+       dash = svname + strnlen(svname, LUSTRE_MAXFSNAME);
        for (; dash > svname && *dash != '-' && *dash != ':'; dash--)
                ;
        if (dash == svname)
@@ -776,14 +889,20 @@ int target_name2index(const char *tgtname, __u32 *idx, const char **endptr)
        index = simple_strtoul(dash, (char **)endptr, 16);
        if (idx != NULL)
                *idx = index;
+
+       if (index > 0xffff)
+               return -ERANGE;
+
        return rc;
 }
 EXPORT_SYMBOL(target_name2index);
 
-/* Get the index from the obd name.
-   rc = server type, or
-   rc < 0  on error
-   if endptr isn't NULL it is set to end of name */
+/*
+ * Get the index from the OBD name.
+ * rc = server type, or
+ * rc < 0  on error
+ * if endptr isn't NULL it is set to end of name
+ */
 int server_name2index(const char *svname, __u32 *idx, const char **endptr)
 {
        const char *dash;
@@ -813,24 +932,27 @@ EXPORT_SYMBOL(server_name2index);
 /* Common umount */
 int lustre_common_put_super(struct super_block *sb)
 {
-        int rc;
-        ENTRY;
-
-        CDEBUG(D_MOUNT, "dropping sb %p\n", sb);
-
-        /* Drop a ref to the MGC */
-        rc = lustre_stop_mgc(sb);
-        if (rc && (rc != -ENOENT)) {
-                if (rc != -EBUSY) {
-                        CERROR("Can't stop MGC: %d\n", rc);
-                        RETURN(rc);
-                }
-                /* BUSY just means that there's some other obd that
-                   needs the mgc.  Let him clean it up. */
-                CDEBUG(D_MOUNT, "MGC still in use\n");
-        }
-        /* Drop a ref to the mounted disk */
-        lustre_put_lsi(sb);
+       int rc;
+
+       ENTRY;
+
+       CDEBUG(D_MOUNT, "dropping sb %p\n", sb);
+
+       /* Drop a ref to the MGC */
+       rc = lustre_stop_mgc(sb);
+       if (rc && (rc != -ENOENT)) {
+               if (rc != -EBUSY) {
+                       CERROR("Can't stop MGC: %d\n", rc);
+                       RETURN(rc);
+               }
+               /*
+                * BUSY just means that there's some other OBD that
+                * needs the mgc.  Let him clean it up.
+                */
+               CDEBUG(D_MOUNT, "MGC still in use\n");
+       }
+       /* Drop a ref to the mounted disk */
+       lustre_put_lsi(sb);
 
        RETURN(rc);
 }
@@ -866,27 +988,28 @@ static void lmd_print(struct lustre_mount_data *lmd)
 /* Is this server on the exclusion list */
 int lustre_check_exclusion(struct super_block *sb, char *svname)
 {
-        struct lustre_sb_info *lsi = s2lsi(sb);
-        struct lustre_mount_data *lmd = lsi->lsi_lmd;
-        __u32 index;
-        int i, rc;
-        ENTRY;
-
-        rc = server_name2index(svname, &index, NULL);
-        if (rc != LDD_F_SV_TYPE_OST)
-                /* Only exclude OSTs */
-                RETURN(0);
-
-        CDEBUG(D_MOUNT, "Check exclusion %s (%d) in %d of %s\n", svname,
-               index, lmd->lmd_exclude_count, lmd->lmd_dev);
-
-        for(i = 0; i < lmd->lmd_exclude_count; i++) {
-                if (index == lmd->lmd_exclude[i]) {
-                        CWARN("Excluding %s (on exclusion list)\n", svname);
-                        RETURN(1);
-                }
-        }
-        RETURN(0);
+       struct lustre_sb_info *lsi = s2lsi(sb);
+       struct lustre_mount_data *lmd = lsi->lsi_lmd;
+       __u32 index;
+       int i, rc;
+
+       ENTRY;
+
+       rc = server_name2index(svname, &index, NULL);
+       if (rc != LDD_F_SV_TYPE_OST)
+               /* Only exclude OSTs */
+               RETURN(0);
+
+       CDEBUG(D_MOUNT, "Check exclusion %s (%d) in %d of %s\n", svname,
+              index, lmd->lmd_exclude_count, lmd->lmd_dev);
+
+       for (i = 0; i < lmd->lmd_exclude_count; i++) {
+               if (index == lmd->lmd_exclude[i]) {
+                       CWARN("Excluding %s (on exclusion list)\n", svname);
+                       RETURN(1);
+               }
+       }
+       RETURN(0);
 }
 
 /* mount -v  -o exclude=lustre-OST0001:lustre-OST0002 -t lustre ... */
@@ -896,11 +1019,14 @@ static int lmd_make_exclusion(struct lustre_mount_data *lmd, const char *ptr)
        __u32 *exclude_list;
        __u32 index = 0;
        int rc = 0, devmax;
+
        ENTRY;
 
-       /* The shortest an ost name can be is 8 chars: -OST0000.
-          We don't actually know the fsname at this time, so in fact
-          a user could specify any fsname. */
+       /*
+        * The shortest an ost name can be is 8 chars: -OST0000.
+        * We don't actually know the fsname at this time, so in fact
+        * a user could specify any fsname.
+        */
        devmax = strlen(ptr) / 8 + 1;
 
        /* temp storage until we figure out how many we have */
@@ -923,8 +1049,10 @@ static int lmd_make_exclusion(struct lustre_mount_data *lmd, const char *ptr)
                        CDEBUG(D_MOUNT, "ignoring exclude %.*s: type = %#x\n",
                               (uint)(s2-s1), s1, rc);
                s1 = s2;
-               /* now we are pointing at ':' (next exclude)
-                  or ',' (end of excludes) */
+               /*
+                * now we are pointing at ':' (next exclude)
+                * or ',' (end of excludes)
+                */
                if (lmd->lmd_exclude_count >= devmax)
                        break;
        }
@@ -949,33 +1077,58 @@ static int lmd_make_exclusion(struct lustre_mount_data *lmd, const char *ptr)
 
 static int lmd_parse_mgssec(struct lustre_mount_data *lmd, char *ptr)
 {
-        char   *tail;
-        int     length;
-
-        if (lmd->lmd_mgssec != NULL) {
-                OBD_FREE(lmd->lmd_mgssec, strlen(lmd->lmd_mgssec) + 1);
-                lmd->lmd_mgssec = NULL;
-        }
-
-        tail = strchr(ptr, ',');
-        if (tail == NULL)
-                length = strlen(ptr);
-        else
-                length = tail - ptr;
-
-        OBD_ALLOC(lmd->lmd_mgssec, length + 1);
-        if (lmd->lmd_mgssec == NULL)
-                return -ENOMEM;
-
-        memcpy(lmd->lmd_mgssec, ptr, length);
-        lmd->lmd_mgssec[length] = '\0';
-        return 0;
+       char *tail;
+       int length;
+
+       if (lmd->lmd_mgssec != NULL) {
+               OBD_FREE(lmd->lmd_mgssec, strlen(lmd->lmd_mgssec) + 1);
+               lmd->lmd_mgssec = NULL;
+       }
+
+       tail = strchr(ptr, ',');
+       if (tail == NULL)
+               length = strlen(ptr);
+       else
+               length = tail - ptr;
+
+       OBD_ALLOC(lmd->lmd_mgssec, length + 1);
+       if (lmd->lmd_mgssec == NULL)
+               return -ENOMEM;
+
+       memcpy(lmd->lmd_mgssec, ptr, length);
+       lmd->lmd_mgssec[length] = '\0';
+       return 0;
+}
+
+static int lmd_parse_network(struct lustre_mount_data *lmd, char *ptr)
+{
+       char *tail;
+       int length;
+
+       if (lmd->lmd_nidnet != NULL) {
+               OBD_FREE(lmd->lmd_nidnet, strlen(lmd->lmd_nidnet) + 1);
+               lmd->lmd_nidnet = NULL;
+       }
+
+       tail = strchr(ptr, ',');
+       if (tail == NULL)
+               length = strlen(ptr);
+       else
+               length = tail - ptr;
+
+       OBD_ALLOC(lmd->lmd_nidnet, length + 1);
+       if (lmd->lmd_nidnet == NULL)
+               return -ENOMEM;
+
+       memcpy(lmd->lmd_nidnet, ptr, length);
+       lmd->lmd_nidnet[length] = '\0';
+       return 0;
 }
 
 static int lmd_parse_string(char **handle, char *ptr)
 {
-       char   *tail;
-       int     length;
+       char *tail;
+       int length;
 
        if ((handle == NULL) || (ptr == NULL))
                return -EINVAL;
@@ -1007,11 +1160,13 @@ static int lmd_parse_mgs(struct lustre_mount_data *lmd, char **ptr)
        lnet_nid_t nid;
        char *tail = *ptr;
        char *mgsnid;
-       int   length;
-       int   oldlen = 0;
+       int length;
+       int oldlen = 0;
+
+       /* Find end of NID-list */
+       while (class_parse_nid_quiet(tail, &nid, &tail) == 0)
+               ; /* do nothing */
 
-       /* Find end of nidlist */
-       while (class_parse_nid_quiet(tail, &nid, &tail) == 0) {}
        length = tail - *ptr;
        if (length == 0) {
                LCONSOLE_ERROR_MSG(0x159, "Can't parse NID '%s'\n", *ptr);
@@ -1039,91 +1194,208 @@ static int lmd_parse_mgs(struct lustre_mount_data *lmd, char **ptr)
        return 0;
 }
 
-/** Parse mount line options
+/**
+ * Find the first delimiter (comma or colon) from the specified \a buf and
+ * make \a *endh point to the string starting with the delimiter. The commas
+ * in expression list [...] will be skipped.
+ *
+ * @buf                a delimiter-separated string
+ * @endh       a pointer to a pointer that will point to the string
+ *             starting with the delimiter
+ *
+ * RETURNS     true if delimiter is found, false if delimiter is not found
+ */
+static bool lmd_find_delimiter(char *buf, char **endh)
+{
+       char *c = buf;
+       size_t pos;
+       bool found;
+
+       if (!buf)
+               return false;
+try_again:
+       if (*c == ',' || *c == ':')
+               return true;
+
+       pos = strcspn(c, "[:,]");
+       if (!pos)
+               return false;
+
+       /* Not a valid mount string */
+       if (*c == ']') {
+               CWARN("invalid mount string format\n");
+               return false;
+       }
+
+       c += pos;
+       if (*c == '[') {
+               c = strchr(c, ']');
+
+               /* invalid mount string */
+               if (!c) {
+                       CWARN("invalid mount string format\n");
+                       return false;
+               }
+               c++;
+               goto try_again;
+       }
+
+       found = *c != '\0';
+       if (found && endh)
+               *endh = c;
+
+       return found;
+}
+
+/**
+ * Find the first valid string delimited by comma or colon from the specified
+ * \a buf and parse it to see whether it's a valid NID list. If yes, \a *endh
+ * will point to the next string starting with the delimiter.
+ *
+ * \param[in] buf      a delimiter-separated string
+ * \param[in] endh     a pointer to a pointer that will point to the string
+ *                     starting with the delimiter
+ *
+ * \retval 0           if the string is a valid NID list
+ * \retval 1           if the string is not a valid NID list
+ */
+static int lmd_parse_nidlist(char *buf, char **endh)
+{
+       LIST_HEAD(nidlist);
+       char *endp = buf;
+       char tmp;
+       int rc = 0;
+
+       if (buf == NULL)
+               return 1;
+       while (*buf == ',' || *buf == ':')
+               buf++;
+       if (*buf == ' ' || *buf == '/' || *buf == '\0')
+               return 1;
+
+       if (!lmd_find_delimiter(buf, &endp))
+               endp = buf + strlen(buf);
+
+       tmp = *endp;
+       *endp = '\0';
+
+       if (cfs_parse_nidlist(buf, strlen(buf), &nidlist) <= 0)
+               rc = 1;
+       cfs_free_nidlist(&nidlist);
+
+       *endp = tmp;
+       if (rc != 0)
+               return rc;
+       if (endh != NULL)
+               *endh = endp;
+       return 0;
+}
+
+/**
+ * Parse mount line options
  * e.g. mount -v -t lustre -o abort_recov uml1:uml2:/lustre-client /mnt/lustre
- * dev is passed as device=uml1:/lustre by mount.lustre
+ * dev is passed as device=uml1:/lustre by mount.lustre_tgt
  */
 static int lmd_parse(char *options, struct lustre_mount_data *lmd)
 {
-       char *s1, *s2, *s3, *devname = NULL;
-        struct lustre_mount_data *raw = (struct lustre_mount_data *)options;
-        int rc = 0;
-        ENTRY;
-
-        LASSERT(lmd);
-        if (!options) {
-                LCONSOLE_ERROR_MSG(0x162, "Missing mount data: check that "
-                                   "/sbin/mount.lustre is installed.\n");
-                RETURN(-EINVAL);
-        }
-
-        /* Options should be a string - try to detect old lmd data */
-        if ((raw->lmd_magic & 0xffffff00) == (LMD_MAGIC & 0xffffff00)) {
-                LCONSOLE_ERROR_MSG(0x163, "You're using an old version of "
-                                   "/sbin/mount.lustre.  Please install "
-                                   "version %s\n", LUSTRE_VERSION_STRING);
-                RETURN(-EINVAL);
-        }
-        lmd->lmd_magic = LMD_MAGIC;
+       char *s1, *s2, *devname = NULL;
+       struct lustre_mount_data *raw = (struct lustre_mount_data *)options;
+       int rc = 0;
+
+       ENTRY;
+
+       LASSERT(lmd);
+       if (!options) {
+               LCONSOLE_ERROR_MSG(0x162,
+                                  "Missing mount data: check /sbin/mount.lustre_tgt is installed.\n");
+               RETURN(-EINVAL);
+       }
+
+       /* Options should be a string - try to detect old lmd data */
+       if ((raw->lmd_magic & 0xffffff00) == (LMD_MAGIC & 0xffffff00)) {
+               LCONSOLE_ERROR_MSG(0x163,
+                                  "Using an old version of /sbin/mount.lustre. Please install version %s\n",
+                                  LUSTRE_VERSION_STRING);
+               RETURN(-EINVAL);
+       }
+       lmd->lmd_magic = LMD_MAGIC;
 
        OBD_ALLOC(lmd->lmd_params, LMD_PARAMS_MAXLEN);
        if (lmd->lmd_params == NULL)
                RETURN(-ENOMEM);
        lmd->lmd_params[0] = '\0';
 
-        /* Set default flags here */
+       /* Set default flags here */
 
-        s1 = options;
-        while (*s1) {
-                int clear = 0;
-                int time_min = OBD_RECOVERY_TIME_MIN;
+       s1 = options;
+       while (*s1) {
+               int clear = 0;
+               int time_min = OBD_RECOVERY_TIME_MIN;
+               char *s3;
 
-                /* Skip whitespace and extra commas */
-                while (*s1 == ' ' || *s1 == ',')
-                        s1++;
+               /* Skip whitespace and extra commas */
+               while (*s1 == ' ' || *s1 == ',')
+                       s1++;
                s3 = s1;
 
-                /* Client options are parsed in ll_options: eg. flock,
-                   user_xattr, acl */
-
-                /* Parse non-ldiskfs options here. Rather than modifying
-                   ldiskfs, we just zero these out here */
-                if (strncmp(s1, "abort_recov", 11) == 0) {
-                        lmd->lmd_flags |= LMD_FLG_ABORT_RECOV;
-                        clear++;
-                } else if (strncmp(s1, "recovery_time_soft=", 19) == 0) {
-                        lmd->lmd_recovery_time_soft = max_t(int,
-                                simple_strtoul(s1 + 19, NULL, 10), time_min);
-                        clear++;
-                } else if (strncmp(s1, "recovery_time_hard=", 19) == 0) {
-                        lmd->lmd_recovery_time_hard = max_t(int,
-                                simple_strtoul(s1 + 19, NULL, 10), time_min);
-                        clear++;
-                } else if (strncmp(s1, "noir", 4) == 0) {
-                        lmd->lmd_flags |= LMD_FLG_NOIR; /* test purpose only. */
-                        clear++;
-                } else if (strncmp(s1, "nosvc", 5) == 0) {
-                        lmd->lmd_flags |= LMD_FLG_NOSVC;
-                        clear++;
-                } else if (strncmp(s1, "nomgs", 5) == 0) {
-                        lmd->lmd_flags |= LMD_FLG_NOMGS;
-                        clear++;
+               /*
+                * Client options are parsed in ll_options: eg. flock,
+                * user_xattr, acl
+                */
+
+               /*
+                * Parse non-ldiskfs options here. Rather than modifying
+                * ldiskfs, we just zero these out here
+                */
+               if (strncmp(s1, "abort_recov", 11) == 0) {
+                       lmd->lmd_flags |= LMD_FLG_ABORT_RECOV;
+                       clear++;
+               } else if (strncmp(s1, "recovery_time_soft=", 19) == 0) {
+                       lmd->lmd_recovery_time_soft =
+                               max_t(int, simple_strtoul(s1 + 19, NULL, 10),
+                                     time_min);
+                       clear++;
+               } else if (strncmp(s1, "recovery_time_hard=", 19) == 0) {
+                       lmd->lmd_recovery_time_hard =
+                               max_t(int, simple_strtoul(s1 + 19, NULL, 10),
+                                     time_min);
+                       clear++;
+               } else if (strncmp(s1, "no_precreate", 12) == 0) {
+                       lmd->lmd_flags |= LMD_FLG_NO_PRECREATE;
+                       clear++;
+               } else if (strncmp(s1, "noir", 4) == 0) {
+                       lmd->lmd_flags |= LMD_FLG_NOIR; /* test purpose only. */
+                       clear++;
+               } else if (strncmp(s1, "nosvc", 5) == 0) {
+                       lmd->lmd_flags |= LMD_FLG_NOSVC;
+                       clear++;
+               } else if (strncmp(s1, "nomgs", 5) == 0) {
+                       lmd->lmd_flags |= LMD_FLG_NOMGS;
+                       clear++;
                } else if (strncmp(s1, "noscrub", 7) == 0) {
                        lmd->lmd_flags |= LMD_FLG_NOSCRUB;
                        clear++;
+               } else if (strncmp(s1, "skip_lfsck", 10) == 0) {
+                       lmd->lmd_flags |= LMD_FLG_SKIP_LFSCK;
+                       clear++;
+               } else if (strncmp(s1, "rdonly_dev", 10) == 0) {
+                       lmd->lmd_flags |= LMD_FLG_DEV_RDONLY;
+                       clear++;
                } else if (strncmp(s1, PARAM_MGSNODE,
                                   sizeof(PARAM_MGSNODE) - 1) == 0) {
                        s2 = s1 + sizeof(PARAM_MGSNODE) - 1;
-                       /* Assume the next mount opt is the first
-                          invalid nid we get to. */
+                       /*
+                        * Assume the next mount opt is the first
+                        * invalid NID we get to.
+                        */
                        rc = lmd_parse_mgs(lmd, &s2);
                        if (rc)
                                goto invalid;
                        s3 = s2;
                        clear++;
-                } else if (strncmp(s1, "writeconf", 9) == 0) {
-                        lmd->lmd_flags |= LMD_FLG_WRITECONF;
-                        clear++;
+               } else if (strncmp(s1, "writeconf", 9) == 0) {
+                       lmd->lmd_flags |= LMD_FLG_WRITECONF;
+                       clear++;
                } else if (strncmp(s1, "update", 6) == 0) {
                        lmd->lmd_flags |= LMD_FLG_UPDATE;
                        clear++;
@@ -1133,17 +1405,17 @@ static int lmd_parse(char *options, struct lustre_mount_data *lmd)
                } else if (strncmp(s1, "noprimnode", 10) == 0) {
                        lmd->lmd_flags |= LMD_FLG_NO_PRIMNODE;
                        clear++;
-                } else if (strncmp(s1, "mgssec=", 7) == 0) {
-                        rc = lmd_parse_mgssec(lmd, s1 + 7);
-                        if (rc)
-                                goto invalid;
-                        clear++;
-                /* ost exclusion list */
-                } else if (strncmp(s1, "exclude=", 8) == 0) {
-                        rc = lmd_make_exclusion(lmd, s1 + 7);
-                        if (rc)
-                                goto invalid;
-                        clear++;
+               } else if (strncmp(s1, "mgssec=", 7) == 0) {
+                       rc = lmd_parse_mgssec(lmd, s1 + 7);
+                       if (rc)
+                               goto invalid;
+                       clear++;
+                       /* ost exclusion list */
+               } else if (strncmp(s1, "exclude=", 8) == 0) {
+                       rc = lmd_make_exclusion(lmd, s1 + 7);
+                       if (rc)
+                               goto invalid;
+                       clear++;
                } else if (strncmp(s1, "mgs", 3) == 0) {
                        /* We are an MGS */
                        lmd->lmd_flags |= LMD_FLG_MGS;
@@ -1155,19 +1427,19 @@ static int lmd_parse(char *options, struct lustre_mount_data *lmd)
                        clear++;
                } else if (strncmp(s1, "param=", 6) == 0) {
                        size_t length, params_length;
-                       char *tail = strchr(s1 + 6, ',');
-                       if (tail == NULL) {
-                               length = strlen(s1);
-                       } else {
-                               lnet_nid_t nid;
-                               char      *param_str = tail + 1;
-                               int        supplementary = 1;
+                       char  *tail = s1;
+
+                       if (lmd_find_delimiter(s1 + 6, &tail)) {
+                               char *param_str = tail + 1;
+                               int   supplementary = 1;
 
-                               while (class_parse_nid_quiet(param_str, &nid,
-                                                            &param_str) == 0) {
+                               while (lmd_parse_nidlist(param_str,
+                                                        &param_str) == 0) {
                                        supplementary = 0;
                                }
                                length = param_str - s1 - supplementary;
+                       } else {
+                               length = strlen(s1);
                        }
                        length -= 6;
                        params_length = strlen(lmd->lmd_params);
@@ -1178,242 +1450,331 @@ static int lmd_parse(char *options, struct lustre_mount_data *lmd)
                        strlcat(lmd->lmd_params, " ", LMD_PARAMS_MAXLEN);
                        s3 = s1 + 6 + length;
                        clear++;
+               } else if (strncmp(s1, "localrecov", 10) == 0) {
+                       lmd->lmd_flags |= LMD_FLG_LOCAL_RECOV;
+                       clear++;
                } else if (strncmp(s1, "osd=", 4) == 0) {
                        rc = lmd_parse_string(&lmd->lmd_osd_type, s1 + 4);
                        if (rc)
                                goto invalid;
                        clear++;
-                }
-                /* Linux 2.4 doesn't pass the device, so we stuck it at the
-                   end of the options. */
-                else if (strncmp(s1, "device=", 7) == 0) {
-                        devname = s1 + 7;
-                        /* terminate options right before device.  device
-                           must be the last one. */
-                        *s1 = '\0';
-                        break;
-                }
+               }
+               /*
+                * Linux 2.4 doesn't pass the device, so we stuck it at
+                * the end of the options.
+                */
+               else if (strncmp(s1, "device=", 7) == 0) {
+                       devname = s1 + 7;
+                       /*
+                        * terminate options right before device.  device
+                        * must be the last one.
+                        */
+                       *s1 = '\0';
+                       break;
+               } else if (strncmp(s1, "network=", 8) == 0) {
+                       rc = lmd_parse_network(lmd, s1 + 8);
+                       if (rc)
+                               goto invalid;
+
+                       /* check if LNet dynamic peer discovery is activated */
+                       if (LNetGetPeerDiscoveryStatus()) {
+                               CERROR("LNet Dynamic Peer Discovery is enabled "
+                                      "on this node. 'network' mount option "
+                                      "cannot be taken into account.\n");
+                               goto invalid;
+                       }
+
+                       clear++;
+               }
 
                /* Find next opt */
                s2 = strchr(s3, ',');
-                if (s2 == NULL) {
-                        if (clear)
-                                *s1 = '\0';
-                        break;
-                }
-                s2++;
-                if (clear)
-                        memmove(s1, s2, strlen(s2) + 1);
-                else
-                        s1 = s2;
-        }
-
-        if (!devname) {
-                LCONSOLE_ERROR_MSG(0x164, "Can't find the device name "
-                                   "(need mount option 'device=...')\n");
-                goto invalid;
-        }
-
-        s1 = strstr(devname, ":/");
-        if (s1) {
-                ++s1;
-                lmd->lmd_flags |= LMD_FLG_CLIENT;
-                /* Remove leading /s from fsname */
-                while (*++s1 == '/') ;
-                /* Freed in lustre_free_lsi */
-                OBD_ALLOC(lmd->lmd_profile, strlen(s1) + 8);
-                if (!lmd->lmd_profile)
-                        RETURN(-ENOMEM);
-                sprintf(lmd->lmd_profile, "%s-client", s1);
-        }
-
-        /* Freed in lustre_free_lsi */
-        OBD_ALLOC(lmd->lmd_dev, strlen(devname) + 1);
-        if (!lmd->lmd_dev)
-                RETURN(-ENOMEM);
-        strcpy(lmd->lmd_dev, devname);
-
-        /* Save mount options */
-        s1 = options + strlen(options) - 1;
-        while (s1 >= options && (*s1 == ',' || *s1 == ' '))
-                *s1-- = 0;
-        if (*options != 0) {
-                /* Freed in lustre_free_lsi */
-                OBD_ALLOC(lmd->lmd_opts, strlen(options) + 1);
-                if (!lmd->lmd_opts)
-                        RETURN(-ENOMEM);
-                strcpy(lmd->lmd_opts, options);
-        }
-
-        lmd_print(lmd);
-        lmd->lmd_magic = LMD_MAGIC;
-
-        RETURN(rc);
+               if (s2 == NULL) {
+                       if (clear)
+                               *s1 = '\0';
+                       break;
+               }
+               s2++;
+               if (clear)
+                       memmove(s1, s2, strlen(s2) + 1);
+               else
+                       s1 = s2;
+       }
+
+       if (!devname) {
+               LCONSOLE_ERROR_MSG(0x164,
+                                  "Can't find device name (need mount option 'device=...')\n");
+               goto invalid;
+       }
+
+       s1 = strstr(devname, ":/");
+       if (s1) {
+               ++s1;
+               lmd->lmd_flags |= LMD_FLG_CLIENT;
+               /* Remove leading /s from fsname */
+               while (*++s1 == '/')
+                       ;
+               s2 = s1;
+               while (*s2 != '/' && *s2 != '\0')
+                       s2++;
+               /* Freed in lustre_free_lsi */
+               OBD_ALLOC(lmd->lmd_profile, s2 - s1 + 8);
+               if (!lmd->lmd_profile)
+                       RETURN(-ENOMEM);
+
+               strncat(lmd->lmd_profile, s1, s2 - s1);
+               strncat(lmd->lmd_profile, "-client", 7);
+
+               s1 = s2;
+               s2 = s1 + strlen(s1) - 1;
+               /* Remove padding /s from fileset */
+               while (*s2 == '/')
+                       s2--;
+               if (s2 > s1) {
+                       OBD_ALLOC(lmd->lmd_fileset, s2 - s1 + 2);
+                       if (lmd->lmd_fileset == NULL) {
+                               OBD_FREE(lmd->lmd_profile,
+                                        strlen(lmd->lmd_profile) + 1);
+                               RETURN(-ENOMEM);
+                       }
+                       strncat(lmd->lmd_fileset, s1, s2 - s1 + 1);
+               }
+       } else {
+               /* server mount */
+               if (lmd->lmd_nidnet != NULL) {
+                       /* 'network=' mount option forbidden for server */
+                       OBD_FREE(lmd->lmd_nidnet, strlen(lmd->lmd_nidnet) + 1);
+                       lmd->lmd_nidnet = NULL;
+                       rc = -EINVAL;
+                       CERROR(
+                              "%s: option 'network=' not allowed for Lustre servers: rc = %d\n",
+                              devname, rc);
+                       RETURN(rc);
+               }
+       }
+
+       /* Freed in lustre_free_lsi */
+       OBD_ALLOC(lmd->lmd_dev, strlen(devname) + 1);
+       if (!lmd->lmd_dev)
+               RETURN(-ENOMEM);
+       strncpy(lmd->lmd_dev, devname, strlen(devname)+1);
+
+       /* Save mount options */
+       s1 = options + strlen(options) - 1;
+       while (s1 >= options && (*s1 == ',' || *s1 == ' '))
+               *s1-- = 0;
+       while (*options && (*options == ',' || *options == ' '))
+               options++;
+       if (*options != 0) {
+               /* Freed in lustre_free_lsi */
+               OBD_ALLOC(lmd->lmd_opts, strlen(options) + 1);
+               if (!lmd->lmd_opts)
+                       RETURN(-ENOMEM);
+               strncpy(lmd->lmd_opts, options, strlen(options)+1);
+       }
+
+       lmd_print(lmd);
+       lmd->lmd_magic = LMD_MAGIC;
+
+       RETURN(rc);
 
 invalid:
-        CERROR("Bad mount options %s\n", options);
-        RETURN(-EINVAL);
+       CERROR("Bad mount options %s\n", options);
+       RETURN(-EINVAL);
 }
 
-struct lustre_mount_data2 {
-        void *lmd2_data;
-        struct vfsmount *lmd2_mnt;
-};
-
-/** This is the entry point for the mount call into Lustre.
+/**
+ * This is the entry point for the mount call into Lustre.
  * This is called when a server or client is mounted,
  * and this is where we start setting things up.
  * @param data Mount options (e.g. -o flock,abort_recov)
  */
-static int lustre_fill_super(struct super_block *sb, void *data, int silent)
+static int lustre_fill_super(struct super_block *sb, void *lmd2_data,
+                            int silent)
 {
-        struct lustre_mount_data *lmd;
-        struct lustre_mount_data2 *lmd2 = data;
-        struct lustre_sb_info *lsi;
-        int rc;
-        ENTRY;
+       struct lustre_mount_data *lmd;
+       struct lustre_sb_info *lsi;
+       int rc;
+
+       ENTRY;
 
-        CDEBUG(D_MOUNT|D_VFSTRACE, "VFS Op: sb %p\n", sb);
+       CDEBUG(D_MOUNT|D_VFSTRACE, "VFS Op: sb %p\n", sb);
 
-        lsi = lustre_init_lsi(sb);
-        if (!lsi)
-                RETURN(-ENOMEM);
-        lmd = lsi->lsi_lmd;
+       lsi = lustre_init_lsi(sb);
+       if (!lsi)
+               RETURN(-ENOMEM);
+       lmd = lsi->lsi_lmd;
 
        /*
         * Disable lockdep during mount, because mount locking patterns are
-        * `special'.
+        * 'special'.
         */
        lockdep_off();
 
-        /*
-         * LU-639: the obd cleanup of last mount may not finish yet, wait here.
-         */
-        obd_zombie_barrier();
+       /*
+        * LU-639: the OBD cleanup of last mount may not finish yet, wait here.
+        */
+       obd_zombie_barrier();
+
+       /* Figure out the lmd from the mount options */
+       if (lmd_parse(lmd2_data, lmd)) {
+               lustre_put_lsi(sb);
+               GOTO(out, rc = -EINVAL);
+       }
 
-        /* Figure out the lmd from the mount options */
-        if (lmd_parse((char *)(lmd2->lmd2_data), lmd)) {
-                lustre_put_lsi(sb);
-                GOTO(out, rc = -EINVAL);
-        }
+       if (lmd_is_client(lmd)) {
+               bool have_client = false;
 
-        if (lmd_is_client(lmd)) {
-                CDEBUG(D_MOUNT, "Mounting client %s\n", lmd->lmd_profile);
-               if (client_fill_super == NULL)
+               CDEBUG(D_MOUNT, "Mounting client %s\n", lmd->lmd_profile);
+               if (!client_fill_super)
                        request_module("lustre");
-               if (client_fill_super == NULL) {
-                        LCONSOLE_ERROR_MSG(0x165, "Nothing registered for "
-                                           "client mount! Is the 'lustre' "
-                                           "module loaded?\n");
-                        lustre_put_lsi(sb);
-                        rc = -ENODEV;
-                } else {
-                        rc = lustre_start_mgc(sb);
-                        if (rc) {
-                                lustre_put_lsi(sb);
-                                GOTO(out, rc);
-                        }
-                        /* Connect and start */
-                        /* (should always be ll_fill_super) */
-                        rc = (*client_fill_super)(sb, lmd2->lmd2_mnt);
-                        /* c_f_s will call lustre_common_put_super on failure */
-                }
-        } else {
+               spin_lock(&client_lock);
+               if (client_fill_super && try_module_get(client_mod))
+                       have_client = true;
+               spin_unlock(&client_lock);
+               if (!have_client) {
+                       LCONSOLE_ERROR_MSG(0x165,
+                                          "Nothing registered for client mount! Is the 'lustre' module loaded?\n");
+                       lustre_put_lsi(sb);
+                       rc = -ENODEV;
+               } else {
+                       rc = lustre_start_mgc(sb);
+                       if (rc) {
+                               lustre_common_put_super(sb);
+                               GOTO(out, rc);
+                       }
+                       /* Connect and start */
+                       /* (should always be ll_fill_super) */
+                       rc = (*client_fill_super)(sb);
+                       /* c_f_s will call lustre_common_put_super on failure,
+                        * which takes care of the module reference.
+                        */
+               }
+       } else {
 #ifdef HAVE_SERVER_SUPPORT
                CDEBUG(D_MOUNT, "Mounting server from %s\n", lmd->lmd_dev);
                rc = server_fill_super(sb);
-               /* s_f_s calls lustre_start_mgc after the mount because we need
-                  the MGS nids which are stored on disk.  Plus, we may
-                  need to start the MGS first. */
+               /*
+                * s_f_s calls lustre_start_mgc after the mount because we need
+                * the MGS NIDs which are stored on disk.  Plus, we may
+                * need to start the MGS first.
+                */
                /* s_f_s will call server_put_super on failure */
 #else
-               CERROR("This is client-side-only module, "
-                      "cannot handle server mount.\n");
+               CERROR("client-side-only module, cannot handle server mount\n");
                rc = -EINVAL;
 #endif
-        }
+       }
 
-        /* If error happens in fill_super() call, @lsi will be killed there.
-         * This is why we do not put it here. */
-        GOTO(out, rc);
+       /*
+        * If error happens in fill_super() call, @lsi will be killed there.
+        * This is why we do not put it here.
+        */
+       GOTO(out, rc);
 out:
-        if (rc) {
-                CERROR("Unable to mount %s (%d)\n",
-                       s2lsi(sb) ? lmd->lmd_dev : "", rc);
-        } else {
-                CDEBUG(D_SUPER, "Mount %s complete\n",
-                       lmd->lmd_dev);
-        }
+       if (rc) {
+               CERROR("Unable to mount %s (%d)\n",
+                      s2lsi(sb) ? lmd->lmd_dev : "", rc);
+       } else {
+               CDEBUG(D_SUPER, "Mount %s complete\n",
+                      lmd->lmd_dev);
+       }
        lockdep_on();
        return rc;
 }
 
 
-/* We can't call ll_fill_super by name because it lives in a module that
-   must be loaded after this one. */
-void lustre_register_client_fill_super(int (*cfs)(struct super_block *sb,
-                                                  struct vfsmount *mnt))
-{
-        client_fill_super = cfs;
-}
-EXPORT_SYMBOL(lustre_register_client_fill_super);
-
-void lustre_register_kill_super_cb(void (*cfs)(struct super_block *sb))
+/*
+ * We can't call ll_fill_super by name because it lives in a module that
+ * must be loaded after this one.
+ */
+void lustre_register_super_ops(struct module *mod,
+                              int (*cfs)(struct super_block *sb),
+                              void (*ksc)(struct super_block *sb))
 {
-        kill_super_cb = cfs;
+       spin_lock(&client_lock);
+       client_mod = mod;
+       client_fill_super = cfs;
+       kill_super_cb = ksc;
+       spin_unlock(&client_lock);
 }
-EXPORT_SYMBOL(lustre_register_kill_super_cb);
+EXPORT_SYMBOL(lustre_register_super_ops);
 
 /***************** FS registration ******************/
-#ifdef HAVE_FSTYPE_MOUNT
 static struct dentry *lustre_mount(struct file_system_type *fs_type, int flags,
                                   const char *devname, void *data)
 {
-       struct lustre_mount_data2 lmd2 = { data, NULL };
-
-       return mount_nodev(fs_type, flags, &lmd2, lustre_fill_super);
-}
-#else
-static int lustre_get_sb(struct file_system_type *fs_type, int flags,
-                        const char *devname, void *data, struct vfsmount *mnt)
-{
-       struct lustre_mount_data2 lmd2 = { data, mnt };
-
-       return get_sb_nodev(fs_type, flags, &lmd2, lustre_fill_super, mnt);
+       return mount_nodev(fs_type, flags, data, lustre_fill_super);
 }
-#endif
 
 static void lustre_kill_super(struct super_block *sb)
 {
-        struct lustre_sb_info *lsi = s2lsi(sb);
+       struct lustre_sb_info *lsi = s2lsi(sb);
 
        if (kill_super_cb && lsi && !IS_SERVER(lsi))
-                (*kill_super_cb)(sb);
+               (*kill_super_cb)(sb);
 
-        kill_anon_super(sb);
+       kill_anon_super(sb);
 }
 
-/** Register the "lustre" fs type
+#ifdef HAVE_SERVER_SUPPORT
+/* Register the "lustre_tgt" fs type.
+ *
+ * Right now this isn't any different than the normal "lustre" filesystem
+ * type, but it is added so that there is some compatibility to allow
+ * changing documentation and scripts to start using the "lustre_tgt" type
+ * at mount time. That will simplify test interop, and in case of upgrades
+ * that change to the new type and then need to roll back for some reason.
+ *
+ * The long-term goal is to disentangle the client and server mount code.
  */
-static struct file_system_type lustre_fs_type = {
-        .owner        = THIS_MODULE,
-        .name         = "lustre",
-#ifdef HAVE_FSTYPE_MOUNT
-       .mount        = lustre_mount,
+static struct file_system_type lustre_fs_type_tgt = {
+       .owner          = THIS_MODULE,
+       .name           = "lustre_tgt",
+       .mount          = lustre_mount,
+       .kill_sb        = lustre_kill_super,
+       .fs_flags       = FS_REQUIRES_DEV | FS_RENAME_DOES_D_MOVE,
+};
+MODULE_ALIAS_FS("lustre_tgt");
+
+#define register_filesystem_tgt(fstype)                                            \
+do {                                                                       \
+       int _rc;                                                            \
+                                                                           \
+       _rc = register_filesystem(fstype);                                  \
+       if (_rc && _rc != -EBUSY) {                                         \
+               /* Don't fail if server code also registers "lustre_tgt" */ \
+               CERROR("obdclass: register fstype '%s' failed: rc = %d\n",  \
+                      (fstype)->name, _rc);                                \
+               return _rc;                                                 \
+       }                                                                   \
+} while (0)
+#define unregister_filesystem_tgt(fstype) unregister_filesystem(fstype)
 #else
-        .get_sb       = lustre_get_sb,
+#define register_filesystem_tgt(fstype)   do {} while (0)
+#define unregister_filesystem_tgt(fstype) do {} while (0)
 #endif
-        .kill_sb      = lustre_kill_super,
-       .fs_flags     = FS_REQUIRES_DEV | FS_HAS_FIEMAP | FS_RENAME_DOES_D_MOVE,
+
+/* Register the "lustre" fs type */
+static struct file_system_type lustre_fs_type = {
+       .owner          = THIS_MODULE,
+       .name           = "lustre",
+       .mount          = lustre_mount,
+       .kill_sb        = lustre_kill_super,
+       .fs_flags       = FS_RENAME_DOES_D_MOVE,
 };
 MODULE_ALIAS_FS("lustre");
 
 int lustre_register_fs(void)
 {
-        return register_filesystem(&lustre_fs_type);
+       register_filesystem_tgt(&lustre_fs_type_tgt);
+
+       return register_filesystem(&lustre_fs_type);
 }
 
 int lustre_unregister_fs(void)
 {
-        return unregister_filesystem(&lustre_fs_type);
+       unregister_filesystem_tgt(&lustre_fs_type_tgt);
+
+       return unregister_filesystem(&lustre_fs_type);
 }