Whamcloud - gitweb
LU-14714 mgc: server to mount without local config 83/55283/8
authorMikhail Pershin <mpershin@whamcloud.com>
Wed, 29 May 2024 18:27:13 +0000 (21:27 +0300)
committerOleg Drokin <green@whamcloud.com>
Thu, 8 Aug 2024 00:15:40 +0000 (00:15 +0000)
Server uses local config copy to mount with but
that is not the case always. Local config can be
damaged or empty and may be not updated from MGS,
e.g. due to -ENOSPC on server upon llog backup or
other errors. That causes empty or partial local
config so server unable to mount with it.

Patch allows a server to mount first from remote config
if local config wasn't copied from MGS. If remote
processing is not possible or failed then local config
is used as last attempt to mount.

Signed-off-by: Mikhail Pershin <mpershin@whamcloud.com>
Change-Id: I442a4f20eeb7deb1b40ccc7cabb1fae65804e211
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/55283
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Sebastien Buisson <sbuisson@ddn.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/include/lustre_log.h
lustre/include/obd_support.h
lustre/mgc/mgc_request.c
lustre/mgc/mgc_request_server.c
lustre/obdclass/llog.c
lustre/tests/conf-sanity.sh

index bc9cfa2..e064935 100644 (file)
@@ -106,6 +106,7 @@ int llog_is_empty(const struct lu_env *env, struct llog_ctxt *ctxt,
 int llog_backup(const struct lu_env *env, struct obd_device *obd,
                struct llog_ctxt *ctxt, struct llog_ctxt *bak_ctxt,
                char *name, char *backup);
+int llog_validate(const struct lu_env *env, struct llog_ctxt *ctxt, char *name);
 int llog_read_header(const struct lu_env *env, struct llog_handle *handle,
                     const struct obd_uuid *uuid);
 __u64 llog_size(const struct lu_env *env, struct llog_handle *llh);
index 0f37442..b7f4181 100644 (file)
@@ -603,6 +603,7 @@ extern bool obd_enable_health_write;
 #define OBD_FAIL_CATLIST                           0x131b
 #define OBD_FAIL_LLOG_PAUSE_AFTER_PAD               0x131c
 #define OBD_FAIL_LLOG_ADD_GAP                      0x131d
+#define OBD_FAIL_LLOG_BACKUP_ENOSPC                0x131e
 
 #define OBD_FAIL_LLITE                              0x1400
 #define OBD_FAIL_LLITE_FAULT_TRUNC_RACE             0x1401
index 5f4ed83..9513a99 100644 (file)
@@ -1629,9 +1629,12 @@ static int mgc_process_cfg_log(struct obd_device *mgc,
        LASSERT(cld);
        LASSERT(mutex_is_locked(&cld->cld_lock));
 
+#ifndef HAVE_SERVER_SUPPORT
+       if (local_only)
+               RETURN(-EIO);
+#endif
        if (cld->cld_cfg.cfg_sb)
                lsi = s2lsi(cld->cld_cfg.cfg_sb);
-
        /* sptlrpc llog must not keep ref to sb,
         * it was just needed to get lsi
         */
@@ -1648,27 +1651,38 @@ static int mgc_process_cfg_log(struct obd_device *mgc,
 
        ctxt = llog_get_context(mgc, LLOG_CONFIG_REPL_CTXT);
        LASSERT(ctxt);
+
 #ifdef HAVE_SERVER_SUPPORT
-       rc = mgc_process_server_cfg_log(env, &ctxt, lsi, mgc, cld,
-                                       local_only);
-       if (rc == -EIO && local_only)
-               GOTO(out_pop, rc);
-       if (rc && rc != -ENOENT)
-#else
-       if (local_only)
-               GOTO(out_pop, rc = -EIO);
+       /* IS_SERVER(lsi) doesn't work if MGC is shared between client/server
+        * distinguish server mount by local storage set by server_mgc_set_fs()
+        */
+       if (lsi && mgc->u.cli.cl_mgc_los) {
+               if (!IS_MGS(lsi))
+                       rc = mgc_process_server_cfg_log(env, &ctxt, lsi, mgc,
+                                                       cld, !local_only);
+       } else if (local_only) {
+               rc = -EIO;
+       }
 #endif
+       /* When returned from mgc_process_server_cfg_log() the rc can be:
+        *   0 - config llog context is returned for parsing below
+        *   EALREADY - config was parsed already
+        *   rc < 0 - fatal error, local and remote parsing are not available
+        */
+       if (!rc)
                rc = class_config_parse_llog(env, ctxt, cld->cld_logname,
                                             &cld->cld_cfg);
-
+       if (rc < 0)
+               GOTO(out_pop, rc);
        /*
         * update settings on existing OBDs.
         * the logname must be <fsname>-sptlrpc
         */
-       if (rc == 0 && cld_is_sptlrpc(cld))
+       if (cld_is_sptlrpc(cld))
                class_notify_sptlrpc_conf(cld->cld_logname,
                                          strlen(cld->cld_logname) -
                                          strlen("-sptlrpc"));
+       rc = 0;
        EXIT;
 
 out_pop:
index 7954d1d..7104cd5 100644 (file)
@@ -504,20 +504,21 @@ int mgc_barrier_glimpse_ast(struct ldlm_lock *lock, void *data)
 
 /* Copy a remote log locally */
 static int mgc_llog_local_copy(const struct lu_env *env,
-                              struct obd_device *obd,
                               struct llog_ctxt *rctxt,
                               struct llog_ctxt *lctxt, char *logname)
 {
+       struct obd_device *obd = lctxt->loc_obd;
        char *temp_log;
        int rc;
 
        ENTRY;
        /*
-        * NB: mgc_process_server_cfg_log() always needs valid local copy
-        * and works only on it, so that defines the process:
+        * NB: mgc_get_server_cfg_log() prefers local copy first
+        * and works on it if valid, so that defines the process:
         * - copy current local copy to temp_log using llog_backup()
         * - copy remote llog to logname using llog_backup()
         * - if failed then restore logname from backup
+        * That guarantees valid local copy only after successful step #2
         */
 
        OBD_ALLOC(temp_log, strlen(logname) + 2);
@@ -525,11 +526,25 @@ static int mgc_llog_local_copy(const struct lu_env *env,
                RETURN(-ENOMEM);
        sprintf(temp_log, "%sT", logname);
 
-       /* copy current local llog to temp_log */
-       rc = llog_backup(env, obd, lctxt, lctxt, logname, temp_log);
-       if (rc < 0 && rc != -ENOENT)
-               CWARN("%s: failed to backup local config %s: rc = %d\n",
+       /* check current local llog is valid */
+       rc = llog_validate(env, lctxt, logname);
+       if (!rc) {
+               /* copy current local llog to temp_log */
+               rc = llog_backup(env, obd, lctxt, lctxt, logname, temp_log);
+               if (rc < 0)
+                       CWARN("%s: can't backup local config %s: rc = %d\n",
+                             obd->obd_name, logname, rc);
+       } else if (rc < 0 && rc != -ENOENT) {
+               CWARN("%s: invalid local config log %s: rc = %d\n",
                      obd->obd_name, logname, rc);
+               rc = llog_erase(env, lctxt, NULL, logname);
+       }
+
+       /* don't ignore errors like -EROFS and -ENOSPC, don't try to
+        * refresh local config in that case but mount using remote one
+        */
+       if (rc == -ENOSPC || rc == -EROFS)
+               GOTO(out_free, rc);
 
        /* build new local llog */
        rc = llog_backup(env, obd, rctxt, lctxt, logname, logname);
@@ -544,7 +559,7 @@ static int mgc_llog_local_copy(const struct lu_env *env,
                llog_backup(env, obd, lctxt, lctxt, temp_log, logname);
        }
        llog_erase(env, lctxt, NULL, temp_log);
-
+out_free:
        OBD_FREE(temp_log, strlen(logname) + 2);
        return rc;
 }
@@ -552,76 +567,65 @@ static int mgc_llog_local_copy(const struct lu_env *env,
 int mgc_process_server_cfg_log(struct lu_env *env, struct llog_ctxt **ctxt,
                               struct lustre_sb_info *lsi,
                               struct obd_device *mgc,
-                              struct config_llog_data *cld, int local_only)
+                              struct config_llog_data *cld, int mgslock)
 {
        struct llog_ctxt *lctxt = llog_get_context(mgc, LLOG_CONFIG_ORIG_CTXT);
        struct client_obd *cli = &mgc->u.cli;
-       int rc = 0;
+       struct dt_object *configs_dir = cli->cl_mgc_configs_dir;
+       int rc = mgslock ? 0 : -EIO;
 
-       /* Copy the setup log locally if we can. Don't mess around if we're
-        * running an MGS though (logs are already local).
-        */
-       if (lctxt && lsi && IS_SERVER(lsi) && !IS_MGS(lsi) &&
-           cli->cl_mgc_configs_dir &&
-           lu2dt_dev(cli->cl_mgc_configs_dir->do_lu.lo_dev) ==
-           lsi->lsi_dt_dev) {
-               if (!local_only && !lsi->lsi_dt_dev->dd_rdonly) {
-                       /* Only try to copy log if we have the lock. */
-                       CDEBUG(D_INFO, "%s: copy local log %s\n",
-                              mgc->obd_name, cld->cld_logname);
-
-                       rc = mgc_llog_local_copy(env, mgc, *ctxt, lctxt,
-                                                cld->cld_logname);
-                       if (!rc)
-                               lsi->lsi_flags &= ~LDD_F_NO_LOCAL_LOGS;
-               }
-               if (local_only || rc) {
-                       if (unlikely(lsi->lsi_flags & LDD_F_NO_LOCAL_LOGS) ||
-                           rc) {
-                               CWARN("%s: local log %s are not valid and/or remote logs are not accessbile rc = %d\n",
-                                     mgc->obd_name, cld->cld_logname, rc);
-                               GOTO(out_pop, rc = -EIO);
-                       }
-
-                       if (strcmp(cld->cld_logname, PARAMS_FILENAME) != 0 &&
-                           llog_is_empty(env, lctxt, cld->cld_logname)) {
-                               LCONSOLE_ERROR("Failed to get MGS log %s and no local copy.\n",
-                                              cld->cld_logname);
-                               GOTO(out_pop, rc = -ENOENT);
-                       }
-                       CDEBUG(D_MGC,
-                              "%s: Failed to get MGS log %s, using local copy for now, will try to update later.\n",
-                              mgc->obd_name, cld->cld_logname);
-                       rc = 0;
-               }
-               /* Now, whether we copied or not, start using the local llog.
-                * If we failed to copy, we'll start using whatever the old
-                * log has.
-                */
-               llog_ctxt_put(*ctxt);
-               *ctxt = lctxt;
-               lctxt = NULL;
-       } else if (local_only) { /* no local log at client side */
-               GOTO(out_pop, rc = -EIO);
+       /* requeue might happen in nowhere state */
+       if (!lctxt)
+               RETURN(rc);
+       if (!configs_dir ||
+           lu2dt_dev(configs_dir->do_lu.lo_dev) != lsi->lsi_dt_dev)
+               GOTO(out_pop, rc);
+
+       if (lsi->lsi_dt_dev->dd_rdonly) {
+               rc = -EROFS;
+       } else if (mgslock) {
+               /* Only try to copy log if we have the MGS lock. */
+               CDEBUG(D_INFO, "%s: copy local log %s\n", mgc->obd_name,
+                      cld->cld_logname);
+
+               rc = mgc_llog_local_copy(env, *ctxt, lctxt, cld->cld_logname);
+               if (!rc)
+                       lsi->lsi_flags &= ~LDD_F_NO_LOCAL_LOGS;
        }
 
-       rc = -EAGAIN;
-       if (lsi && IS_SERVER(lsi) && !IS_MGS(lsi) &&
-           lsi->lsi_dt_dev->dd_rdonly) {
-               struct llog_ctxt *rctxt;
+       if (!mgslock) {
+               if (unlikely(lsi->lsi_flags & LDD_F_NO_LOCAL_LOGS)) {
+                       rc = -EIO;
+                       CWARN("%s: failed to get MGS log %s and no_local_log flag is set: rc = %d\n",
+                             mgc->obd_name, cld->cld_logname, rc);
+                       GOTO(out_pop, rc);
+               }
 
-               /* Under readonly mode, we may have no local copy or local
-                * copy is incomplete, so try to use remote llog firstly.
+               rc = llog_validate(env, lctxt, cld->cld_logname);
+               if (rc && strcmp(cld->cld_logname, PARAMS_FILENAME)) {
+                       LCONSOLE_ERROR("Failed to get MGS log %s and no local copy.\n",
+                                      cld->cld_logname);
+                       GOTO(out_pop, rc);
+               }
+               CDEBUG(D_MGC,
+                      "%s: Failed to get MGS log %s, using local copy for now, will try to update later.\n",
+                      mgc->obd_name, cld->cld_logname);
+       } else if (rc) {
+               /* In case of error we may have empty or incomplete local
+                * config. In both cases proceed with remote llog first
                 */
-               rctxt = llog_get_context(mgc, LLOG_CONFIG_REPL_CTXT);
-               LASSERT(rctxt);
-
-               rc = class_config_parse_llog(env, rctxt, cld->cld_logname,
+               rc = class_config_parse_llog(env, *ctxt, cld->cld_logname,
                                             &cld->cld_cfg);
-               llog_ctxt_put(rctxt);
+               if (!rc)
+                       GOTO(out_pop, rc = EALREADY);
+               /* in case of an error while parsing remote MGS config
+                * just try local copy whatever it is as last attempt
+                */
        }
+       llog_ctxt_put(*ctxt);
+       *ctxt = lctxt;
+       RETURN(0);
 out_pop:
-       if (lctxt)
-               __llog_ctxt_put(env, lctxt);
+       __llog_ctxt_put(env, lctxt);
        return rc;
 }
index 82f042d..a45d0d5 100644 (file)
@@ -1456,6 +1456,9 @@ int llog_copy_handler(const struct lu_env *env, struct llog_handle *llh,
 
        ENTRY;
 
+       if (CFS_FAIL_CHECK(OBD_FAIL_LLOG_BACKUP_ENOSPC))
+               RETURN(-ENOSPC);
+
        /* Append all records */
        rc = llog_write(env, copy_llh, rec, LLOG_NEXT_IDX);
 
@@ -1534,6 +1537,54 @@ out_close:
 }
 EXPORT_SYMBOL(llog_backup);
 
+/* just count processed records */
+int llog_validate_record(const struct lu_env *env, struct llog_handle *llh,
+                        struct llog_rec_hdr *rec, void *data)
+{
+       int *recs = data;
+
+       (*recs)++;
+       return 0;
+}
+/* validate plain llog by reading all its records */
+int llog_validate(const struct lu_env *env, struct llog_ctxt *ctxt, char *name)
+{
+       struct llog_handle *llh;
+       struct llog_process_cat_data cd = { 0 };
+       unsigned int recs;
+       unsigned int processed = 1; /* one for header */
+       int rc;
+
+       ENTRY;
+
+       rc = llog_open(env, ctxt, &llh, NULL, name, LLOG_OPEN_EXISTS);
+       if (rc < 0)
+               RETURN(rc);
+
+       rc = llog_init_handle(env, llh, LLOG_F_IS_PLAIN, NULL);
+       if (rc)
+               GOTO(out_close, rc);
+
+       recs = llog_get_size(llh);
+       if (recs <= 1)
+               GOTO(out_close, rc = -ENOENT);
+
+       rc = llog_process_or_fork(env, llh, llog_validate_record, &processed,
+                                 &cd, false);
+       if (rc) {
+               CWARN("%s: can't validate log %s: rc = %d\n",
+                     ctxt->loc_obd->obd_name, name, rc);
+       } else if (recs != processed) {
+               rc = -EINVAL;
+               CWARN("%s: %s has %d recs but %d were processed: rc = %d\n",
+                     ctxt->loc_obd->obd_name, name, recs, processed, rc);
+       }
+out_close:
+       llog_close(env, llh);
+       RETURN(rc);
+}
+EXPORT_SYMBOL(llog_validate);
+
 /* Get size of llog */
 __u64 llog_size(const struct lu_env *env, struct llog_handle *llh)
 {
index fd4bd67..b3733e6 100755 (executable)
@@ -11106,7 +11106,7 @@ test_150() {
 }
 run_test 150 "test setting max_cached_mb to a %"
 
-test_151() {
+test_151a() {
        (( MDS1_VERSION >= $(version_code 2.15.58) )) ||
                skip "need MDS version at least 2.15.58"
        [[ "$ost1_FSTYPE" == ldiskfs ]] || skip "ldiskfs only test"
@@ -11132,7 +11132,27 @@ test_151() {
        start_ost || error "OST start failed"
        reformat_and_config
 }
-run_test 151 "damaged local config doesn't prevent mounting"
+run_test 151a "damaged local config doesn't prevent mounting"
+
+test_151b() {
+       (( MDS1_VERSION >= $(version_code 2.15.63) )) ||
+               skip "need MDS version at least 2.15.63"
+       [[ "$ost1_FSTYPE" == ldiskfs ]] || skip "ldiskfs only test"
+
+       cleanup
+       if ! combined_mgs_mds ; then
+               stop mgs
+       fi
+
+       start_mgsmds || error "MDS start failed"
+
+       # start despite -ENOSPC errors
+#define OBD_FAIL_LLOG_BACKUP_ENOSPC 0x131e
+       do_facet ost1 $LCTL set_param fail_loc=0x131e
+       start_ost || error "OST start failed"
+       reformat_and_config
+}
+run_test 151b "-ENOSPC doesn't affect mount"
 
 test_152() {
        (( MDS1_VERSION >= $(version_code 2.15.59.53) )) ||