From 707916ab3cf220ff1784f958a0bddb42063b1bc6 Mon Sep 17 00:00:00 2001
From: ericm <ericm>
Date: Tue, 25 Nov 2008 01:23:48 +0000
Subject: [PATCH] branch: HEAD support gss on mgc-mgs connection. b=16054
 r=umka r=vitaly

---
 lustre/include/lustre_disk.h     |   1 +
 lustre/include/lustre_sec.h      |  10 ++-
 lustre/include/obd.h             |   2 +
 lustre/ldlm/ldlm_lib.c           |   1 +
 lustre/mdt/mdt_handler.c         |   3 +-
 lustre/mgc/mgc_request.c         |  65 ++++++++++++++++++-
 lustre/mgs/lproc_mgs.c           |  86 +++++++++++++++----------
 lustre/mgs/mgs_handler.c         |  65 ++++++++++++++++++-
 lustre/mgs/mgs_internal.h        |   7 ++-
 lustre/mgs/mgs_llog.c            | 105 ++++++++++++++++++++-----------
 lustre/obdclass/obd_mount.c      |  51 ++++++++++++++-
 lustre/ost/ost_handler.c         |   3 +-
 lustre/ptlrpc/gss/gss_internal.h |   8 ++-
 lustre/ptlrpc/sec.c              |  17 +++--
 lustre/ptlrpc/sec_config.c       |  18 +++---
 lustre/tests/sanity-gss.sh       |  77 ++++++++++++++++++++++-
 lustre/utils/gss/gss_util.c      |  26 +++++++-
 lustre/utils/gss/gssd.h          |   1 +
 lustre/utils/gss/lgss_utils.c    |   2 +-
 lustre/utils/gss/lgss_utils.h    |   8 +--
 lustre/utils/gss/lsupport.c      |   1 +
 lustre/utils/gss/lsupport.h      |   5 +-
 lustre/utils/gss/svcgssd.c       |  15 +++--
 lustre/utils/gss/svcgssd.h       |   3 +-
 lustre/utils/gss/svcgssd_proc.c  |   5 +-
 lustre/utils/obd.c               |   3 -
 26 files changed, 469 insertions(+), 119 deletions(-)

diff --git a/lustre/include/lustre_disk.h b/lustre/include/lustre_disk.h
index 6e0a0f6dc9..e9b15b8cf9 100644
--- a/lustre/include/lustre_disk.h
+++ b/lustre/include/lustre_disk.h
@@ -169,6 +169,7 @@ struct lustre_mount_data {
         int        lmd_exclude_count;
         char      *lmd_dev;           /* device name */
         char      *lmd_profile;       /* client only */
+        char      *lmd_mgssec;        /* sptlrpc flavor to mgs */
         char      *lmd_opts;          /* lustre mount options (as opposed to 
                                          _device_ mount options) */
         __u32     *lmd_exclude;       /* array of OSTs to ignore */
diff --git a/lustre/include/lustre_sec.h b/lustre/include/lustre_sec.h
index f391e35557..57a58c7a28 100644
--- a/lustre/include/lustre_sec.h
+++ b/lustre/include/lustre_sec.h
@@ -162,7 +162,8 @@ enum sptlrpc_service_type {
                       SPTLRPC_MECH_GSS_KRB5,            \
                       SPTLRPC_SVC_PRIV)
 
-#define SPTLRPC_FLVR_INVALID            ((__u16) -1)
+#define SPTLRPC_FLVR_ANY                ((__u16) 0xf000)
+#define SPTLRPC_FLVR_INVALID            ((__u16) 0xffff)
 
 #define SPTLRPC_FLVR_DEFAULT            SPTLRPC_FLVR_NULL
 
@@ -214,6 +215,8 @@ struct sptlrpc_rule_set {
         struct sptlrpc_rule    *srs_rules;
 };
 
+int sptlrpc_parse_flavor(const char *str, struct sptlrpc_flavor *flvr);
+
 static inline void sptlrpc_rule_set_init(struct sptlrpc_rule_set *set)
 {
         memset(set, 0, sizeof(*set));
@@ -224,6 +227,11 @@ int  sptlrpc_rule_set_expand(struct sptlrpc_rule_set *set, int expand);
 int  sptlrpc_rule_set_merge(struct sptlrpc_rule_set *set,
                             struct sptlrpc_rule *rule,
                             int expand);
+int sptlrpc_rule_set_choose(struct sptlrpc_rule_set *rset,
+                            enum lustre_sec_part from,
+                            enum lustre_sec_part to,
+                            lnet_nid_t nid,
+                            struct sptlrpc_flavor *sf);
 void sptlrpc_rule_set_dump(struct sptlrpc_rule_set *set);
 
 int  sptlrpc_process_config(struct lustre_cfg *lcfg);
diff --git a/lustre/include/obd.h b/lustre/include/obd.h
index 86f8659330..badcf8f325 100644
--- a/lustre/include/obd.h
+++ b/lustre/include/obd.h
@@ -391,6 +391,7 @@ struct client_obd {
 
         enum lustre_sec_part     cl_sp_me;
         enum lustre_sec_part     cl_sp_to;
+        struct sptlrpc_flavor    cl_flvr_mgc;   /* fixed flavor of mgc->mgs */
 
         //struct llog_canceld_ctxt *cl_llcd; /* it's included by obd_llog_ctxt */
         void                    *cl_llcd_offset;
@@ -1109,6 +1110,7 @@ enum obd_cleanup_stage {
 #define KEY_BLOCKSIZE_BITS      "blocksize_bits"
 #define KEY_FIEMAP              "FIEMAP"
 #define KEY_SPTLRPC_CONF        "sptlrpc_conf"
+#define KEY_MGSSEC              "mgssec"
 /* XXX unused ?*/
 #define KEY_INTERMDS            "inter_mds"
 #define KEY_ASYNC               "async"
diff --git a/lustre/ldlm/ldlm_lib.c b/lustre/ldlm/ldlm_lib.c
index 7f65388803..b39e1c5b90 100644
--- a/lustre/ldlm/ldlm_lib.c
+++ b/lustre/ldlm/ldlm_lib.c
@@ -235,6 +235,7 @@ int client_obd_setup(struct obd_device *obddev, struct lustre_cfg *lcfg)
                 connect_op = MGS_CONNECT;
                 cli->cl_sp_me = LUSTRE_SP_MGC;
                 cli->cl_sp_to = LUSTRE_SP_MGS;
+                cli->cl_flvr_mgc.sf_rpc = SPTLRPC_FLVR_INVALID;
         } else {
                 CERROR("unknown client OBD type \"%s\", can't setup\n",
                        name);
diff --git a/lustre/mdt/mdt_handler.c b/lustre/mdt/mdt_handler.c
index 061e22cde7..d9437f7f7c 100644
--- a/lustre/mdt/mdt_handler.c
+++ b/lustre/mdt/mdt_handler.c
@@ -4774,7 +4774,8 @@ static int mdt_connect_check_sptlrpc(struct mdt_device *mdt,
                 exp->exp_sp_peer = req->rq_sp_from;
                 exp->exp_flvr = flvr;
 
-                if (exp->exp_flvr.sf_rpc != req->rq_flvr.sf_rpc) {
+                if (exp->exp_flvr.sf_rpc != SPTLRPC_FLVR_ANY &&
+                    exp->exp_flvr.sf_rpc != req->rq_flvr.sf_rpc) {
                         CERROR("unauthorized rpc flavor %x from %s, "
                                "expect %x\n", req->rq_flvr.sf_rpc,
                                libcfs_nid2str(req->rq_peer.nid),
diff --git a/lustre/mgc/mgc_request.c b/lustre/mgc/mgc_request.c
index 2ab2ef3e3f..bf696c1e76 100644
--- a/lustre/mgc/mgc_request.c
+++ b/lustre/mgc/mgc_request.c
@@ -316,17 +316,29 @@ DECLARE_MUTEX(llog_process_lock);
 /* Stop watching for updates on this log. */
 static int config_log_end(char *logname, struct config_llog_instance *cfg)
 {
-        struct config_llog_data *cld, *cld_sptlrpc;
+        struct config_llog_data *cld, *cld_sptlrpc = NULL;
         int rc = 0;
         ENTRY;
 
         cld = config_log_find(logname, cfg);
         if (IS_ERR(cld))
                 RETURN(PTR_ERR(cld));
-        /* drop the ref from the find */
-        config_log_put(cld);
 
         down(&llog_process_lock);
+        /*
+         * if cld_stopping is set, it means we didn't start the log thus
+         * not owning the start ref. this can happen after previous umount:
+         * the cld still hanging there waiting for lock cancel, and we
+         * remount again but failed in the middle and call log_end without
+         * calling start_log.
+         */
+        if (unlikely(cld->cld_stopping)) {
+                up(&llog_process_lock);
+                /* drop the ref from the find */
+                config_log_put(cld);
+                RETURN(rc);
+        }
+
         cld->cld_stopping = 1;
         up(&llog_process_lock);
 
@@ -338,8 +350,11 @@ static int config_log_end(char *logname, struct config_llog_instance *cfg)
         if (cld_sptlrpc)
                 config_log_put(cld_sptlrpc);
 
+        /* drop the ref from the find */
+        config_log_put(cld);
         /* drop the start ref */
         config_log_put(cld);
+
         CDEBUG(D_MGC, "end config log %s (%d)\n", logname ? logname : "client",
                rc);
         RETURN(rc);
@@ -671,6 +686,7 @@ static int mgc_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
 
         lprocfs_mgc_init_vars(&lvars);
         lprocfs_obd_setup(obd, lvars.obd_vars);
+        sptlrpc_lprocfs_cliobd_attach(obd);
 
         spin_lock(&config_list_lock);
         atomic_inc(&mgc_count);
@@ -1004,6 +1020,49 @@ int mgc_set_info_async(struct obd_export *exp, obd_count keylen,
                 rc =  mgc_set_mgs_param(exp, msp);
                 RETURN(rc);
         }
+        if (KEY_IS(KEY_MGSSEC)) {
+                struct client_obd     *cli = &exp->exp_obd->u.cli;
+                struct sptlrpc_flavor  flvr;
+
+                /*
+                 * empty string means using current flavor, if which haven't
+                 * been set yet, set it as null.
+                 *
+                 * if flavor has been set previously, check the asking flavor
+                 * must match the existing one.
+                 */
+                if (vallen == 0) {
+                        if (cli->cl_flvr_mgc.sf_rpc != SPTLRPC_FLVR_INVALID)
+                                RETURN(0);
+                        val = "null";
+                        vallen = 4;
+                }
+
+                rc = sptlrpc_parse_flavor(val, &flvr);
+                if (rc) {
+                        CERROR("invalid sptlrpc flavor %s to MGS\n",
+                               (char *) val);
+                        RETURN(rc);
+                }
+
+                /*
+                 * caller already hold a mutex
+                 */
+                if (cli->cl_flvr_mgc.sf_rpc == SPTLRPC_FLVR_INVALID) {
+                        cli->cl_flvr_mgc = flvr;
+                } else if (memcmp(&cli->cl_flvr_mgc, &flvr,
+                                  sizeof(flvr)) != 0) {
+                        char    str[20];
+
+                        sptlrpc_flavor2name(&cli->cl_flvr_mgc,
+                                            str, sizeof(str));
+                        LCONSOLE_ERROR("asking sptlrpc flavor %s to MGS but "
+                                       "currently %s is in use\n",
+                                       (char *) val, str);
+                        rc = -EPERM;
+                }
+                RETURN(rc);
+        }
 
         RETURN(rc);
 }
diff --git a/lustre/mgs/lproc_mgs.c b/lustre/mgs/lproc_mgs.c
index d3434bf4da..b6732802fd 100644
--- a/lustre/mgs/lproc_mgs.c
+++ b/lustre/mgs/lproc_mgs.c
@@ -88,6 +88,54 @@ static int mgs_fs_seq_show(struct seq_file *seq, void *v)
 
 LPROC_SEQ_FOPS_RO(mgs_fs);
 
+static void seq_show_srpc_rules(struct seq_file *seq, const char *tgtname,
+                                struct sptlrpc_rule_set *rset)
+{
+        struct sptlrpc_rule    *r;
+        char                    dirbuf[10];
+        char                    flvrbuf[40];
+        char                   *net;
+        int                     i;
+
+        for (i = 0; i < rset->srs_nrule; i++) {
+                r = &rset->srs_rules[i];
+
+                if (r->sr_netid == LNET_NIDNET(LNET_NID_ANY))
+                        net = "default";
+                else
+                        net = libcfs_net2str(r->sr_netid);
+
+                if (r->sr_from == LUSTRE_SP_ANY && r->sr_to == LUSTRE_SP_ANY)
+                        dirbuf[0] = '\0';
+                else
+                        snprintf(dirbuf, sizeof(dirbuf), ".%s2%s",
+                                 sptlrpc_part2name(r->sr_from),
+                                 sptlrpc_part2name(r->sr_to));
+
+                sptlrpc_flavor2name(&r->sr_flvr, flvrbuf, sizeof(flvrbuf));
+                seq_printf(seq, "%s.srpc.flavor.%s%s=%s\n", tgtname,
+                           net, dirbuf, flvrbuf);
+        }
+}
+
+static int mgsself_srpc_seq_show(struct seq_file *seq, void *v)
+{
+        struct obd_device *obd = seq->private;
+        struct fs_db      *fsdb;
+        int                rc;
+
+        rc = mgs_find_or_make_fsdb(obd, MGSSELF_NAME, &fsdb);
+        if (rc)
+                return rc;
+
+        down(&fsdb->fsdb_sem);
+        seq_show_srpc_rules(seq, fsdb->fsdb_name, &fsdb->fsdb_srpc_gen);
+        up(&fsdb->fsdb_sem);
+        return 0;
+}
+
+LPROC_SEQ_FOPS_RO(mgsself_srpc);
+
 int lproc_mgs_setup(struct obd_device *obd)
 {
         struct mgs_obd *mgs = &obd->u.mgs;
@@ -95,6 +143,8 @@ int lproc_mgs_setup(struct obd_device *obd)
 
         rc = lprocfs_obd_seq_create(obd, "filesystems", 0444,
                                     &mgs_fs_fops, obd);
+        rc = lprocfs_obd_seq_create(obd, "srpc_rules", 0600,
+                                    &mgsself_srpc_fops, obd);
 
         mgs->mgs_proc_live = lprocfs_register("live", obd->obd_proc_entry,
                                               NULL, NULL);
@@ -136,36 +186,6 @@ int lproc_mgs_cleanup(struct obd_device *obd)
         return lprocfs_obd_cleanup(obd);
 }
 
-static void seq_show_srpc_rule(struct seq_file *seq, const char *tgtname,
-                               struct sptlrpc_rule_set *rset)
-{
-        struct sptlrpc_rule    *r;
-        char                    dirbuf[10];
-        char                    flvrbuf[40];
-        char                   *net;
-        int                     i;
-
-        for (i = 0; i < rset->srs_nrule; i++) {
-                r = &rset->srs_rules[i];
-
-                if (r->sr_netid == LNET_NIDNET(LNET_NID_ANY))
-                        net = "default";
-                else
-                        net = libcfs_net2str(r->sr_netid);
-
-                if (r->sr_from == LUSTRE_SP_ANY && r->sr_to == LUSTRE_SP_ANY)
-                        dirbuf[0] = '\0';
-                else
-                        snprintf(dirbuf, sizeof(dirbuf), ".%s2%s",
-                                 sptlrpc_part2name(r->sr_from),
-                                 sptlrpc_part2name(r->sr_to));
-
-                sptlrpc_flavor2name(&r->sr_flvr, flvrbuf, sizeof(flvrbuf));
-                seq_printf(seq, "%s.srpc.flavor.%s%s=%s\n", tgtname,
-                           net, dirbuf, flvrbuf);
-        }
-}
-
 static int mgs_live_seq_show(struct seq_file *seq, void *v)
 {
         struct fs_db             *fsdb = seq->private;
@@ -191,10 +211,10 @@ static int mgs_live_seq_show(struct seq_file *seq, void *v)
 #endif
         for (srpc_tgt = fsdb->fsdb_srpc_tgt; srpc_tgt;
              srpc_tgt = srpc_tgt->mtsc_next) {
-                seq_show_srpc_rule(seq, srpc_tgt->mtsc_tgt,
-                                   &srpc_tgt->mtsc_rset);
+                seq_show_srpc_rules(seq, srpc_tgt->mtsc_tgt,
+                                    &srpc_tgt->mtsc_rset);
         }
-        seq_show_srpc_rule(seq, fsdb->fsdb_name, &fsdb->fsdb_srpc_gen);
+        seq_show_srpc_rules(seq, fsdb->fsdb_name, &fsdb->fsdb_srpc_gen);
 
         up(&fsdb->fsdb_sem);
         return 0;
diff --git a/lustre/mgs/mgs_handler.c b/lustre/mgs/mgs_handler.c
index 9fbe6c2ad3..d9b827214e 100644
--- a/lustre/mgs/mgs_handler.c
+++ b/lustre/mgs/mgs_handler.c
@@ -80,8 +80,6 @@ static int mgs_connect(const struct lu_env *env,
         exp = class_conn2export(conn);
         LASSERT(exp);
 
-        exp->exp_flvr.sf_rpc = SPTLRPC_FLVR_NULL;
-
         mgs_counter_incr(exp, LPROC_MGS_CONNECT);
 
         if (data != NULL) {
@@ -560,6 +558,60 @@ static int mgs_set_info_rpc(struct ptlrpc_request *req)
         RETURN(rc);
 }
 
+/*
+ * similar as in ost_connect_check_sptlrpc()
+ */
+static int mgs_connect_check_sptlrpc(struct ptlrpc_request *req)
+{
+        struct obd_export     *exp = req->rq_export;
+        struct obd_device     *obd = exp->exp_obd;
+        struct fs_db          *fsdb;
+        struct sptlrpc_flavor  flvr;
+        int                    rc = 0;
+
+        if (exp->exp_flvr.sf_rpc == SPTLRPC_FLVR_INVALID) {
+                rc = mgs_find_or_make_fsdb(obd, MGSSELF_NAME, &fsdb);
+                if (rc)
+                        return rc;
+
+                down(&fsdb->fsdb_sem);
+                if (sptlrpc_rule_set_choose(&fsdb->fsdb_srpc_gen,
+                                            LUSTRE_SP_MGC, LUSTRE_SP_MGS,
+                                            req->rq_peer.nid,
+                                            &flvr) == 0) {
+                        /* by defualt allow any flavors */
+                        flvr.sf_rpc = SPTLRPC_FLVR_ANY;
+                }
+                up(&fsdb->fsdb_sem);
+
+                spin_lock(&exp->exp_lock);
+
+                exp->exp_sp_peer = req->rq_sp_from;
+                exp->exp_flvr = flvr;
+
+                if (exp->exp_flvr.sf_rpc != SPTLRPC_FLVR_ANY &&
+                    exp->exp_flvr.sf_rpc != req->rq_flvr.sf_rpc) {
+                        CERROR("invalid rpc flavor %x, expect %x, from %s\n",
+                               req->rq_flvr.sf_rpc, exp->exp_flvr.sf_rpc,
+                               libcfs_nid2str(req->rq_peer.nid));
+                        rc = -EACCES;
+                }
+
+                spin_unlock(&exp->exp_lock);
+        } else {
+                if (exp->exp_sp_peer != req->rq_sp_from) {
+                        CERROR("RPC source %s doesn't match %s\n",
+                               sptlrpc_part2name(req->rq_sp_from),
+                               sptlrpc_part2name(exp->exp_sp_peer));
+                        rc = -EACCES;
+                } else {
+                        rc = sptlrpc_target_export_check(exp, req);
+                }
+        }
+
+        return rc;
+}
+
 /* Called whenever a target cleans up. */
 /* XXX - Currently unused */
 static int mgs_handle_target_del(struct ptlrpc_request *req)
@@ -591,6 +643,12 @@ int mgs_handle(struct ptlrpc_request *req)
 
         LASSERT(current->journal_info == NULL);
         opc = lustre_msg_get_opc(req->rq_reqmsg);
+
+        if (opc == SEC_CTX_INIT ||
+            opc == SEC_CTX_INIT_CONT ||
+            opc == SEC_CTX_FINI)
+                GOTO(out, rc = 0);
+
         if (opc != MGS_CONNECT) {
                 if (req->rq_export == NULL) {
                         CERROR("lustre_mgs: operation %d on unconnected MGS\n",
@@ -606,6 +664,9 @@ int mgs_handle(struct ptlrpc_request *req)
                 /* MGS and MDS have same request format for connect */
                 req_capsule_set(&req->rq_pill, &RQF_MDS_CONNECT);
                 rc = target_handle_connect(req);
+                if (rc == 0)
+                        rc = mgs_connect_check_sptlrpc(req);
+
                 if (!rc && (lustre_msg_get_conn_cnt(req->rq_reqmsg) > 1))
                         /* Make clients trying to reconnect after a MGS restart
                            happy; also requires obd_replayable */
diff --git a/lustre/mgs/mgs_internal.h b/lustre/mgs/mgs_internal.h
index eeb98e952b..8ae2d6822b 100644
--- a/lustre/mgs/mgs_internal.h
+++ b/lustre/mgs/mgs_internal.h
@@ -52,6 +52,8 @@ int class_dentry_readdir(struct obd_device *obd, struct dentry *dir,
                          struct vfsmount *inmnt,
                          struct list_head *dentry_list);
 
+#define MGSSELF_NAME    "_mgs"
+
 struct mgs_tgt_srpc_conf {
         struct mgs_tgt_srpc_conf  *mtsc_next;
         char                      *mtsc_tgt;
@@ -82,11 +84,14 @@ struct fs_db {
         /* in-memory copy of the srpc rules, guarded by fsdb_sem */
         struct sptlrpc_rule_set   fsdb_srpc_gen;
         struct mgs_tgt_srpc_conf *fsdb_srpc_tgt;
-        unsigned int              fsdb_srpc_fl_udesc:1;
+        unsigned int              fsdb_fl_udesc:1,
+                                  fsdb_fl_mgsself:1;
 };
 
 int mgs_init_fsdb_list(struct obd_device *obd);
 int mgs_cleanup_fsdb_list(struct obd_device *obd);
+int mgs_find_or_make_fsdb(struct obd_device *obd, char *name, 
+                          struct fs_db **dbh);
 int mgs_get_fsdb_srpc_from_llog(struct obd_device *obd, struct fs_db *fsdb);
 int mgs_check_index(struct obd_device *obd, struct mgs_target_info *mti);
 int mgs_check_failnid(struct obd_device *obd, struct mgs_target_info *mti);
diff --git a/lustre/mgs/mgs_llog.c b/lustre/mgs/mgs_llog.c
index 6440f2ff4f..797bc1aea6 100644
--- a/lustre/mgs/mgs_llog.c
+++ b/lustre/mgs/mgs_llog.c
@@ -320,37 +320,46 @@ static struct fs_db *mgs_new_fsdb(struct obd_device *obd, char *fsname)
         int rc;
         ENTRY;
 
+        if (strlen(fsname) >= sizeof(fsdb->fsdb_name)) {
+                CERROR("fsname %s is too long\n", fsname);
+                RETURN(NULL);
+        }
+
         OBD_ALLOC_PTR(fsdb);
         if (!fsdb)
                 RETURN(NULL);
 
-        OBD_ALLOC(fsdb->fsdb_ost_index_map, INDEX_MAP_SIZE);
-        OBD_ALLOC(fsdb->fsdb_mdt_index_map, INDEX_MAP_SIZE);
-        if (!fsdb->fsdb_ost_index_map || !fsdb->fsdb_mdt_index_map) {
-                CERROR("No memory for index maps\n");
-                GOTO(err, 0);
-        }
+        strcpy(fsdb->fsdb_name, fsname);
+        sema_init(&fsdb->fsdb_sem, 1);
+        fsdb->fsdb_fl_udesc = 1;
 
-        strncpy(fsdb->fsdb_name, fsname, sizeof(fsdb->fsdb_name));
-        fsdb->fsdb_name[sizeof(fsdb->fsdb_name) - 1] = 0;
-        rc = name_create(&fsdb->fsdb_mdtlov, fsname, "-mdtlov");
-        if (rc)
-                GOTO(err, rc);
-        rc = name_create(&fsdb->fsdb_mdtlmv, fsname, "-mdtlmv");
-        if (rc)
-                GOTO(err, rc);
-        rc = name_create(&fsdb->fsdb_clilov, fsname, "-clilov");
-        if (rc)
-                GOTO(err, rc);
+        if (strcmp(fsname, MGSSELF_NAME) == 0) {
+                fsdb->fsdb_fl_mgsself = 1;
+        } else {
+                OBD_ALLOC(fsdb->fsdb_ost_index_map, INDEX_MAP_SIZE);
+                OBD_ALLOC(fsdb->fsdb_mdt_index_map, INDEX_MAP_SIZE);
+                if (!fsdb->fsdb_ost_index_map || !fsdb->fsdb_mdt_index_map) {
+                        CERROR("No memory for index maps\n");
+                        GOTO(err, 0);
+                }
 
-        rc = name_create(&fsdb->fsdb_clilmv, fsname, "-clilmv");
-        if (rc)
-                GOTO(err, rc);
+                rc = name_create(&fsdb->fsdb_mdtlov, fsname, "-mdtlov");
+                if (rc)
+                        GOTO(err, rc);
+                rc = name_create(&fsdb->fsdb_mdtlmv, fsname, "-mdtlmv");
+                if (rc)
+                        GOTO(err, rc);
+                rc = name_create(&fsdb->fsdb_clilov, fsname, "-clilov");
+                if (rc)
+                        GOTO(err, rc);
+                rc = name_create(&fsdb->fsdb_clilmv, fsname, "-clilmv");
+                if (rc)
+                        GOTO(err, rc);
+
+                lproc_mgs_add_live(obd, fsdb);
+        }
 
-        fsdb->fsdb_srpc_fl_udesc = 1;
-        sema_init(&fsdb->fsdb_sem, 1);
         list_add(&fsdb->fsdb_list, &mgs->mgs_fs_db_list);
-        lproc_mgs_add_live(obd, fsdb);
 
         RETURN(fsdb);
 err:
@@ -372,8 +381,10 @@ static void mgs_free_fsdb(struct obd_device *obd, struct fs_db *fsdb)
         down(&fsdb->fsdb_sem);
         lproc_mgs_del_live(obd, fsdb);
         list_del(&fsdb->fsdb_list);
-        OBD_FREE(fsdb->fsdb_ost_index_map, INDEX_MAP_SIZE);
-        OBD_FREE(fsdb->fsdb_mdt_index_map, INDEX_MAP_SIZE);
+        if (fsdb->fsdb_ost_index_map)
+                OBD_FREE(fsdb->fsdb_ost_index_map, INDEX_MAP_SIZE);
+        if (fsdb->fsdb_mdt_index_map)
+                OBD_FREE(fsdb->fsdb_mdt_index_map, INDEX_MAP_SIZE);
         name_destroy(&fsdb->fsdb_clilov);
         name_destroy(&fsdb->fsdb_clilmv);
         name_destroy(&fsdb->fsdb_mdtlov);
@@ -404,8 +415,8 @@ int mgs_cleanup_fsdb_list(struct obd_device *obd)
         return 0;
 }
 
-static int mgs_find_or_make_fsdb(struct obd_device *obd, char *name,
-                               struct fs_db **dbh)
+int mgs_find_or_make_fsdb(struct obd_device *obd, char *name,
+                          struct fs_db **dbh)
 {
         struct mgs_obd *mgs = &obd->u.mgs;
         struct fs_db *fsdb;
@@ -425,12 +436,14 @@ static int mgs_find_or_make_fsdb(struct obd_device *obd, char *name,
         if (!fsdb)
                 return -ENOMEM;
 
-        /* populate the db from the client llog */
-        rc = mgs_get_fsdb_from_llog(obd, fsdb);
-        if (rc) {
-                CERROR("Can't get db from client log %d\n", rc);
-                mgs_free_fsdb(obd, fsdb);
-                return rc;
+        if (!fsdb->fsdb_fl_mgsself) {
+                /* populate the db from the client llog */
+                rc = mgs_get_fsdb_from_llog(obd, fsdb);
+                if (rc) {
+                        CERROR("Can't get db from client log %d\n", rc);
+                        mgs_free_fsdb(obd, fsdb);
+                        return rc;
+                }
         }
 
         /* populate srpc rules from params llog */
@@ -1923,10 +1936,10 @@ static int mgs_srpc_set_param_udesc_mem(struct fs_db *fsdb,
                 goto error_out;
 
         if (strcmp(ptr, "yes") == 0) {
-                fsdb->fsdb_srpc_fl_udesc = 1;
+                fsdb->fsdb_fl_udesc = 1;
                 CWARN("Enable user descriptor shipping from client to MDT\n");
         } else if (strcmp(ptr, "no") == 0) {
-                fsdb->fsdb_srpc_fl_udesc = 0;
+                fsdb->fsdb_fl_udesc = 0;
                 CWARN("Disable user descriptor shipping from client to MDT\n");
         } else {
                 *(ptr - 1) = '=';
@@ -1969,6 +1982,15 @@ static int mgs_srpc_set_param_mem(struct fs_db *fsdb,
         if (rc)
                 RETURN(rc);
 
+        /* mgs rules implies must be mgc->mgs */
+        if (fsdb->fsdb_fl_mgsself) {
+                if ((rule.sr_from != LUSTRE_SP_MGC &&
+                     rule.sr_from != LUSTRE_SP_ANY) ||
+                    (rule.sr_to != LUSTRE_SP_MGS &&
+                     rule.sr_to != LUSTRE_SP_ANY))
+                        RETURN(-EINVAL);
+        }
+
         /* preapre room for this coming rule. svcname format should be:
          * - fsname: general rule
          * - fsname-tgtname: target-specific rule
@@ -2038,6 +2060,17 @@ static int mgs_srpc_set_param(struct obd_device *obd,
 
         /* previous steps guaranteed the syntax is correct */
         rc = mgs_srpc_set_param_disk(obd, fsdb, mti, copy);
+        if (rc)
+                goto out_free;
+
+        if (fsdb->fsdb_fl_mgsself) {
+                /*
+                 * for mgs rules, make them effective immediately.
+                 */
+                LASSERT(fsdb->fsdb_srpc_tgt == NULL);
+                sptlrpc_target_update_exp_flavor(obd, &fsdb->fsdb_srpc_gen);
+        }
+
 out_free:
         OBD_FREE(copy, copy_size);
         RETURN(rc);
@@ -2765,7 +2798,7 @@ int mgs_setparam(struct obd_device *obd, struct lustre_cfg *lcfg, char *fsname)
         rc = mgs_find_or_make_fsdb(obd, fsname, &fsdb);
         if (rc)
                 RETURN(rc);
-        if (fsdb->fsdb_flags & FSDB_LOG_EMPTY) {
+        if (!fsdb->fsdb_fl_mgsself && fsdb->fsdb_flags & FSDB_LOG_EMPTY) {
                 CERROR("No filesystem targets for %s.  cfg_device from lctl "
                        "is '%s'\n", fsname, devname);
                 mgs_free_fsdb(obd, fsdb);
diff --git a/lustre/obdclass/obd_mount.c b/lustre/obdclass/obd_mount.c
index 979aaa5341..be853c9f39 100644
--- a/lustre/obdclass/obd_mount.c
+++ b/lustre/obdclass/obd_mount.c
@@ -572,7 +572,7 @@ static int lustre_start_mgc(struct super_block *sb)
         struct obd_uuid *uuid;
         class_uuid_t uuidc;
         lnet_nid_t nid;
-        char *mgcname, *niduuid;
+        char *mgcname, *niduuid, *mgssec;
         char *ptr;
         int recov_bk;
         int rc = 0, i = 0, j, len;
@@ -615,10 +615,18 @@ static int lustre_start_mgc(struct super_block *sb)
                 GOTO(out_free, rc = -ENOMEM);
         sprintf(mgcname, "%s%s", LUSTRE_MGC_OBDNAME, libcfs_nid2str(nid));
 
+        mgssec = lsi->lsi_lmd->lmd_mgssec ? lsi->lsi_lmd->lmd_mgssec : "";
+
         mutex_down(&mgc_start_lock);
 
         obd = class_name2obd(mgcname);
         if (obd && !obd->obd_stopping) {
+                rc = obd_set_info_async(obd->obd_self_export,
+                                        strlen(KEY_MGSSEC), KEY_MGSSEC,
+                                        strlen(mgssec), mgssec, NULL);
+                if (rc)
+                        GOTO(out_free, rc);
+
                 /* Re-using an existing MGC */
                 atomic_inc(&obd->u.cli.cl_mgc_refcount);
 
@@ -731,6 +739,12 @@ static int lustre_start_mgc(struct super_block *sb)
                 GOTO(out_free, rc = -ENOTCONN);
         }
 
+        rc = obd_set_info_async(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);
@@ -1212,6 +1226,9 @@ static int lustre_free_lsi(struct super_block *sb)
                 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);
@@ -1603,7 +1620,7 @@ static int server_fill_super(struct super_block *sb)
         }
 
         /* Start MGS before MGC */
-        if (IS_MGS(lsi->lsi_ldd) && !(lsi->lsi_lmd->lmd_flags & LMD_FLG_NOMGS)) {
+        if (IS_MGS(lsi->lsi_ldd) && !(lsi->lsi_lmd->lmd_flags & LMD_FLG_NOMGS)){
                 rc = server_start_mgs(sb);
                 if (rc)
                         GOTO(out_mnt, rc);
@@ -1799,6 +1816,31 @@ static int lmd_make_exclusion(struct lustre_mount_data *lmd, char *ptr)
         RETURN(rc);
 }
 
+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;
+}
+
 /* mount -v -t lustre uml1:uml2:/lustre-client /mnt/lustre */
 static int lmd_parse(char *options, struct lustre_mount_data *lmd)
 {
@@ -1846,6 +1888,11 @@ static int lmd_parse(char *options, struct lustre_mount_data *lmd)
                 } else if (strncmp(s1, "nomgs", 5) == 0) {
                         lmd->lmd_flags |= LMD_FLG_NOMGS;
                         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);
diff --git a/lustre/ost/ost_handler.c b/lustre/ost/ost_handler.c
index b49ca7a5ce..d76b2e2941 100644
--- a/lustre/ost/ost_handler.c
+++ b/lustre/ost/ost_handler.c
@@ -1440,7 +1440,8 @@ static int ost_connect_check_sptlrpc(struct ptlrpc_request *req)
                 exp->exp_sp_peer = req->rq_sp_from;
                 exp->exp_flvr = flvr;
 
-                if (exp->exp_flvr.sf_rpc != req->rq_flvr.sf_rpc) {
+                if (exp->exp_flvr.sf_rpc != SPTLRPC_FLVR_ANY &&
+                    exp->exp_flvr.sf_rpc != req->rq_flvr.sf_rpc) {
                         CERROR("unauthorized rpc flavor %x from %s, "
                                "expect %x\n", req->rq_flvr.sf_rpc,
                                libcfs_nid2str(req->rq_peer.nid),
diff --git a/lustre/ptlrpc/gss/gss_internal.h b/lustre/ptlrpc/gss/gss_internal.h
index 4725059f4c..afbb614467 100644
--- a/lustre/ptlrpc/gss/gss_internal.h
+++ b/lustre/ptlrpc/gss/gss_internal.h
@@ -106,9 +106,9 @@ enum ptlrpc_gss_proc {
 };
 
 enum ptlrpc_gss_tgt {
-        LUSTRE_GSS_TGT_MDS              = 0,
-        LUSTRE_GSS_TGT_OSS              = 1,
-        LUSTRE_GSS_TGT_MGS              = 2,
+        LUSTRE_GSS_TGT_MGS              = 0,
+        LUSTRE_GSS_TGT_MDS              = 1,
+        LUSTRE_GSS_TGT_OSS              = 2,
 };
 
 enum ptlrpc_gss_header_flags {
@@ -121,6 +121,8 @@ __u32 import_to_gss_svc(struct obd_import *imp)
 {
         const char *name = imp->imp_obd->obd_type->typ_name;
 
+        if (!strcmp(name, LUSTRE_MGC_NAME))
+                return LUSTRE_GSS_TGT_MGS;
         if (!strcmp(name, LUSTRE_MDC_NAME))
                 return LUSTRE_GSS_TGT_MDS;
         if (!strcmp(name, LUSTRE_OSC_NAME))
diff --git a/lustre/ptlrpc/sec.c b/lustre/ptlrpc/sec.c
index 87205d5b07..d268380eb6 100644
--- a/lustre/ptlrpc/sec.c
+++ b/lustre/ptlrpc/sec.c
@@ -1329,10 +1329,17 @@ int sptlrpc_import_sec_adapt(struct obd_import *imp,
 
         if (svc_ctx == NULL) {
                 struct client_obd *cliobd = &imp->imp_obd->u.cli;
-                /* normal import, determine flavor from rule set */
-                sptlrpc_conf_choose_flavor(cliobd->cl_sp_me, cliobd->cl_sp_to,
-                                           &cliobd->cl_target_uuid,
-                                           conn->c_self, &sf);
+                /*
+                 * normal import, determine flavor from rule set, except
+                 * for mgc the flavor is predetermined.
+                 */
+                if (cliobd->cl_sp_me == LUSTRE_SP_MGC)
+                        sf = cliobd->cl_flvr_mgc;
+                else 
+                        sptlrpc_conf_choose_flavor(cliobd->cl_sp_me,
+                                                   cliobd->cl_sp_to,
+                                                   &cliobd->cl_target_uuid,
+                                                   conn->c_self, &sf);
 
                 sp = imp->imp_obd->u.cli.cl_sp_me;
         } else {
@@ -1648,7 +1655,7 @@ static int flavor_allowed(struct sptlrpc_flavor *exp,
 {
         struct sptlrpc_flavor *flvr = &req->rq_flvr;
 
-        if (exp->sf_rpc == flvr->sf_rpc)
+        if (exp->sf_rpc == SPTLRPC_FLVR_ANY || exp->sf_rpc == flvr->sf_rpc)
                 return 1;
 
         if ((req->rq_ctx_init || req->rq_ctx_fini) &&
diff --git a/lustre/ptlrpc/sec_config.c b/lustre/ptlrpc/sec_config.c
index 84f926c3e3..b54a3a4fbf 100644
--- a/lustre/ptlrpc/sec_config.c
+++ b/lustre/ptlrpc/sec_config.c
@@ -200,7 +200,7 @@ static __u16 __flavors[] = {
  *  krb5i-bulkp
  *  krb5i-bulkp:sha512/arc4
  */
-static int parse_flavor(const char *str, struct sptlrpc_flavor *flvr)
+int sptlrpc_parse_flavor(const char *str, struct sptlrpc_flavor *flvr)
 {
         const char     *f;
         char           *bulk, *alg, *enc;
@@ -321,6 +321,7 @@ invalid:
         CERROR("invalid flavor string: %s\n", str);
         return -EINVAL;
 }
+EXPORT_SYMBOL(sptlrpc_parse_flavor);
 
 /****************************************
  * configure rules                      *
@@ -387,7 +388,7 @@ int sptlrpc_parse_rule(char *param, struct sptlrpc_rule *rule)
         }
 
         /* 2.1 flavor */
-        rc = parse_flavor(flavor, &rule->sr_flvr);
+        rc = sptlrpc_parse_flavor(flavor, &rule->sr_flvr);
         if (rc)
                 RETURN(-EINVAL);
 
@@ -559,11 +560,11 @@ EXPORT_SYMBOL(sptlrpc_rule_set_merge);
  * given from/to/nid, determine a matching flavor in ruleset.
  * return 1 if a match found, otherwise return 0.
  */
-static int sptlrpc_rule_set_choose(struct sptlrpc_rule_set *rset,
-                                   enum lustre_sec_part from,
-                                   enum lustre_sec_part to,
-                                   lnet_nid_t nid,
-                                   struct sptlrpc_flavor *sf)
+int sptlrpc_rule_set_choose(struct sptlrpc_rule_set *rset,
+                            enum lustre_sec_part from,
+                            enum lustre_sec_part to,
+                            lnet_nid_t nid,
+                            struct sptlrpc_flavor *sf)
 {
         struct sptlrpc_rule    *r;
         int                     n;
@@ -590,6 +591,7 @@ static int sptlrpc_rule_set_choose(struct sptlrpc_rule_set *rset,
 
         return 0;
 }
+EXPORT_SYMBOL(sptlrpc_rule_set_choose);
 
 void sptlrpc_rule_set_dump(struct sptlrpc_rule_set *rset)
 {
@@ -827,6 +829,8 @@ static int __sptlrpc_process_config(struct lustre_cfg *lcfg,
                 RETURN(-EINVAL);
         }
 
+        CDEBUG(D_SEC, "got one rule: %s.%s\n", target, param);
+
         /* parse rule to make sure the format is correct */
         if (strncmp(param, PARAM_SRPC_FLVR, sizeof(PARAM_SRPC_FLVR) - 1) != 0) {
                 CERROR("Invalid sptlrpc parameter: %s\n", param);
diff --git a/lustre/tests/sanity-gss.sh b/lustre/tests/sanity-gss.sh
index 31cfae0649..018c242188 100644
--- a/lustre/tests/sanity-gss.sh
+++ b/lustre/tests/sanity-gss.sh
@@ -59,9 +59,7 @@ cnt_all2ost=0
 cnt_all2mdt=0
 cnt_all2all=0
 DBENCH_PID=0
-PROC_CLI="srpc.info"
-# Escape "." to use lctl
-PROC_CLI=${PROC_CLI//\./\*} 
+PROC_CLI="srpc_info"
 
 # set manually
 GSS=true
@@ -230,6 +228,14 @@ flvr_cnt_mdt2ost()
     echo $cnt;
 }
 
+flvr_cnt_mgc2mgs()
+{
+    local flavor=$1
+
+    output=`do_facet client lctl get_param -n mgc.*.$PROC_CLI 2>/dev/null`
+    count_flvr "$output" $flavor
+}
+
 do_check_flavor()
 {
     local dir=$1        # from to
@@ -452,6 +458,7 @@ test_1() {
     chmod 0777 $DIR || error "chmod $DIR failed"
     # access w/o cred
     $RUNAS kdestroy
+    $RUNAS $LFS flushctx || error "can't flush ctx"
     $RUNAS touch $file && error "unexpected success"
 
     # access w/ cred
@@ -1057,6 +1064,70 @@ test_102() {
 }
 run_test 102 "survive from insanely fast flavor switch"
 
+test_150() {
+    local save_opts
+
+    # started from default flavors
+    restore_to_default_flavor
+
+    # at this time no rules has been set on mgs; mgc use null
+    # flavor connect to mgs.
+    count=`flvr_cnt_mgc2mgs null`
+    [ $count -eq 1 ] || error "$count mgc connection use null flavor"
+
+    # umount both clients
+    zconf_umount $HOSTNAME $MOUNT || return 1
+    zconf_umount $HOSTNAME $MOUNT2 || return 2
+
+    # mount client with default flavor - should succeed
+    zconf_mount $HOSTNAME $MOUNT || error "mount with default flavor should have succeeded"
+    zconf_umount $HOSTNAME $MOUNT || return 5
+
+    # mount client with conflict flavor - should fail
+    save_opts=$MOUNTOPT
+    MOUNTOPT="$MOUNTOPT,mgssec=krb5p"
+    zconf_mount $HOSTNAME $MOUNT && error "mount with conflict flavor should have failed"
+    MOUNTOPT=$save_opts
+
+    # mount client with same flavor - should succeed
+    save_opts=$MOUNTOPT
+    MOUNTOPT="$MOUNTOPT,mgssec=null"
+    zconf_mount $HOSTNAME $MOUNT || error "mount with same flavor should have succeeded"
+    zconf_umount $HOSTNAME $MOUNT || return 6
+    MOUNTOPT=$save_opts
+}
+run_test 150 "secure mgs connection: client flavor setting"
+
+test_151() {
+    local save_opts
+
+    # set mgs only accept krb5p
+    set_rule _mgs any any krb5p
+
+    # umount everything, modules still loaded
+    stopall
+
+    # mount mgs with default flavor, in current framework it means mgs+mdt1.
+    # the connection of mgc of mdt1 to mgs is expected fail.
+    DEVNAME=$(mdsdevname 1)
+    start mds1 $DEVNAME $MDS_MOUNT_OPTS && error "mount with default flavor should have failed"
+
+    # mount with unauthorized flavor should fail
+    save_opts=$MDS_MOUNT_OPTS
+    MDS_MOUNT_OPTS="$MDS_MOUNT_OPTS,mgssec=null"
+    start mds1 $DEVNAME $MDS_MOUNT_OPTS && error "mount with unauthorized flavor should have failed"
+    MDS_MOUNT_OPTS=$save_opts
+
+    # mount with designated flavor should succeed
+    save_opts=$MDS_MOUNT_OPTS
+    MDS_MOUNT_OPTS="$MDS_MOUNT_OPTS,mgssec=krb5p"
+    start mds1 $DEVNAME $MDS_MOUNT_OPTS || error "mount with designated flavor should have succeeded"
+    MDS_MOUNT_OPTS=$save_opts
+
+    stop mds1 -f
+}
+run_test 151 "secure mgs connection: server flavor control"
+
 equals_msg `basename $0`: test complete, cleaning up
 check_and_cleanup_lustre
 [ -f "$TESTSUITELOG" ] && cat $TESTSUITELOG && grep -q FAIL $TESTSUITELOG && exit 1 || true
diff --git a/lustre/utils/gss/gss_util.c b/lustre/utils/gss/gss_util.c
index b08f2f51cc..fa4838b1fc 100644
--- a/lustre/utils/gss/gss_util.c
+++ b/lustre/utils/gss/gss_util.c
@@ -90,11 +90,14 @@
 #include "lsupport.h"
 
 /* Global gssd_credentials handle */
+gss_cred_id_t  gssd_cred_mgs;
 gss_cred_id_t  gssd_cred_mds;
 gss_cred_id_t  gssd_cred_oss;
+int            gssd_cred_mgs_valid = 0;
 int            gssd_cred_mds_valid = 0;
 int            gssd_cred_oss_valid = 0;
 
+char *mgs_local_realm = NULL;
 char *mds_local_realm = NULL;
 char *oss_local_realm = NULL;
 
@@ -284,8 +287,14 @@ int gssd_acquire_cred(char *server_name, gss_cred_id_t *cred,
 	return 0;
 }
 
-int gssd_prepare_creds(int must_srv_mds, int must_srv_oss)
+int gssd_prepare_creds(int must_srv_mgs, int must_srv_mds, int must_srv_oss)
 {
+        if (gssd_acquire_cred(GSSD_SERVICE_MGS, &gssd_cred_mgs,
+                              &mgs_local_realm, &gssd_cred_mgs_valid)) {
+                if (must_srv_mgs)
+                        return -1;
+        }
+
         if (gssd_acquire_cred(GSSD_SERVICE_MDS, &gssd_cred_mds,
                               &mds_local_realm, &gssd_cred_mds_valid)) {
                 if (must_srv_mds)
@@ -298,11 +307,16 @@ int gssd_prepare_creds(int must_srv_mds, int must_srv_oss)
                         return -1;
         }
 
-        if (!gssd_cred_mds_valid && !gssd_cred_oss_valid) {
-                printerr(0, "can't obtain both mds & oss creds, exit\n");
+        if (!gssd_cred_mgs_valid &&
+	    !gssd_cred_mds_valid &&
+            !gssd_cred_oss_valid) {
+                printerr(0, "can't obtain any service creds, exit\n");
                 return -1;
         }
 
+	if (gssd_cred_mgs_valid)
+		printerr(0, "Ready to serve Lustre MGS in realm %s\n",
+			 mgs_local_realm ? mgs_local_realm : "N/A");
 	if (gssd_cred_mds_valid)
 		printerr(0, "Ready to serve Lustre MDS in realm %s\n",
 			 mds_local_realm ? mds_local_realm : "N/A");
@@ -316,6 +330,12 @@ int gssd_prepare_creds(int must_srv_mds, int must_srv_oss)
 gss_cred_id_t gssd_select_svc_cred(int lustre_svc)
 {
         switch (lustre_svc) {
+	case LUSTRE_GSS_SVC_MGS:
+		if (!gssd_cred_mgs_valid) {
+                        printerr(0, "ERROR: service cred for mgs not ready\n");
+                        return NULL;
+		}
+		return gssd_cred_mgs;
         case LUSTRE_GSS_SVC_MDS:
                 if (!gssd_cred_mds_valid) {
                         printerr(0, "ERROR: service cred for mds not ready\n");
diff --git a/lustre/utils/gss/gssd.h b/lustre/utils/gss/gssd.h
index 5f0006e0e2..5d1e8cbd24 100644
--- a/lustre/utils/gss/gssd.h
+++ b/lustre/utils/gss/gssd.h
@@ -48,6 +48,7 @@
 #define GSSD_DEFAULT_CRED_PREFIX		"krb5cc_"
 #define GSSD_DEFAULT_MACHINE_CRED_SUFFIX	"machine"
 #define GSSD_DEFAULT_KEYTAB_FILE		"/etc/krb5.keytab"
+#define GSSD_SERVICE_MGS			"lustre_mgs"
 #define GSSD_SERVICE_MDS			"lustre_mds"
 #define GSSD_SERVICE_OSS			"lustre_oss"
 #define GSSD_SERVICE_MDS_NAMELEN		10
diff --git a/lustre/utils/gss/lgss_utils.c b/lustre/utils/gss/lgss_utils.c
index db3152e8e3..e665d8500b 100644
--- a/lustre/utils/gss/lgss_utils.c
+++ b/lustre/utils/gss/lgss_utils.c
@@ -102,9 +102,9 @@
 #include "lgss_krb5_utils.h"
 
 const char *lgss_svc_str[LGSS_SVC_MAX] = {
+        [LGSS_SVC_MGS] = LGSS_SVC_MGS_STR,
         [LGSS_SVC_MDS] = LGSS_SVC_MDS_STR,
         [LGSS_SVC_OSS] = LGSS_SVC_OST_STR,
-        [LGSS_SVC_MGS] = LGSS_SVC_MGS_STR,
 };
 
 /****************************************
diff --git a/lustre/utils/gss/lgss_utils.h b/lustre/utils/gss/lgss_utils.h
index 55535910f7..bd2fa93c02 100644
--- a/lustre/utils/gss/lgss_utils.h
+++ b/lustre/utils/gss/lgss_utils.h
@@ -47,15 +47,15 @@
 
 #include <libcfs/libcfs.h>
 
+#define LGSS_SVC_MGS_STR        "lustre_mgs"
 #define LGSS_SVC_MDS_STR        "lustre_mds"
 #define LGSS_SVC_OST_STR        "lustre_oss"
-#define LGSS_SVC_MGS_STR        "lustre_mgs"
 #define LGSS_USR_ROOT_STR       "lustre_root"
 
 typedef enum {
-        LGSS_SVC_MDS    = 0,
-        LGSS_SVC_OSS    = 1,
-        LGSS_SVC_MGS    = 2,
+        LGSS_SVC_MGS    = 0,
+        LGSS_SVC_MDS    = 1,
+        LGSS_SVC_OSS    = 2,
         LGSS_SVC_MAX
 } lgss_svc_t;
 
diff --git a/lustre/utils/gss/lsupport.c b/lustre/utils/gss/lsupport.c
index 82b7b8e469..cbd7a56a1c 100644
--- a/lustre/utils/gss/lsupport.c
+++ b/lustre/utils/gss/lsupport.c
@@ -73,6 +73,7 @@
 
 const char * lustre_svc_name[] =
 {
+        [LUSTRE_GSS_SVC_MGS]    = "MGS",
         [LUSTRE_GSS_SVC_MDS]    = "MDS",
         [LUSTRE_GSS_SVC_OSS]    = "OSS",
 };
diff --git a/lustre/utils/gss/lsupport.h b/lustre/utils/gss/lsupport.h
index 2172e9ca36..fece9c49c3 100644
--- a/lustre/utils/gss/lsupport.h
+++ b/lustre/utils/gss/lsupport.h
@@ -20,8 +20,9 @@ void gssd_exit_unique(int type);
  * copied from lustre source
  */
 
-#define LUSTRE_GSS_SVC_MDS      0
-#define LUSTRE_GSS_SVC_OSS      1
+#define LUSTRE_GSS_SVC_MGS      0
+#define LUSTRE_GSS_SVC_MDS      1
+#define LUSTRE_GSS_SVC_OSS      2
 
 extern const char * lustre_svc_name[];
 
diff --git a/lustre/utils/gss/svcgssd.c b/lustre/utils/gss/svcgssd.c
index 3ab7ad2819..cebd8521ac 100644
--- a/lustre/utils/gss/svcgssd.c
+++ b/lustre/utils/gss/svcgssd.c
@@ -177,7 +177,7 @@ sig_hup(int signal)
 static void
 usage(char *progname)
 {
-	fprintf(stderr, "usage: %s [-n] [-f] [-v] [-r] [-m] [-o]\n",
+	fprintf(stderr, "usage: %s [-n] [-f] [-v] [-r] [-m] [-o] [-g]\n",
 		progname);
 	exit(1);
 }
@@ -189,11 +189,11 @@ main(int argc, char *argv[])
 	int fg = 0;
 	int verbosity = 0;
 	int opt;
-	int must_srv_mds = 0, must_srv_oss = 0;
+	int must_srv_mds = 0, must_srv_oss = 0, must_srv_mgs = 0;
 	extern char *optarg;
 	char *progname;
 
-	while ((opt = getopt(argc, argv, "fivrnp:")) != -1) {
+	while ((opt = getopt(argc, argv, "fvrnmog:")) != -1) {
 		switch (opt) {
 			case 'f':
 				fg = 1;
@@ -212,6 +212,10 @@ main(int argc, char *argv[])
 				get_creds = 1;
 				must_srv_oss = 1;
 				break;
+			case 'g':
+				get_creds = 1;
+				must_srv_mgs = 1;
+				break;
 			default:
 				usage(argv[0]);
 				break;
@@ -235,10 +239,11 @@ main(int argc, char *argv[])
 		exit(1);
 	}
   
-	if (get_creds && gssd_prepare_creds(must_srv_mds, must_srv_oss)) {
+	if (get_creds &&
+	    gssd_prepare_creds(must_srv_mgs, must_srv_mds, must_srv_oss)) {
                 printerr(0, "unable to obtain root (machine) credentials\n");
                 printerr(0, "do you have a keytab entry for "
-			    "nfs/<your.host>@<YOUR.REALM> in "
+			    "<lustre_xxs>/<your.host>@<YOUR.REALM> in "
 			    "/etc/krb5.keytab?\n");
 		exit(1);
 	}
diff --git a/lustre/utils/gss/svcgssd.h b/lustre/utils/gss/svcgssd.h
index 5283c9591b..a2eece667f 100644
--- a/lustre/utils/gss/svcgssd.h
+++ b/lustre/utils/gss/svcgssd.h
@@ -37,7 +37,7 @@
 
 int handle_nullreq(FILE *f);
 void svcgssd_run(void);
-int gssd_prepare_creds(int must_srv_mds, int must_srv_oss);
+int gssd_prepare_creds(int must_srv_mgs, int must_srv_mds, int must_srv_oss);
 gss_cred_id_t gssd_select_svc_cred(int lustre_svc);
 
 extern char *mds_local_realm;
@@ -46,6 +46,7 @@ extern char *oss_local_realm;
 #define GSSD_SERVICE_NAME	"lustre"
 
 /* XXX */
+#define GSSD_SERVICE_MGS			"lustre_mgs"
 #define GSSD_SERVICE_MDS			"lustre_mds"
 #define GSSD_SERVICE_OSS			"lustre_oss"
 #define LUSTRE_ROOT_NAME			"lustre_root"
diff --git a/lustre/utils/gss/svcgssd_proc.c b/lustre/utils/gss/svcgssd_proc.c
index 2ba8e37761..5074a0e074 100644
--- a/lustre/utils/gss/svcgssd_proc.c
+++ b/lustre/utils/gss/svcgssd_proc.c
@@ -344,8 +344,9 @@ get_ids(gss_name_t client_name, gss_OID mech, struct svc_cred *cred,
         if (host)
                 *host++ = '\0';
 
-	if (strcmp(sname, GSSD_SERVICE_OSS) == 0) {
-		printerr(0, "forbid "GSSD_SERVICE_OSS" as user name\n");
+	if (strcmp(sname, GSSD_SERVICE_OSS) == 0 ||
+	    strcmp(sname, GSSD_SERVICE_MGS) == 0) {
+		printerr(0, "forbid %s as user name\n", sname);
 		goto out_free;
 	}
 
diff --git a/lustre/utils/obd.c b/lustre/utils/obd.c
index c8e9059cd8..e7abfce901 100644
--- a/lustre/utils/obd.c
+++ b/lustre/utils/obd.c
@@ -207,9 +207,6 @@ out:
         if (rc) {
                 if (errno == ENOSYS)
                         fprintf(stderr, "Make sure cfg_device is set first.\n");
-                if (errno == EINVAL)
-                        fprintf(stderr, "cfg_device should be of the form "
-                                "'lustre-MDT0000'\n");
         }
         return rc;
 }
-- 
GitLab