Whamcloud - gitweb
LU-8851 nodemap: add uid/gid only flags to control mapping
[fs/lustre-release.git] / lustre / mgs / mgs_llog.c
index c84988b..400a3ce 100644 (file)
 
 /********************** Class functions ********************/
 
-/* Find all logs in CONFIG directory and link then into list */
-int class_dentry_readdir(const struct lu_env *env,
-                        struct mgs_device *mgs, struct list_head *log_list)
+/**
+ * Find all logs in CONFIG directory and link then into list.
+ *
+ * \param[in] env      pointer to the thread context
+ * \param[in] mgs      pointer to the mgs device
+ * \param[out] log_list        the list to hold the found llog name entry
+ *
+ * \retval             0 for success
+ * \retval             negative error number on failure
+ **/
+int class_dentry_readdir(const struct lu_env *env, struct mgs_device *mgs,
+                        struct list_head *log_list)
 {
-       struct dt_object    *dir = mgs->mgs_configs_dir;
+       struct dt_object *dir = mgs->mgs_configs_dir;
        const struct dt_it_ops *iops;
-       struct dt_it        *it;
+       struct dt_it *it;
        struct mgs_direntry *de;
-       char                *key;
-       int                  rc, key_sz;
+       char *key;
+       int rc, key_sz;
 
        INIT_LIST_HEAD(log_list);
 
@@ -126,9 +135,18 @@ next:
 
 fini:
        iops->fini(env, it);
-       if (rc)
+       if (rc) {
+               struct mgs_direntry *n;
+
                CERROR("%s: key failed when listing %s: rc = %d\n",
                       mgs->mgs_obd->obd_name, MOUNT_CONFIGS_DIR, rc);
+
+               list_for_each_entry_safe(de, n, log_list, mde_list) {
+                       list_del_init(&de->mde_list);
+                       mgs_direntry_free(de);
+               }
+       }
+
        RETURN(rc);
 }
 
@@ -217,9 +235,11 @@ static int mgs_fsdb_handler(const struct lu_env *env, struct llog_handle *llh,
                 }
                 rc = 0;
                 CDEBUG(D_MGS, "MDT index is %u\n", index);
-               set_bit(index, fsdb->fsdb_mdt_index_map);
-                fsdb->fsdb_mdt_count ++;
-        }
+               if (!test_bit(index, fsdb->fsdb_mdt_index_map)) {
+                       set_bit(index, fsdb->fsdb_mdt_index_map);
+                       fsdb->fsdb_mdt_count++;
+               }
+       }
 
        /**
         * figure out the old config. fsdb_gen = 0 means old log
@@ -261,10 +281,12 @@ static int mgs_get_fsdb_from_llog(const struct lu_env *env,
                                  struct mgs_device *mgs,
                                  struct fs_db *fsdb)
 {
-       char                            *logname;
-       struct llog_handle              *loghandle;
-       struct llog_ctxt                *ctxt;
-       struct mgs_fsdb_handler_data     d = { fsdb, 0 };
+       char *logname;
+       struct llog_handle *loghandle;
+       struct llog_ctxt *ctxt;
+       struct mgs_fsdb_handler_data d = {
+               .fsdb = fsdb,
+       };
        int rc;
 
        ENTRY;
@@ -317,98 +339,185 @@ static void mgs_free_fsdb_srpc(struct fs_db *fsdb)
         sptlrpc_rule_set_free(&fsdb->fsdb_srpc_gen);
 }
 
-struct fs_db *mgs_find_fsdb(struct mgs_device *mgs, char *fsname)
+static void mgs_unlink_fsdb(struct mgs_device *mgs, struct fs_db *fsdb)
 {
-        struct fs_db *fsdb;
+       mutex_lock(&mgs->mgs_mutex);
+       if (likely(!list_empty(&fsdb->fsdb_list))) {
+               LASSERTF(atomic_read(&fsdb->fsdb_ref) >= 2,
+                        "Invalid ref %d on %s\n",
+                        atomic_read(&fsdb->fsdb_ref),
+                        fsdb->fsdb_name);
+
+               list_del_init(&fsdb->fsdb_list);
+               /* Drop the reference on the list.*/
+               mgs_put_fsdb(mgs, fsdb);
+       }
+       mutex_unlock(&mgs->mgs_mutex);
+}
+
+/* The caller must hold mgs->mgs_mutex. */
+static inline struct fs_db *
+mgs_find_fsdb_noref(struct mgs_device *mgs, const char *fsname)
+{
+       struct fs_db *fsdb;
        struct list_head *tmp;
 
        list_for_each(tmp, &mgs->mgs_fs_db_list) {
                fsdb = list_entry(tmp, struct fs_db, fsdb_list);
-                if (strcmp(fsdb->fsdb_name, fsname) == 0)
-                        return fsdb;
-        }
-        return NULL;
+               if (strcmp(fsdb->fsdb_name, fsname) == 0)
+                       return fsdb;
+       }
+
+       return NULL;
 }
 
-/* caller must hold the mgs->mgs_fs_db_lock */
+/* The caller must hold mgs->mgs_mutex. */
+static void mgs_remove_fsdb_by_name(struct mgs_device *mgs, const char *name)
+{
+       struct fs_db *fsdb;
+
+       fsdb = mgs_find_fsdb_noref(mgs, name);
+       if (fsdb) {
+               list_del_init(&fsdb->fsdb_list);
+               /* Drop the reference on the list.*/
+               mgs_put_fsdb(mgs, fsdb);
+       }
+}
+
+/* The caller must hold mgs->mgs_mutex. */
+struct fs_db *mgs_find_fsdb(struct mgs_device *mgs, const char *fsname)
+{
+       struct fs_db *fsdb;
+
+       fsdb = mgs_find_fsdb_noref(mgs, fsname);
+       if (fsdb)
+               atomic_inc(&fsdb->fsdb_ref);
+
+       return fsdb;
+}
+
+/* The caller must hold mgs->mgs_mutex. */
 static struct fs_db *mgs_new_fsdb(const struct lu_env *env,
                                  struct mgs_device *mgs, char *fsname)
 {
-        struct fs_db *fsdb;
-        int rc;
-        ENTRY;
+       struct fs_db *fsdb;
+       int rc;
+       ENTRY;
+
+       if (strlen(fsname) >= sizeof(fsdb->fsdb_name)) {
+               CERROR("fsname %s is too long\n", fsname);
 
-        if (strlen(fsname) >= sizeof(fsdb->fsdb_name)) {
-                CERROR("fsname %s is too long\n", fsname);
                RETURN(ERR_PTR(-EINVAL));
-        }
+       }
 
-        OBD_ALLOC_PTR(fsdb);
-        if (!fsdb)
+       OBD_ALLOC_PTR(fsdb);
+       if (!fsdb)
                RETURN(ERR_PTR(-ENOMEM));
 
-        strcpy(fsdb->fsdb_name, fsname);
+       strncpy(fsdb->fsdb_name, fsname, sizeof(fsdb->fsdb_name));
        mutex_init(&fsdb->fsdb_mutex);
+       INIT_LIST_HEAD(&fsdb->fsdb_list);
        set_bit(FSDB_UDESC, &fsdb->fsdb_flags);
        fsdb->fsdb_gen = 1;
+       INIT_LIST_HEAD(&fsdb->fsdb_clients);
+       atomic_set(&fsdb->fsdb_notify_phase, 0);
+       init_waitqueue_head(&fsdb->fsdb_notify_waitq);
+       init_completion(&fsdb->fsdb_notify_comp);
 
-        if (strcmp(fsname, MGSSELF_NAME) == 0) {
+       if (strcmp(fsname, MGSSELF_NAME) == 0) {
                set_bit(FSDB_MGS_SELF, &fsdb->fsdb_flags);
                fsdb->fsdb_mgs = mgs;
-        } 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");
+               if (logname_is_barrier(fsname))
+                       goto add;
+       } else {
+               OBD_ALLOC(fsdb->fsdb_mdt_index_map, INDEX_MAP_SIZE);
+               if (!fsdb->fsdb_mdt_index_map) {
+                       CERROR("No memory for MDT index maps\n");
+
                        GOTO(err, rc = -ENOMEM);
-                }
+               }
 
-                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);
+               OBD_ALLOC(fsdb->fsdb_ost_index_map, INDEX_MAP_SIZE);
+               if (!fsdb->fsdb_ost_index_map) {
+                       CERROR("No memory for OST index maps\n");
 
-                /* initialise data for NID table */
-               mgs_ir_init_fs(env, mgs, fsdb);
+                       GOTO(err, rc = -ENOMEM);
+               }
+
+               if (logname_is_barrier(fsname))
+                       goto add;
+
+               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);
 
+               /* initialise data for NID table */
+               mgs_ir_init_fs(env, mgs, fsdb);
                lproc_mgs_add_live(mgs, fsdb);
-        }
+       }
+
+       if (!test_bit(FSDB_MGS_SELF, &fsdb->fsdb_flags) &&
+           strcmp(PARAMS_FILENAME, fsname) != 0) {
+               /* populate the db from the client llog */
+               rc = mgs_get_fsdb_from_llog(env, mgs, fsdb);
+               if (rc) {
+                       CERROR("Can't get db from client log %d\n", rc);
+
+                       GOTO(err, rc);
+               }
+       }
+
+       /* populate srpc rules from params llog */
+       rc = mgs_get_fsdb_srpc_from_llog(env, mgs, fsdb);
+       if (rc) {
+               CERROR("Can't get db from params log %d\n", rc);
+
+               GOTO(err, rc);
+       }
 
+add:
+       /* One ref is for the fsdb on the list.
+        * The other ref is for the caller. */
+       atomic_set(&fsdb->fsdb_ref, 2);
        list_add(&fsdb->fsdb_list, &mgs->mgs_fs_db_list);
 
-        RETURN(fsdb);
+       RETURN(fsdb);
+
 err:
-        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);
-        OBD_FREE_PTR(fsdb);
+       atomic_set(&fsdb->fsdb_ref, 1);
+       mgs_put_fsdb(mgs, fsdb);
+
        RETURN(ERR_PTR(rc));
 }
 
 static void mgs_free_fsdb(struct mgs_device *mgs, struct fs_db *fsdb)
 {
-       /* wait for anyone with the sem */
-       mutex_lock(&fsdb->fsdb_mutex);
+       LASSERT(list_empty(&fsdb->fsdb_list));
+
        lproc_mgs_del_live(mgs, fsdb);
-       list_del(&fsdb->fsdb_list);
-
-        /* deinitialize fsr */
-       mgs_ir_fini_fs(mgs, fsdb);
-
-        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);
-        mgs_free_fsdb_srpc(fsdb);
-       mutex_unlock(&fsdb->fsdb_mutex);
-        OBD_FREE_PTR(fsdb);
+
+       /* deinitialize fsr */
+       if (fsdb->fsdb_mgs)
+               mgs_ir_fini_fs(mgs, fsdb);
+
+       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);
+       mgs_free_fsdb_srpc(fsdb);
+       OBD_FREE_PTR(fsdb);
+}
+
+void mgs_put_fsdb(struct mgs_device *mgs, struct fs_db *fsdb)
+{
+       if (atomic_dec_and_test(&fsdb->fsdb_ref))
+               mgs_free_fsdb(mgs, fsdb);
 }
 
 int mgs_init_fsdb_list(struct mgs_device *mgs)
@@ -425,62 +534,35 @@ int mgs_cleanup_fsdb_list(struct mgs_device *mgs)
        mutex_lock(&mgs->mgs_mutex);
        list_for_each_safe(tmp, tmp2, &mgs->mgs_fs_db_list) {
                fsdb = list_entry(tmp, struct fs_db, fsdb_list);
-               mgs_free_fsdb(mgs, fsdb);
+               list_del_init(&fsdb->fsdb_list);
+               mgs_put_fsdb(mgs, fsdb);
        }
        mutex_unlock(&mgs->mgs_mutex);
        return 0;
 }
 
-int mgs_find_or_make_fsdb(const struct lu_env *env,
-                         struct mgs_device *mgs, char *name,
-                          struct fs_db **dbh)
+int mgs_find_or_make_fsdb(const struct lu_env *env, struct mgs_device *mgs,
+                         char *name, struct fs_db **dbh)
 {
-        struct fs_db *fsdb;
-        int rc = 0;
-
+       struct fs_db *fsdb;
+       int rc = 0;
        ENTRY;
+
        mutex_lock(&mgs->mgs_mutex);
        fsdb = mgs_find_fsdb(mgs, name);
-        if (fsdb) {
-               mutex_unlock(&mgs->mgs_mutex);
-                *dbh = fsdb;
-               RETURN(0);
-        }
+       if (!fsdb) {
+               fsdb = mgs_new_fsdb(env, mgs, name);
+               if (IS_ERR(fsdb))
+                       rc = PTR_ERR(fsdb);
 
-        CDEBUG(D_MGS, "Creating new db\n");
-       fsdb = mgs_new_fsdb(env, mgs, name);
-       /* lock fsdb_mutex until the db is loaded from llogs */
-       if (!IS_ERR(fsdb))
-               mutex_lock(&fsdb->fsdb_mutex);
+               CDEBUG(D_MGS, "Created new db: rc = %d\n", rc);
+       }
        mutex_unlock(&mgs->mgs_mutex);
-       if (IS_ERR(fsdb))
-               RETURN(PTR_ERR(fsdb));
-
-       if (!test_bit(FSDB_MGS_SELF, &fsdb->fsdb_flags)) {
-                /* populate the db from the client llog */
-               rc = mgs_get_fsdb_from_llog(env, mgs, fsdb);
-                if (rc) {
-                        CERROR("Can't get db from client log %d\n", rc);
-                       GOTO(out_free, rc);
-                }
-        }
-
-        /* populate srpc rules from params llog */
-       rc = mgs_get_fsdb_srpc_from_llog(env, mgs, fsdb);
-        if (rc) {
-                CERROR("Can't get db from params log %d\n", rc);
-               GOTO(out_free, rc);
-        }
-
-       mutex_unlock(&fsdb->fsdb_mutex);
-        *dbh = fsdb;
 
-        RETURN(0);
+       if (!rc)
+               *dbh = fsdb;
 
-out_free:
-       mutex_unlock(&fsdb->fsdb_mutex);
-       mgs_free_fsdb(mgs, fsdb);
-       return rc;
+       RETURN(rc);
 }
 
 /* 1 = index in use
@@ -504,18 +586,23 @@ int mgs_check_index(const struct lu_env *env,
         }
 
        if (test_bit(FSDB_LOG_EMPTY, &fsdb->fsdb_flags))
-                RETURN(-1);
+               GOTO(out, rc = -1);
 
-        if (mti->mti_flags & LDD_F_SV_TYPE_OST)
-                imap = fsdb->fsdb_ost_index_map;
-        else if (mti->mti_flags & LDD_F_SV_TYPE_MDT)
-                imap = fsdb->fsdb_mdt_index_map;
-        else
-                RETURN(-EINVAL);
+       if (mti->mti_flags & LDD_F_SV_TYPE_OST)
+               imap = fsdb->fsdb_ost_index_map;
+       else if (mti->mti_flags & LDD_F_SV_TYPE_MDT)
+               imap = fsdb->fsdb_mdt_index_map;
+       else
+               GOTO(out, rc = -EINVAL);
 
        if (test_bit(mti->mti_stripe_index, imap))
-                RETURN(1);
-        RETURN(0);
+               GOTO(out, rc = 1);
+
+       GOTO(out, rc = 0);
+
+out:
+       mgs_put_fsdb(mgs, fsdb);
+       return rc;
 }
 
 static __inline__ int next_index(void *index_map, int map_len)
@@ -529,6 +616,28 @@ static __inline__ int next_index(void *index_map, int map_len)
         return -1;
 }
 
+/* Make the mdt/ost server obd name based on the filesystem name */
+static bool server_make_name(u32 flags, u16 index, const char *fs,
+                            char *name_buf, size_t name_buf_size)
+{
+       bool invalid_flag = false;
+
+       if (flags & (LDD_F_SV_TYPE_MDT | LDD_F_SV_TYPE_OST)) {
+               if (!(flags & LDD_F_SV_ALL))
+                       snprintf(name_buf, name_buf_size, "%.8s%c%s%04x", fs,
+                               (flags & LDD_F_VIRGIN) ? ':' :
+                                       ((flags & LDD_F_WRITECONF) ? '=' : '-'),
+                               (flags & LDD_F_SV_TYPE_MDT) ? "MDT" : "OST",
+                               index);
+       } else if (flags & LDD_F_SV_TYPE_MGS) {
+               snprintf(name_buf, name_buf_size, "MGS");
+       } else {
+               CERROR("unknown server type %#x\n", flags);
+               invalid_flag = true;
+       }
+       return invalid_flag;
+}
+
 /* Return codes:
         0  newly marked as in use
         <0 err
@@ -562,8 +671,6 @@ static int mgs_set_index(const struct lu_env *env,
                 if (rc == -1)
                        GOTO(out_up, rc = -ERANGE);
                 mti->mti_stripe_index = rc;
-                if (mti->mti_flags & LDD_F_SV_TYPE_MDT)
-                        fsdb->fsdb_mdt_count ++;
         }
 
        /* the last index(0xffff) is reserved for default value. */
@@ -588,25 +695,30 @@ static int mgs_set_index(const struct lu_env *env,
                         CDEBUG(D_MGS, "Server %s updating index %d\n",
                                mti->mti_svname, mti->mti_stripe_index);
                        GOTO(out_up, rc = EALREADY);
-                }
-        }
+               }
+       } else {
+               set_bit(mti->mti_stripe_index, imap);
+               if (mti->mti_flags & LDD_F_SV_TYPE_MDT)
+                       fsdb->fsdb_mdt_count++;
+       }
 
        set_bit(mti->mti_stripe_index, imap);
        clear_bit(FSDB_LOG_EMPTY, &fsdb->fsdb_flags);
-       mutex_unlock(&fsdb->fsdb_mutex);
        if (server_make_name(mti->mti_flags & ~(LDD_F_VIRGIN | LDD_F_WRITECONF),
                             mti->mti_stripe_index, mti->mti_fsname,
-                            mti->mti_svname)) {
+                            mti->mti_svname, sizeof(mti->mti_svname))) {
                CERROR("unknown server type %#x\n", mti->mti_flags);
-               return -EINVAL;
+               GOTO(out_up, rc = -EINVAL);
        }
 
-        CDEBUG(D_MGS, "Set index for %s to %d\n", mti->mti_svname,
-               mti->mti_stripe_index);
+       CDEBUG(D_MGS, "Set index for %s to %d\n", mti->mti_svname,
+              mti->mti_stripe_index);
+
+       GOTO(out_up, rc = 0);
 
-        RETURN(0);
 out_up:
        mutex_unlock(&fsdb->fsdb_mutex);
+       mgs_put_fsdb(mgs, fsdb);
        return rc;
 }
 
@@ -1331,7 +1443,7 @@ int mgs_replace_nids(const struct lu_env *env,
        int rc;
        __u32 index;
        char *logname;
-       struct fs_db *fsdb;
+       struct fs_db *fsdb = NULL;
        unsigned int i;
        int conn_state;
        struct obd_device *mgs_obd = mgs->mgs_obd;
@@ -1386,6 +1498,9 @@ out:
        mgs_obd->obd_no_conn = conn_state;
        spin_unlock(&mgs_obd->obd_dev_lock);
 
+       if (fsdb)
+               mgs_put_fsdb(mgs, fsdb);
+
        RETURN(rc);
 }
 
@@ -3013,6 +3128,7 @@ static int mgs_write_log_quota(const struct lu_env *env, struct mgs_device *mgs,
                CDEBUG(D_MGS, "global '%s'\n", quota);
 
                if (strchr(tmp, 'u') == NULL && strchr(tmp, 'g') == NULL &&
+                   strchr(tmp, 'p') == NULL &&
                    strcmp(tmp, "none") != 0) {
                        CERROR("enable option(%s) isn't supported\n", tmp);
                        return -EINVAL;
@@ -3483,7 +3599,7 @@ static int mgs_write_log_param(const struct lu_env *env,
                                LCONSOLE_ERROR_MSG(0x144, "%s: MDC0 can not be"
                                                   " (de)activated.\n",
                                                   mti->mti_svname);
-                               GOTO(end, rc = -EINVAL);
+                               GOTO(end, rc = -EPERM);
                        }
                }
 
@@ -3938,27 +4054,37 @@ int mgs_erase_log(const struct lu_env *env, struct mgs_device *mgs, char *name)
 }
 
 /* erase all logs for the given fs */
-int mgs_erase_logs(const struct lu_env *env, struct mgs_device *mgs, char *fsname)
+int mgs_erase_logs(const struct lu_env *env, struct mgs_device *mgs,
+                  const char *fsname)
 {
-       struct fs_db *fsdb;
        struct list_head log_list;
        struct mgs_direntry *dirent, *n;
-       int rc, len = strlen(fsname);
+       char barrier_name[20] = {};
        char *suffix;
+       int count = 0;
+       int rc, len = strlen(fsname);
        ENTRY;
 
+       mutex_lock(&mgs->mgs_mutex);
+
        /* Find all the logs in the CONFIGS directory */
        rc = class_dentry_readdir(env, mgs, &log_list);
-       if (rc)
+       if (rc) {
+               mutex_unlock(&mgs->mgs_mutex);
                RETURN(rc);
+       }
 
-       mutex_lock(&mgs->mgs_mutex);
-
-        /* Delete the fs db */
-       fsdb = mgs_find_fsdb(mgs, fsname);
-        if (fsdb)
-               mgs_free_fsdb(mgs, fsdb);
+       if (list_empty(&log_list)) {
+               mutex_unlock(&mgs->mgs_mutex);
+               RETURN(-ENOENT);
+       }
 
+       snprintf(barrier_name, sizeof(barrier_name) - 1, "%s-%s",
+                fsname, BARRIER_FILENAME);
+       /* Delete the barrier fsdb */
+       mgs_remove_fsdb_by_name(mgs, barrier_name);
+       /* Delete the fs db */
+       mgs_remove_fsdb_by_name(mgs, fsname);
        mutex_unlock(&mgs->mgs_mutex);
 
        list_for_each_entry_safe(dirent, n, &log_list, mde_list) {
@@ -3970,12 +4096,16 @@ int mgs_erase_logs(const struct lu_env *env, struct mgs_device *mgs, char *fsnam
                                CDEBUG(D_MGS, "Removing log %s\n",
                                       dirent->mde_name);
                                mgs_erase_log(env, mgs, dirent->mde_name);
+                               count++;
                        }
                }
                mgs_direntry_free(dirent);
        }
 
-        RETURN(rc);
+       if (count == 0)
+               rc = -ENOENT;
+
+       RETURN(rc);
 }
 
 /* list all logs for the given fs */
@@ -4000,7 +4130,7 @@ int mgs_list_logs(const struct lu_env *env, struct mgs_device *mgs,
                list_del_init(&dirent->mde_list);
                suffix = strrchr(dirent->mde_name, '-');
                if (suffix != NULL) {
-                       l = snprintf(out, remains, "config log: $%s\n",
+                       l = snprintf(out, remains, "config_log: %s\n",
                                     dirent->mde_name);
                        out += l;
                        remains -= l;
@@ -4012,6 +4142,546 @@ int mgs_list_logs(const struct lu_env *env, struct mgs_device *mgs,
        RETURN(rc);
 }
 
+struct mgs_lcfg_fork_data {
+       struct lustre_cfg_bufs   mlfd_bufs;
+       struct mgs_device       *mlfd_mgs;
+       struct llog_handle      *mlfd_llh;
+       const char              *mlfd_oldname;
+       const char              *mlfd_newname;
+       char                     mlfd_data[0];
+};
+
+static bool contain_valid_fsname(char *buf, const char *fsname,
+                                int buflen, int namelen)
+{
+       if (buflen < namelen)
+               return false;
+
+       if (memcmp(buf, fsname, namelen) != 0)
+               return false;
+
+       if (buf[namelen] != '\0' && buf[namelen] != '-')
+               return false;
+
+       return true;
+}
+
+static int mgs_lcfg_fork_handler(const struct lu_env *env,
+                                struct llog_handle *o_llh,
+                                struct llog_rec_hdr *o_rec, void *data)
+{
+       struct mgs_lcfg_fork_data *mlfd = data;
+       struct lustre_cfg_bufs *n_bufs = &mlfd->mlfd_bufs;
+       struct lustre_cfg *o_lcfg = (struct lustre_cfg *)(o_rec + 1);
+       struct llog_cfg_rec *lcr;
+       char *o_buf;
+       char *n_buf = mlfd->mlfd_data;
+       int o_buflen;
+       int o_namelen = strlen(mlfd->mlfd_oldname);
+       int n_namelen = strlen(mlfd->mlfd_newname);
+       int diff = n_namelen - o_namelen;
+       __u32 cmd = o_lcfg->lcfg_command;
+       __u32 cnt = o_lcfg->lcfg_bufcount;
+       int rc;
+       int i;
+       ENTRY;
+
+       /* buf[0] */
+       o_buf = lustre_cfg_buf(o_lcfg, 0);
+       o_buflen = o_lcfg->lcfg_buflens[0];
+       if (contain_valid_fsname(o_buf, mlfd->mlfd_oldname, o_buflen,
+                                o_namelen)) {
+               memcpy(n_buf, mlfd->mlfd_newname, n_namelen);
+               memcpy(n_buf + n_namelen, o_buf + o_namelen,
+                      o_buflen - o_namelen);
+               lustre_cfg_bufs_reset(n_bufs, n_buf);
+               n_buf += cfs_size_round(o_buflen + diff);
+       } else {
+               lustre_cfg_bufs_reset(n_bufs, o_buflen != 0 ? o_buf : NULL);
+       }
+
+       switch (cmd) {
+       case LCFG_MARKER: {
+               struct cfg_marker *o_marker;
+               struct cfg_marker *n_marker;
+               int tgt_namelen;
+
+               if (cnt != 2) {
+                       CDEBUG(D_MGS, "Unknown cfg marker entry with %d "
+                              "buffers\n", cnt);
+                       RETURN(-EINVAL);
+               }
+
+               /* buf[1] is marker */
+               o_buf = lustre_cfg_buf(o_lcfg, 1);
+               o_buflen = o_lcfg->lcfg_buflens[1];
+               o_marker = (struct cfg_marker *)o_buf;
+               if (!contain_valid_fsname(o_marker->cm_tgtname,
+                                         mlfd->mlfd_oldname,
+                                         sizeof(o_marker->cm_tgtname),
+                                         o_namelen)) {
+                       lustre_cfg_bufs_set(n_bufs, 1, o_marker,
+                                           sizeof(*o_marker));
+                       break;
+               }
+
+               n_marker = (struct cfg_marker *)n_buf;
+               *n_marker = *o_marker;
+               memcpy(n_marker->cm_tgtname, mlfd->mlfd_newname, n_namelen);
+               tgt_namelen = strlen(o_marker->cm_tgtname);
+               if (tgt_namelen > o_namelen)
+                       memcpy(n_marker->cm_tgtname + n_namelen,
+                              o_marker->cm_tgtname + o_namelen,
+                              tgt_namelen - o_namelen);
+               n_marker->cm_tgtname[tgt_namelen + diff] = '\0';
+               lustre_cfg_bufs_set(n_bufs, 1, n_marker, sizeof(*n_marker));
+               break;
+       }
+       case LCFG_PARAM:
+       case LCFG_SET_PARAM: {
+               for (i = 1; i < cnt; i++)
+                       /* buf[i] is the param value, reuse it directly */
+                       lustre_cfg_bufs_set(n_bufs, i,
+                                           lustre_cfg_buf(o_lcfg, i),
+                                           o_lcfg->lcfg_buflens[i]);
+               break;
+       }
+       case LCFG_POOL_NEW:
+       case LCFG_POOL_ADD:
+       case LCFG_POOL_REM:
+       case LCFG_POOL_DEL: {
+               if (cnt < 3 || cnt > 4) {
+                       CDEBUG(D_MGS, "Unknown cfg pool (%x) entry with %d "
+                              "buffers\n", cmd, cnt);
+                       RETURN(-EINVAL);
+               }
+
+               /* buf[1] is fsname */
+               o_buf = lustre_cfg_buf(o_lcfg, 1);
+               o_buflen = o_lcfg->lcfg_buflens[1];
+               memcpy(n_buf, mlfd->mlfd_newname, n_namelen);
+               memcpy(n_buf + n_namelen, o_buf + o_namelen,
+                      o_buflen - o_namelen);
+               lustre_cfg_bufs_set(n_bufs, 1, n_buf, o_buflen + diff);
+               n_buf += cfs_size_round(o_buflen + diff);
+
+               /* buf[2] is the pool name, reuse it directly */
+               lustre_cfg_bufs_set(n_bufs, 2, lustre_cfg_buf(o_lcfg, 2),
+                                   o_lcfg->lcfg_buflens[2]);
+
+               if (cnt == 3)
+                       break;
+
+               /* buf[3] is ostname */
+               o_buf = lustre_cfg_buf(o_lcfg, 3);
+               o_buflen = o_lcfg->lcfg_buflens[3];
+               memcpy(n_buf, mlfd->mlfd_newname, n_namelen);
+               memcpy(n_buf + n_namelen, o_buf + o_namelen,
+                      o_buflen - o_namelen);
+               lustre_cfg_bufs_set(n_bufs, 3, n_buf, o_buflen + diff);
+               break;
+       }
+       case LCFG_SETUP: {
+               if (cnt == 2) {
+                       o_buflen = o_lcfg->lcfg_buflens[1];
+                       if (o_buflen == sizeof(struct lov_desc) ||
+                           o_buflen == sizeof(struct lmv_desc)) {
+                               char *o_uuid;
+                               char *n_uuid;
+                               int uuid_len;
+
+                               /* buf[1] */
+                               o_buf = lustre_cfg_buf(o_lcfg, 1);
+                               if (o_buflen == sizeof(struct lov_desc)) {
+                                       struct lov_desc *o_desc =
+                                               (struct lov_desc *)o_buf;
+                                       struct lov_desc *n_desc =
+                                               (struct lov_desc *)n_buf;
+
+                                       *n_desc = *o_desc;
+                                       o_uuid = o_desc->ld_uuid.uuid;
+                                       n_uuid = n_desc->ld_uuid.uuid;
+                                       uuid_len = sizeof(o_desc->ld_uuid.uuid);
+                               } else {
+                                       struct lmv_desc *o_desc =
+                                               (struct lmv_desc *)o_buf;
+                                       struct lmv_desc *n_desc =
+                                               (struct lmv_desc *)n_buf;
+
+                                       *n_desc = *o_desc;
+                                       o_uuid = o_desc->ld_uuid.uuid;
+                                       n_uuid = n_desc->ld_uuid.uuid;
+                                       uuid_len = sizeof(o_desc->ld_uuid.uuid);
+                               }
+
+                               if (unlikely(!contain_valid_fsname(o_uuid,
+                                               mlfd->mlfd_oldname, uuid_len,
+                                               o_namelen))) {
+                                       lustre_cfg_bufs_set(n_bufs, 1, o_buf,
+                                                           o_buflen);
+                                       break;
+                               }
+
+                               memcpy(n_uuid, mlfd->mlfd_newname, n_namelen);
+                               uuid_len = strlen(o_uuid);
+                               if (uuid_len > o_namelen)
+                                       memcpy(n_uuid + n_namelen,
+                                              o_uuid + o_namelen,
+                                              uuid_len - o_namelen);
+                               n_uuid[uuid_len + diff] = '\0';
+                               lustre_cfg_bufs_set(n_bufs, 1, n_buf, o_buflen);
+                               break;
+                       } /* else case fall through */
+               } /* else case fall through */
+       }
+       default: {
+               for (i = 1; i < cnt; i++) {
+                       o_buflen = o_lcfg->lcfg_buflens[i];
+                       if (o_buflen == 0)
+                               continue;
+
+                       o_buf = lustre_cfg_buf(o_lcfg, i);
+                       if (!contain_valid_fsname(o_buf, mlfd->mlfd_oldname,
+                                                 o_buflen, o_namelen)) {
+                               lustre_cfg_bufs_set(n_bufs, i, o_buf, o_buflen);
+                               continue;
+                       }
+
+                       memcpy(n_buf, mlfd->mlfd_newname, n_namelen);
+                       if (o_buflen == o_namelen) {
+                               lustre_cfg_bufs_set(n_bufs, i, n_buf,
+                                                   n_namelen);
+                               n_buf += cfs_size_round(n_namelen);
+                               continue;
+                       }
+
+                       memcpy(n_buf + n_namelen, o_buf + o_namelen,
+                              o_buflen - o_namelen);
+                       lustre_cfg_bufs_set(n_bufs, i, n_buf, o_buflen + diff);
+                       n_buf += cfs_size_round(o_buflen + diff);
+               }
+               break;
+       }
+       }
+
+       lcr = lustre_cfg_rec_new(cmd, n_bufs);
+       if (!lcr)
+               RETURN(-ENOMEM);
+
+       lcr->lcr_cfg = *o_lcfg;
+       rc = llog_write(env, mlfd->mlfd_llh, &lcr->lcr_hdr, LLOG_NEXT_IDX);
+       lustre_cfg_rec_free(lcr);
+
+       RETURN(rc);
+}
+
+static int mgs_lcfg_fork_one(const struct lu_env *env, struct mgs_device *mgs,
+                            struct mgs_direntry *mde, const char *oldname,
+                            const char *newname)
+{
+       struct llog_handle *old_llh = NULL;
+       struct llog_handle *new_llh = NULL;
+       struct llog_ctxt *ctxt = NULL;
+       struct mgs_lcfg_fork_data *mlfd = NULL;
+       char *name_buf = NULL;
+       int name_buflen;
+       int old_namelen = strlen(oldname);
+       int new_namelen = strlen(newname);
+       int rc;
+       ENTRY;
+
+       name_buflen = mde->mde_len + new_namelen - old_namelen;
+       OBD_ALLOC(name_buf, name_buflen);
+       if (!name_buf)
+               RETURN(-ENOMEM);
+
+       memcpy(name_buf, newname, new_namelen);
+       memcpy(name_buf + new_namelen, mde->mde_name + old_namelen,
+              mde->mde_len - old_namelen);
+
+       CDEBUG(D_MGS, "Fork the config-log from %s to %s\n",
+              mde->mde_name, name_buf);
+
+       ctxt = llog_get_context(mgs->mgs_obd, LLOG_CONFIG_ORIG_CTXT);
+       LASSERT(ctxt);
+
+       rc = llog_open_create(env, ctxt, &new_llh, NULL, name_buf);
+       if (rc)
+               GOTO(out, rc);
+
+       rc = llog_init_handle(env, new_llh, LLOG_F_IS_PLAIN, NULL);
+       if (rc)
+               GOTO(out, rc);
+
+       if (unlikely(mgs_log_is_empty(env, mgs, mde->mde_name)))
+               GOTO(out, rc = 0);
+
+       rc = llog_open(env, ctxt, &old_llh, NULL, mde->mde_name,
+                      LLOG_OPEN_EXISTS);
+       if (rc)
+               GOTO(out, rc);
+
+       rc = llog_init_handle(env, old_llh, LLOG_F_IS_PLAIN, NULL);
+       if (rc)
+               GOTO(out, rc);
+
+       new_llh->lgh_hdr->llh_tgtuuid = old_llh->lgh_hdr->llh_tgtuuid;
+
+       OBD_ALLOC(mlfd, LLOG_MIN_CHUNK_SIZE);
+       if (!mlfd)
+               GOTO(out, rc = -ENOMEM);
+
+       mlfd->mlfd_mgs = mgs;
+       mlfd->mlfd_llh = new_llh;
+       mlfd->mlfd_oldname = oldname;
+       mlfd->mlfd_newname = newname;
+
+       rc = llog_process(env, old_llh, mgs_lcfg_fork_handler, mlfd, NULL);
+       OBD_FREE(mlfd, LLOG_MIN_CHUNK_SIZE);
+
+       GOTO(out, rc);
+
+out:
+       if (old_llh)
+               llog_close(env, old_llh);
+       if (new_llh)
+               llog_close(env, new_llh);
+       if (name_buf)
+               OBD_FREE(name_buf, name_buflen);
+       if (ctxt)
+               llog_ctxt_put(ctxt);
+
+       return rc;
+}
+
+int mgs_lcfg_fork(const struct lu_env *env, struct mgs_device *mgs,
+                 const char *oldname, const char *newname)
+{
+       struct list_head log_list;
+       struct mgs_direntry *dirent, *n;
+       int olen = strlen(oldname);
+       int nlen = strlen(newname);
+       int count = 0;
+       int rc = 0;
+       ENTRY;
+
+       if (unlikely(!oldname || oldname[0] == '\0' ||
+                    !newname || newname[0] == '\0'))
+               RETURN(-EINVAL);
+
+       if (strcmp(oldname, newname) == 0)
+               RETURN(-EINVAL);
+
+       /* lock it to prevent fork/erase/register in parallel. */
+       mutex_lock(&mgs->mgs_mutex);
+
+       rc = class_dentry_readdir(env, mgs, &log_list);
+       if (rc) {
+               mutex_unlock(&mgs->mgs_mutex);
+               RETURN(rc);
+       }
+
+       if (list_empty(&log_list)) {
+               mutex_unlock(&mgs->mgs_mutex);
+               RETURN(-ENOENT);
+       }
+
+       list_for_each_entry_safe(dirent, n, &log_list, mde_list) {
+               char *ptr;
+
+               ptr = strrchr(dirent->mde_name, '-');
+               if (ptr) {
+                       int tlen = ptr - dirent->mde_name;
+
+                       if (tlen == nlen &&
+                           strncmp(newname, dirent->mde_name, tlen) == 0)
+                               GOTO(out, rc = -EEXIST);
+
+                       if (tlen == olen &&
+                           strncmp(oldname, dirent->mde_name, tlen) == 0)
+                               continue;
+               }
+
+               list_del_init(&dirent->mde_list);
+               mgs_direntry_free(dirent);
+       }
+
+       if (list_empty(&log_list)) {
+               mutex_unlock(&mgs->mgs_mutex);
+               RETURN(-ENOENT);
+       }
+
+       list_for_each_entry(dirent, &log_list, mde_list) {
+               rc = mgs_lcfg_fork_one(env, mgs, dirent, oldname, newname);
+               if (rc)
+                       break;
+
+               count++;
+       }
+
+out:
+       mutex_unlock(&mgs->mgs_mutex);
+
+       list_for_each_entry_safe(dirent, n, &log_list, mde_list) {
+               list_del_init(&dirent->mde_list);
+               mgs_direntry_free(dirent);
+       }
+
+       if (rc && count > 0)
+               mgs_erase_logs(env, mgs, newname);
+
+       RETURN(rc);
+}
+
+int mgs_lcfg_erase(const struct lu_env *env, struct mgs_device *mgs,
+                  const char *fsname)
+{
+       int rc;
+       ENTRY;
+
+       if (unlikely(!fsname || fsname[0] == '\0'))
+               RETURN(-EINVAL);
+
+       rc = mgs_erase_logs(env, mgs, fsname);
+
+       RETURN(rc);
+}
+
+static int mgs_xattr_del(const struct lu_env *env, struct dt_object *obj)
+{
+       struct dt_device *dev;
+       struct thandle *th = NULL;
+       int rc = 0;
+
+       ENTRY;
+
+       dev = container_of0(obj->do_lu.lo_dev, struct dt_device, dd_lu_dev);
+       th = dt_trans_create(env, dev);
+       if (IS_ERR(th))
+               RETURN(PTR_ERR(th));
+
+       rc = dt_declare_xattr_del(env, obj, XATTR_TARGET_RENAME, th);
+       if (rc)
+               GOTO(stop, rc);
+
+       rc = dt_trans_start_local(env, dev, th);
+       if (rc)
+               GOTO(stop, rc);
+
+       dt_write_lock(env, obj, 0);
+       rc = dt_xattr_del(env, obj, XATTR_TARGET_RENAME, th);
+
+       GOTO(unlock, rc);
+
+unlock:
+       dt_write_unlock(env, obj);
+
+stop:
+       dt_trans_stop(env, dev, th);
+
+       return rc;
+}
+
+int mgs_lcfg_rename(const struct lu_env *env, struct mgs_device *mgs)
+{
+       struct list_head log_list;
+       struct mgs_direntry *dirent, *n;
+       char fsname[16];
+       struct lu_buf buf = {
+               .lb_buf = fsname,
+               .lb_len = sizeof(fsname)
+       };
+       int rc = 0;
+
+       ENTRY;
+
+       rc = class_dentry_readdir(env, mgs, &log_list);
+       if (rc)
+               RETURN(rc);
+
+       if (list_empty(&log_list))
+               RETURN(0);
+
+       list_for_each_entry_safe(dirent, n, &log_list, mde_list) {
+               struct dt_object *o = NULL;
+               char oldname[16];
+               char *ptr;
+               int len;
+
+               list_del_init(&dirent->mde_list);
+               ptr = strrchr(dirent->mde_name, '-');
+               if (!ptr)
+                       goto next;
+
+               len = ptr - dirent->mde_name;
+               if (unlikely(len >= sizeof(oldname))) {
+                       CDEBUG(D_MGS, "Skip invalid configuration file %s\n",
+                              dirent->mde_name);
+                       goto next;
+               }
+
+               o = local_file_find(env, mgs->mgs_los, mgs->mgs_configs_dir,
+                                   dirent->mde_name);
+               if (IS_ERR(o)) {
+                       rc = PTR_ERR(o);
+                       CDEBUG(D_MGS, "Fail to locate file %s: rc = %d\n",
+                              dirent->mde_name, rc);
+                       goto next;
+               }
+
+               rc = dt_xattr_get(env, o, &buf, XATTR_TARGET_RENAME);
+               if (rc < 0) {
+                       if (rc == -ENODATA)
+                               rc = 0;
+                       else
+                               CDEBUG(D_MGS,
+                                      "Fail to get EA for %s: rc = %d\n",
+                                      dirent->mde_name, rc);
+                       goto next;
+               }
+
+               if (unlikely(rc == len &&
+                            memcmp(fsname, dirent->mde_name, len) == 0)) {
+                       /* The new fsname is the same as the old one. */
+                       rc = mgs_xattr_del(env, o);
+                       goto next;
+               }
+
+               memcpy(oldname, dirent->mde_name, len);
+               oldname[len] = '\0';
+               fsname[rc] = '\0';
+               rc = mgs_lcfg_fork_one(env, mgs, dirent, oldname, fsname);
+               if (rc && rc != -EEXIST) {
+                       CDEBUG(D_MGS, "Fail to fork %s: rc = %d\n",
+                              dirent->mde_name, rc);
+                       goto next;
+               }
+
+               rc = mgs_erase_log(env, mgs, dirent->mde_name);
+               if (rc) {
+                       CDEBUG(D_MGS, "Fail to erase old %s: rc = %d\n",
+                              dirent->mde_name, rc);
+                       /* keep it there if failed to remove it. */
+                       rc = 0;
+               }
+
+next:
+               if (o && !IS_ERR(o))
+                       lu_object_put(env, &o->do_lu);
+
+               mgs_direntry_free(dirent);
+               if (rc)
+                       break;
+       }
+
+       list_for_each_entry_safe(dirent, n, &log_list, mde_list) {
+               list_del_init(&dirent->mde_list);
+               mgs_direntry_free(dirent);
+       }
+
+       RETURN(rc);
+}
+
 /* from llog_swab */
 static void print_lustre_cfg(struct lustre_cfg *lcfg)
 {
@@ -4038,33 +4708,36 @@ static void print_lustre_cfg(struct lustre_cfg *lcfg)
 
 /* Setup _mgs fsdb and log
  */
-int mgs__mgs_fsdb_setup(const struct lu_env *env, struct mgs_device *mgs,
-                         struct fs_db *fsdb)
+int mgs__mgs_fsdb_setup(const struct lu_env *env, struct mgs_device *mgs)
 {
-       int                     rc;
+       struct fs_db *fsdb = NULL;
+       int rc;
        ENTRY;
 
        rc = mgs_find_or_make_fsdb(env, mgs, MGSSELF_NAME, &fsdb);
+       if (!rc)
+               mgs_put_fsdb(mgs, fsdb);
 
        RETURN(rc);
 }
 
 /* Setup params fsdb and log
  */
-int mgs_params_fsdb_setup(const struct lu_env *env, struct mgs_device *mgs,
-                         struct fs_db *fsdb)
+int mgs_params_fsdb_setup(const struct lu_env *env, struct mgs_device *mgs)
 {
-       struct llog_handle      *params_llh = NULL;
-       int                     rc;
+       struct fs_db *fsdb = NULL;
+       struct llog_handle *params_llh = NULL;
+       int rc;
        ENTRY;
 
        rc = mgs_find_or_make_fsdb(env, mgs, PARAMS_FILENAME, &fsdb);
-       if (fsdb != NULL) {
+       if (!rc) {
                mutex_lock(&fsdb->fsdb_mutex);
                rc = record_start_log(env, mgs, &params_llh, PARAMS_FILENAME);
-               if (rc == 0)
+               if (!rc)
                        rc = record_end_log(env, &params_llh);
                mutex_unlock(&fsdb->fsdb_mutex);
+               mgs_put_fsdb(mgs, fsdb);
        }
 
        RETURN(rc);
@@ -4074,7 +4747,10 @@ int mgs_params_fsdb_setup(const struct lu_env *env, struct mgs_device *mgs,
  */
 int mgs_params_fsdb_cleanup(const struct lu_env *env, struct mgs_device *mgs)
 {
-       return mgs_erase_logs(env, mgs, PARAMS_FILENAME);
+       int rc;
+
+       rc = mgs_erase_logs(env, mgs, PARAMS_FILENAME);
+       return rc == -ENOENT ? 0 : rc;
 }
 
 /* Set a permanent (config log) param for a target or fs
@@ -4084,13 +4760,14 @@ int mgs_params_fsdb_cleanup(const struct lu_env *env, struct mgs_device *mgs)
 int mgs_setparam(const struct lu_env *env, struct mgs_device *mgs,
                 struct lustre_cfg *lcfg, char *fsname)
 {
-       struct fs_db *fsdb;
-       struct mgs_target_info *mti;
-        char *devname, *param;
+       struct fs_db *fsdb = NULL;
+       struct mgs_target_info *mti = NULL;
+       char *devname, *param;
        char *ptr;
        const char *tmp;
        __u32 index;
        int rc = 0;
+       bool free = false;
        ENTRY;
 
         print_lustre_cfg(lcfg);
@@ -4134,16 +4811,16 @@ int mgs_setparam(const struct lu_env *env, struct mgs_device *mgs,
        if (lcfg->lcfg_command != LCFG_SET_PARAM &&
            !test_bit(FSDB_MGS_SELF, &fsdb->fsdb_flags) &&
            test_bit(FSDB_LOG_EMPTY, &fsdb->fsdb_flags)) {
-                CERROR("No filesystem targets for %s.  cfg_device from lctl "
-                       "is '%s'\n", fsname, devname);
-               mgs_free_fsdb(mgs, fsdb);
-                RETURN(-EINVAL);
-        }
+               CERROR("No filesystem targets for %s. cfg_device from lctl "
+                      "is '%s'\n", fsname, devname);
+               free = true;
+               GOTO(out, rc = -EINVAL);
+       }
 
-        /* Create a fake mti to hold everything */
-        OBD_ALLOC_PTR(mti);
-        if (!mti)
-                GOTO(out, rc = -ENOMEM);
+       /* Create a fake mti to hold everything */
+       OBD_ALLOC_PTR(mti);
+       if (!mti)
+               GOTO(out, rc = -ENOMEM);
        if (strlcpy(mti->mti_fsname, fsname, sizeof(mti->mti_fsname))
            >= sizeof(mti->mti_fsname))
                GOTO(out, rc = -E2BIG);
@@ -4160,7 +4837,7 @@ int mgs_setparam(const struct lu_env *env, struct mgs_device *mgs,
         else
                 /* Strip -osc or -mdc suffix from svname */
                 if (server_make_name(rc, mti->mti_stripe_index, mti->mti_fsname,
-                                     mti->mti_svname))
+                                    mti->mti_svname, sizeof(mti->mti_svname)))
                         GOTO(out, rc = -EINVAL);
        /*
         * Revoke lock so everyone updates.  Should be alright if
@@ -4183,8 +4860,16 @@ int mgs_setparam(const struct lu_env *env, struct mgs_device *mgs,
        }
 
 out:
-        OBD_FREE_PTR(mti);
-        RETURN(rc);
+       if (mti)
+               OBD_FREE_PTR(mti);
+
+       if (fsdb) {
+               if (free)
+                       mgs_unlink_fsdb(mgs, fsdb);
+               mgs_put_fsdb(mgs, fsdb);
+       }
+
+       RETURN(rc);
 }
 
 static int mgs_write_log_pool(const struct lu_env *env,
@@ -4251,6 +4936,19 @@ int mgs_nodemap_cmd(const struct lu_env *env, struct mgs_device *mgs,
                bool_switch = simple_strtoul(param, NULL, 10);
                rc = nodemap_set_deny_unknown(nodemap_name, bool_switch);
                break;
+       case LCFG_NODEMAP_MAP_MODE:
+               if (strcmp("both", param) == 0)
+                       rc = nodemap_set_mapping_mode(nodemap_name,
+                                                     NODEMAP_MAP_BOTH);
+               else if (strcmp("uid_only", param) == 0)
+                       rc = nodemap_set_mapping_mode(nodemap_name,
+                                                     NODEMAP_MAP_UID_ONLY);
+               else if (strcmp("gid_only", param) == 0)
+                       rc = nodemap_set_mapping_mode(nodemap_name,
+                                                     NODEMAP_MAP_GID_ONLY);
+               else
+                       rc = -EINVAL;
+               break;
        case LCFG_NODEMAP_TRUSTED:
                bool_switch = simple_strtoul(param, NULL, 10);
                rc = nodemap_set_trust_client_ids(nodemap_name, bool_switch);
@@ -4308,18 +5006,20 @@ int mgs_pool_cmd(const struct lu_env *env, struct mgs_device *mgs,
         int label_sz;
         struct mgs_target_info *mti = NULL;
        bool checked = false;
-        int rc, i;
-        ENTRY;
+       bool locked = false;
+       bool free = false;
+       int rc, i;
+       ENTRY;
 
        rc = mgs_find_or_make_fsdb(env, mgs, fsname, &fsdb);
-        if (rc) {
-                CERROR("Can't get db for %s\n", fsname);
-                RETURN(rc);
-        }
+       if (rc) {
+               CERROR("Can't get db for %s\n", fsname);
+               RETURN(rc);
+       }
        if (test_bit(FSDB_LOG_EMPTY, &fsdb->fsdb_flags)) {
-                CERROR("%s is not defined\n", fsname);
-               mgs_free_fsdb(mgs, fsdb);
-                RETURN(-EINVAL);
+               CERROR("%s is not defined\n", fsname);
+               free = true;
+               GOTO(out_fsdb, rc = -EINVAL);
         }
 
         label_sz = 10 + strlen(fsname) + strlen(poolname);
@@ -4336,8 +5036,8 @@ int mgs_pool_cmd(const struct lu_env *env, struct mgs_device *mgs,
         }
 
         OBD_ALLOC(label, label_sz);
-        if (label == NULL)
-               RETURN(-ENOMEM);
+       if (!label)
+               GOTO(out_fsdb, rc = -ENOMEM);
 
         switch(cmd) {
        case LCFG_POOL_NEW:
@@ -4376,15 +5076,14 @@ int mgs_pool_cmd(const struct lu_env *env, struct mgs_device *mgs,
        strncpy(mti->mti_svname, "lov pool", sizeof(mti->mti_svname));
 
        mutex_lock(&fsdb->fsdb_mutex);
-        /* write pool def to all MDT logs */
-        for (i = 0; i < INDEX_MAP_SIZE * 8; i++) {
+       locked = true;
+       /* write pool def to all MDT logs */
+       for (i = 0; i < INDEX_MAP_SIZE * 8; i++) {
                if (test_bit(i,  fsdb->fsdb_mdt_index_map)) {
                        rc = name_create_mdt_and_lov(&logname, &lovname,
                                                     fsdb, i);
-                       if (rc) {
-                               mutex_unlock(&fsdb->fsdb_mutex);
+                       if (rc)
                                GOTO(out_mti, rc);
-                       }
 
                        if (!checked && (canceled_label == NULL)) {
                                rc = mgs_check_marker(env, mgs, fsdb, mti,
@@ -4392,7 +5091,6 @@ int mgs_pool_cmd(const struct lu_env *env, struct mgs_device *mgs,
                                if (rc) {
                                        name_destroy(&logname);
                                        name_destroy(&lovname);
-                                       mutex_unlock(&fsdb->fsdb_mutex);
                                        GOTO(out_mti,
                                                rc = (rc == LLOG_PROC_BREAK ?
                                                        -EEXIST : rc));
@@ -4409,27 +5107,22 @@ int mgs_pool_cmd(const struct lu_env *env, struct mgs_device *mgs,
                                                        fsdb, lovname, cmd,
                                                        fsname, poolname,
                                                        ostname, label);
-                        name_destroy(&logname);
-                        name_destroy(&lovname);
-                       if (rc) {
-                               mutex_unlock(&fsdb->fsdb_mutex);
+                       name_destroy(&logname);
+                       name_destroy(&lovname);
+                       if (rc)
                                GOTO(out_mti, rc);
-                       }
-                }
-        }
+               }
+       }
 
        rc = name_create(&logname, fsname, "-client");
-       if (rc) {
-               mutex_unlock(&fsdb->fsdb_mutex);
+       if (rc)
                GOTO(out_mti, rc);
-       }
 
        if (!checked && (canceled_label == NULL)) {
                rc = mgs_check_marker(env, mgs, fsdb, mti, logname,
                                fsdb->fsdb_clilov, label);
                if (rc) {
                        name_destroy(&logname);
-                       mutex_unlock(&fsdb->fsdb_mutex);
                        GOTO(out_mti, rc = (rc == LLOG_PROC_BREAK ?
                                -EEXIST : rc));
                }
@@ -4438,7 +5131,6 @@ int mgs_pool_cmd(const struct lu_env *env, struct mgs_device *mgs,
                rc = mgs_modify(env, mgs, fsdb, mti, logname,
                                fsdb->fsdb_clilov, canceled_label, CM_SKIP);
                if (rc < 0) {
-                       mutex_unlock(&fsdb->fsdb_mutex);
                        name_destroy(&logname);
                        GOTO(out_mti, rc);
                }
@@ -4447,18 +5139,27 @@ int mgs_pool_cmd(const struct lu_env *env, struct mgs_device *mgs,
        rc = mgs_write_log_pool(env, mgs, logname, fsdb, fsdb->fsdb_clilov,
                                cmd, fsname, poolname, ostname, label);
        mutex_unlock(&fsdb->fsdb_mutex);
+       locked = false;
        name_destroy(&logname);
-        /* request for update */
+       /* request for update */
        mgs_revoke_lock(mgs, fsdb, CONFIG_T_CONFIG);
 
-        EXIT;
+       GOTO(out_mti, rc);
+
 out_mti:
-        if (mti != NULL)
-                OBD_FREE_PTR(mti);
+       if (locked)
+               mutex_unlock(&fsdb->fsdb_mutex);
+       if (mti != NULL)
+               OBD_FREE_PTR(mti);
 out_cancel:
        if (canceled_label != NULL)
                OBD_FREE(canceled_label, label_sz);
 out_label:
        OBD_FREE(label, label_sz);
-        return rc;
+out_fsdb:
+       if (free)
+               mgs_unlink_fsdb(mgs, fsdb);
+       mgs_put_fsdb(mgs, fsdb);
+
+       return rc;
 }