Whamcloud - gitweb
LU-6027 osd-zfs: Preserve lu_buf when listing EAs
[fs/lustre-release.git] / lustre / lfsck / lfsck_lib.c
index 9a7980e..60f1df6 100644 (file)
@@ -42,6 +42,8 @@
 
 #include "lfsck_internal.h"
 
+#define LFSCK_CHECKPOINT_SKIP  1
+
 /* define lfsck thread key */
 LU_KEY_INIT(lfsck, struct lfsck_thread_info);
 
@@ -51,6 +53,7 @@ static void lfsck_key_fini(const struct lu_context *ctx,
        struct lfsck_thread_info *info = data;
 
        lu_buf_free(&info->lti_linkea_buf);
+       lu_buf_free(&info->lti_linkea_buf2);
        lu_buf_free(&info->lti_big_buf);
        OBD_FREE_PTR(info);
 }
@@ -95,6 +98,7 @@ const char *lfsck_param_names[] = {
        "broadcast",
        "orphan",
        "create_ostobj",
+       "create_mdtobj",
        NULL
 };
 
@@ -148,6 +152,8 @@ static void lfsck_tgt_descs_fini(struct lfsck_tgt_descs *ltds)
                if (likely(ltd != NULL)) {
                        LASSERT(list_empty(&ltd->ltd_layout_list));
                        LASSERT(list_empty(&ltd->ltd_layout_phase_list));
+                       LASSERT(list_empty(&ltd->ltd_namespace_list));
+                       LASSERT(list_empty(&ltd->ltd_namespace_phase_list));
 
                        ltds->ltd_tgtnr--;
                        cfs_bitmap_clear(ltds->ltd_tgts_bitmap, idx);
@@ -386,10 +392,25 @@ int lfsck_ibits_lock(const struct lu_env *env, struct lfsck_instance *lfsck,
        memset(policy, 0, sizeof(*policy));
        policy->l_inodebits.bits = bits;
        fid_build_reg_res_name(lfsck_dto2fid(obj), resid);
-       rc = ldlm_cli_enqueue_local(lfsck->li_namespace, resid, LDLM_IBITS,
-                                   policy, mode, &flags, ldlm_blocking_ast,
-                                   ldlm_completion_ast, NULL, NULL, 0,
-                                   LVB_T_NONE, NULL, lh);
+       if (dt_object_remote(obj)) {
+               struct ldlm_enqueue_info *einfo = &info->lti_einfo;
+
+               memset(einfo, 0, sizeof(*einfo));
+               einfo->ei_type = LDLM_IBITS;
+               einfo->ei_mode = mode;
+               einfo->ei_cb_bl = ldlm_blocking_ast;
+               einfo->ei_cb_cp = ldlm_completion_ast;
+               einfo->ei_res_id = resid;
+
+               rc = dt_object_lock(env, obj, lh, einfo, policy);
+       } else {
+               rc = ldlm_cli_enqueue_local(lfsck->li_namespace, resid,
+                                           LDLM_IBITS, policy, mode,
+                                           &flags, ldlm_blocking_ast,
+                                           ldlm_completion_ast, NULL, NULL,
+                                           0, LVB_T_NONE, NULL, lh);
+       }
+
        if (rc == ELDLM_OK) {
                rc = 0;
        } else {
@@ -417,8 +438,25 @@ void lfsck_ibits_unlock(struct lustre_handle *lh, ldlm_mode_t mode)
        }
 }
 
-static const char dot[] = ".";
-static const char dotdot[] = "..";
+int lfsck_find_mdt_idx_by_fid(const struct lu_env *env,
+                             struct lfsck_instance *lfsck,
+                             const struct lu_fid *fid)
+{
+       struct seq_server_site  *ss     =
+                       lu_site2seq(lfsck->li_bottom->dd_lu_dev.ld_site);
+       struct lu_seq_range     *range  = &lfsck_env_info(env)->lti_range;
+       int                      rc;
+
+       fld_range_set_mdt(range);
+       rc = fld_server_lookup(env, ss->ss_server_fld, fid_seq(fid), range);
+       if (rc == 0)
+               rc = range->lsr_index;
+
+       return rc;
+}
+
+const char dot[] = ".";
+const char dotdot[] = "..";
 static const char dotlustre[] = ".lustre";
 static const char lostfound[] = "lost+found";
 
@@ -445,7 +483,7 @@ static int lfsck_create_lpf_local(const struct lu_env *env,
        ENTRY;
 
        rc = linkea_data_new(&ldata,
-                            &lfsck_env_info(env)->lti_linkea_buf);
+                            &lfsck_env_info(env)->lti_linkea_buf2);
        if (rc != 0)
                RETURN(rc);
 
@@ -589,7 +627,7 @@ static int lfsck_create_lpf_remote(const struct lu_env *env,
        ENTRY;
 
        rc = linkea_data_new(&ldata,
-                            &lfsck_env_info(env)->lti_linkea_buf);
+                            &lfsck_env_info(env)->lti_linkea_buf2);
        if (rc != 0)
                RETURN(rc);
 
@@ -913,13 +951,8 @@ static int lfsck_scan_lpf_bad_entries(const struct lu_env *env,
                        break;
 
                ent->lde_namelen = le16_to_cpu(ent->lde_namelen);
-               if (ent->lde_name[0] == '.') {
-                       if (ent->lde_namelen == 1)
-                               goto next;
-
-                       if (ent->lde_namelen == 2 && ent->lde_name[1] == '.')
-                               goto next;
-               }
+               if (name_is_dot_or_dotdot(ent->lde_name, ent->lde_namelen))
+                       goto next;
 
                /* name length must be strlen("MDTxxxx") */
                if (ent->lde_namelen != 7)
@@ -1271,8 +1304,12 @@ int lfsck_verify_lpf(const struct lu_env *env, struct lfsck_instance *lfsck)
        snprintf(name, 8, "MDT%04x", node);
        rc = dt_lookup(env, parent, (struct dt_rec *)cfid,
                       (const struct dt_key *)name, BYPASS_CAPA);
-       if (rc == -ENOENT)
-               goto check_child1;
+       if (rc == -ENOENT) {
+               if (!fid_is_zero(&bk->lb_lpf_fid))
+                       goto check_child1;
+
+               GOTO(put, rc = 0);
+       }
 
        if (rc != 0)
                GOTO(put, rc);
@@ -1402,6 +1439,9 @@ void lfsck_instance_cleanup(const struct lu_env *env,
        struct ptlrpc_thread    *thread = &lfsck->li_thread;
        struct lfsck_component  *com;
        struct lfsck_component  *next;
+       struct lfsck_lmv_unit   *llu;
+       struct lfsck_lmv_unit   *llu_next;
+       struct lfsck_lmv        *llmv;
        ENTRY;
 
        LASSERT(list_empty(&lfsck->li_link));
@@ -1413,6 +1453,17 @@ void lfsck_instance_cleanup(const struct lu_env *env,
        }
 
        LASSERT(lfsck->li_obj_dir == NULL);
+       LASSERT(lfsck->li_lmv == NULL);
+
+       list_for_each_entry_safe(llu, llu_next, &lfsck->li_list_lmv, llu_link) {
+               llmv = &llu->llu_lmv;
+
+               LASSERTF(atomic_read(&llmv->ll_ref) == 1,
+                        "still in using: %u\n",
+                        atomic_read(&llmv->ll_ref));
+
+               lfsck_lmv_put(env, llmv);
+       }
 
        list_for_each_entry_safe(com, next, &lfsck->li_list_scan, lc_link) {
                lfsck_component_cleanup(env, com);
@@ -1594,12 +1645,14 @@ bool __lfsck_set_speed(struct lfsck_instance *lfsck, __u32 limit)
        bool dirty = false;
 
        if (limit != LFSCK_SPEED_NO_LIMIT) {
-               if (limit > HZ) {
-                       lfsck->li_sleep_rate = limit / HZ;
+               if (limit > msecs_to_jiffies(MSEC_PER_SEC)) {
+                       lfsck->li_sleep_rate = limit /
+                                              msecs_to_jiffies(MSEC_PER_SEC);
                        lfsck->li_sleep_jif = 1;
                } else {
                        lfsck->li_sleep_rate = 1;
-                       lfsck->li_sleep_jif = HZ / limit;
+                       lfsck->li_sleep_jif = msecs_to_jiffies(MSEC_PER_SEC) /
+                                             limit;
                }
        } else {
                lfsck->li_sleep_jif = 0;
@@ -1649,9 +1702,10 @@ void lfsck_control_speed_by_self(struct lfsck_component *com)
        }
 }
 
-struct lfsck_thread_args *lfsck_thread_args_init(struct lfsck_instance *lfsck,
-                                                struct lfsck_component *com,
-                                                struct lfsck_start_param *lsp)
+static struct lfsck_thread_args *
+lfsck_thread_args_init(struct lfsck_instance *lfsck,
+                      struct lfsck_component *com,
+                      struct lfsck_start_param *lsp)
 {
        struct lfsck_thread_args *lta;
        int                       rc;
@@ -1684,6 +1738,241 @@ void lfsck_thread_args_fini(struct lfsck_thread_args *lta)
        OBD_FREE_PTR(lta);
 }
 
+struct lfsck_assistant_data *
+lfsck_assistant_data_init(struct lfsck_assistant_operations *lao,
+                         const char *name)
+{
+       struct lfsck_assistant_data *lad;
+
+       OBD_ALLOC_PTR(lad);
+       if (lad != NULL) {
+               lad->lad_bitmap = CFS_ALLOCATE_BITMAP(BITS_PER_LONG);
+               if (lad->lad_bitmap == NULL) {
+                       OBD_FREE_PTR(lad);
+                       return NULL;
+               }
+
+               INIT_LIST_HEAD(&lad->lad_req_list);
+               spin_lock_init(&lad->lad_lock);
+               INIT_LIST_HEAD(&lad->lad_ost_list);
+               INIT_LIST_HEAD(&lad->lad_ost_phase1_list);
+               INIT_LIST_HEAD(&lad->lad_ost_phase2_list);
+               INIT_LIST_HEAD(&lad->lad_mdt_list);
+               INIT_LIST_HEAD(&lad->lad_mdt_phase1_list);
+               INIT_LIST_HEAD(&lad->lad_mdt_phase2_list);
+               init_waitqueue_head(&lad->lad_thread.t_ctl_waitq);
+               lad->lad_ops = lao;
+               lad->lad_name = name;
+       }
+
+       return lad;
+}
+
+/**
+ * Generic LFSCK asynchronous communication interpretor function.
+ * The LFSCK RPC reply for both the event notification and status
+ * querying will be handled here.
+ *
+ * \param[in] env      pointer to the thread context
+ * \param[in] req      pointer to the LFSCK request
+ * \param[in] args     pointer to the lfsck_async_interpret_args
+ * \param[in] rc       the result for handling the LFSCK request
+ *
+ * \retval             0 for success
+ * \retval             negative error number on failure
+ */
+int lfsck_async_interpret_common(const struct lu_env *env,
+                                struct ptlrpc_request *req,
+                                void *args, int rc)
+{
+       struct lfsck_async_interpret_args *laia = args;
+       struct lfsck_component            *com  = laia->laia_com;
+       struct lfsck_assistant_data       *lad  = com->lc_data;
+       struct lfsck_tgt_descs            *ltds = laia->laia_ltds;
+       struct lfsck_tgt_desc             *ltd  = laia->laia_ltd;
+       struct lfsck_request              *lr   = laia->laia_lr;
+
+       LASSERT(com->lc_lfsck->li_master);
+
+       switch (lr->lr_event) {
+       case LE_START:
+               if (rc != 0) {
+                       CDEBUG(D_LFSCK, "%s: fail to notify %s %x for %s "
+                              "start: rc = %d\n",
+                              lfsck_lfsck2name(com->lc_lfsck),
+                              (lr->lr_flags & LEF_TO_OST) ? "OST" : "MDT",
+                              ltd->ltd_index, lad->lad_name, rc);
+
+                       if (com->lc_type == LFSCK_TYPE_LAYOUT) {
+                               struct lfsck_layout *lo = com->lc_file_ram;
+
+                               if (lr->lr_flags & LEF_TO_OST)
+                                       lfsck_lad_set_bitmap(env, com,
+                                                            ltd->ltd_index);
+                               else
+                                       lo->ll_flags |= LF_INCOMPLETE;
+                       } else {
+                               struct lfsck_namespace *ns = com->lc_file_ram;
+
+                               /* If some MDT does not join the namespace
+                                * LFSCK, then we cannot know whether there
+                                * is some name entry on such MDT that with
+                                * the referenced MDT-object on this MDT or
+                                * not. So the namespace LFSCK on this MDT
+                                * cannot handle orphan MDT-objects properly.
+                                * So we mark the LFSCK as LF_INCOMPLETE and
+                                * skip orphan MDT-objects handling. */
+                               ns->ln_flags |= LF_INCOMPLETE;
+                       }
+                       break;
+               }
+
+               spin_lock(&ltds->ltd_lock);
+               if (ltd->ltd_dead) {
+                       spin_unlock(&ltds->ltd_lock);
+                       break;
+               }
+
+               if (com->lc_type == LFSCK_TYPE_LAYOUT) {
+                       struct list_head *list;
+                       struct list_head *phase_list;
+
+                       if (ltd->ltd_layout_done) {
+                               spin_unlock(&ltds->ltd_lock);
+                               break;
+                       }
+
+                       if (lr->lr_flags & LEF_TO_OST) {
+                               list = &lad->lad_ost_list;
+                               phase_list = &lad->lad_ost_phase1_list;
+                       } else {
+                               list = &lad->lad_mdt_list;
+                               phase_list = &lad->lad_mdt_phase1_list;
+                       }
+
+                       if (list_empty(&ltd->ltd_layout_list))
+                               list_add_tail(&ltd->ltd_layout_list, list);
+                       if (list_empty(&ltd->ltd_layout_phase_list))
+                               list_add_tail(&ltd->ltd_layout_phase_list,
+                                             phase_list);
+               } else {
+                       if (ltd->ltd_namespace_done) {
+                               spin_unlock(&ltds->ltd_lock);
+                               break;
+                       }
+
+                       if (list_empty(&ltd->ltd_namespace_list))
+                               list_add_tail(&ltd->ltd_namespace_list,
+                                             &lad->lad_mdt_list);
+                       if (list_empty(&ltd->ltd_namespace_phase_list))
+                               list_add_tail(&ltd->ltd_namespace_phase_list,
+                                             &lad->lad_mdt_phase1_list);
+               }
+               spin_unlock(&ltds->ltd_lock);
+               break;
+       case LE_STOP:
+       case LE_PHASE1_DONE:
+       case LE_PHASE2_DONE:
+       case LE_PEER_EXIT:
+               if (rc != 0 && rc != -EALREADY)
+                       CDEBUG(D_LFSCK, "%s: fail to notify %s %x for %s: "
+                             "event = %d, rc = %d\n",
+                             lfsck_lfsck2name(com->lc_lfsck),
+                             (lr->lr_flags & LEF_TO_OST) ? "OST" : "MDT",
+                             ltd->ltd_index, lad->lad_name, lr->lr_event, rc);
+               break;
+       case LE_QUERY: {
+               struct lfsck_reply *reply;
+               struct list_head *list;
+               struct list_head *phase_list;
+
+               if (com->lc_type == LFSCK_TYPE_LAYOUT) {
+                       list = &ltd->ltd_layout_list;
+                       phase_list = &ltd->ltd_layout_phase_list;
+               } else {
+                       list = &ltd->ltd_namespace_list;
+                       phase_list = &ltd->ltd_namespace_phase_list;
+               }
+
+               if (rc != 0) {
+                       spin_lock(&ltds->ltd_lock);
+                       list_del_init(phase_list);
+                       list_del_init(list);
+                       spin_unlock(&ltds->ltd_lock);
+                       break;
+               }
+
+               reply = req_capsule_server_get(&req->rq_pill,
+                                              &RMF_LFSCK_REPLY);
+               if (reply == NULL) {
+                       rc = -EPROTO;
+                       CDEBUG(D_LFSCK, "%s: invalid query reply for %s: "
+                              "rc = %d\n", lfsck_lfsck2name(com->lc_lfsck),
+                              lad->lad_name, rc);
+                       spin_lock(&ltds->ltd_lock);
+                       list_del_init(phase_list);
+                       list_del_init(list);
+                       spin_unlock(&ltds->ltd_lock);
+                       break;
+               }
+
+               switch (reply->lr_status) {
+               case LS_SCANNING_PHASE1:
+                       break;
+               case LS_SCANNING_PHASE2:
+                       spin_lock(&ltds->ltd_lock);
+                       list_del_init(phase_list);
+                       if (ltd->ltd_dead) {
+                               spin_unlock(&ltds->ltd_lock);
+                               break;
+                       }
+
+                       if (com->lc_type == LFSCK_TYPE_LAYOUT) {
+                               if (ltd->ltd_layout_done) {
+                                       spin_unlock(&ltds->ltd_lock);
+                                       break;
+                               }
+
+                               if (lr->lr_flags & LEF_TO_OST)
+                                       list_add_tail(phase_list,
+                                               &lad->lad_ost_phase2_list);
+                               else
+                                       list_add_tail(phase_list,
+                                               &lad->lad_mdt_phase2_list);
+                       } else {
+                               if (ltd->ltd_namespace_done) {
+                                       spin_unlock(&ltds->ltd_lock);
+                                       break;
+                               }
+
+                               list_add_tail(phase_list,
+                                             &lad->lad_mdt_phase2_list);
+                       }
+                       spin_unlock(&ltds->ltd_lock);
+                       break;
+               default:
+                       spin_lock(&ltds->ltd_lock);
+                       list_del_init(phase_list);
+                       list_del_init(list);
+                       spin_unlock(&ltds->ltd_lock);
+                       break;
+               }
+               break;
+       }
+       default:
+               CDEBUG(D_LFSCK, "%s: unexpected event: rc = %d\n",
+                      lfsck_lfsck2name(com->lc_lfsck), lr->lr_event);
+               break;
+       }
+
+       if (!laia->laia_shared) {
+               lfsck_tgt_put(ltd);
+               lfsck_component_put(env, com);
+       }
+
+       return 0;
+}
+
 static void lfsck_interpret(const struct lu_env *env,
                            struct lfsck_instance *lfsck,
                            struct ptlrpc_request *req, void *args, int result)
@@ -1696,17 +1985,13 @@ static void lfsck_interpret(const struct lu_env *env,
 
        spin_lock(&lfsck->li_lock);
        list_for_each_entry(com, &lfsck->li_list_scan, lc_link) {
-               if (com->lc_ops->lfsck_interpret != NULL) {
-                       laia->laia_com = com;
-                       com->lc_ops->lfsck_interpret(env, req, laia, result);
-               }
+               laia->laia_com = com;
+               lfsck_async_interpret_common(env, req, laia, result);
        }
 
        list_for_each_entry(com, &lfsck->li_list_double_scan, lc_link) {
-               if (com->lc_ops->lfsck_interpret != NULL) {
-                       laia->laia_com = com;
-                       com->lc_ops->lfsck_interpret(env, req, laia, result);
-               }
+               laia->laia_com = com;
+               lfsck_async_interpret_common(env, req, laia, result);
        }
        spin_unlock(&lfsck->li_lock);
 }
@@ -1716,11 +2001,12 @@ static int lfsck_stop_notify(const struct lu_env *env,
                             struct lfsck_tgt_descs *ltds,
                             struct lfsck_tgt_desc *ltd, __u16 type)
 {
-       struct ptlrpc_request_set *set;
-       struct lfsck_component    *com;
-       int                        rc  = 0;
+       struct lfsck_component *com;
+       int                     rc = 0;
        ENTRY;
 
+       LASSERT(lfsck->li_master);
+
        spin_lock(&lfsck->li_lock);
        com = __lfsck_component_find(lfsck, type, &lfsck->li_list_scan);
        if (com == NULL)
@@ -1731,22 +2017,72 @@ static int lfsck_stop_notify(const struct lu_env *env,
        spin_unlock(&lfsck->li_lock);
 
        if (com != NULL) {
-               if (com->lc_ops->lfsck_stop_notify != NULL) {
-                       set = ptlrpc_prep_set();
-                       if (set == NULL) {
-                               lfsck_component_put(env, com);
+               struct lfsck_thread_info          *info  = lfsck_env_info(env);
+               struct lfsck_async_interpret_args *laia  = &info->lti_laia;
+               struct lfsck_request              *lr    = &info->lti_lr;
+               struct lfsck_assistant_data       *lad   = com->lc_data;
+               struct list_head                  *list;
+               struct list_head                  *phase_list;
+               struct ptlrpc_request_set         *set;
+
+               set = ptlrpc_prep_set();
+               if (set == NULL) {
+                       lfsck_component_put(env, com);
 
-                               RETURN(-ENOMEM);
-                       }
+                       RETURN(-ENOMEM);
+               }
 
-                       rc = com->lc_ops->lfsck_stop_notify(env, com, ltds,
-                                                           ltd, set);
-                       if (rc == 0)
-                               rc = ptlrpc_set_wait(set);
+               if (type == LFSCK_TYPE_LAYOUT) {
+                       list = &ltd->ltd_layout_list;
+                       phase_list = &ltd->ltd_layout_phase_list;
+               } else {
+                       list = &ltd->ltd_namespace_list;
+                       phase_list = &ltd->ltd_namespace_phase_list;
+               }
 
+               spin_lock(&ltds->ltd_lock);
+               if (list_empty(list)) {
+                       LASSERT(list_empty(phase_list));
+                       spin_unlock(&ltds->ltd_lock);
                        ptlrpc_set_destroy(set);
+
+                       RETURN(0);
+               }
+
+               list_del_init(phase_list);
+               list_del_init(list);
+               spin_unlock(&ltds->ltd_lock);
+
+               memset(lr, 0, sizeof(*lr));
+               lr->lr_index = lfsck_dev_idx(lfsck->li_bottom);
+               lr->lr_event = LE_PEER_EXIT;
+               lr->lr_active = type;
+               lr->lr_status = LS_CO_PAUSED;
+               if (ltds == &lfsck->li_ost_descs)
+                       lr->lr_flags = LEF_TO_OST;
+
+               laia->laia_com = com;
+               laia->laia_ltds = ltds;
+               atomic_inc(&ltd->ltd_ref);
+               laia->laia_ltd = ltd;
+               laia->laia_lr = lr;
+               laia->laia_shared = 0;
+
+               rc = lfsck_async_request(env, ltd->ltd_exp, lr, set,
+                                        lfsck_async_interpret_common,
+                                        laia, LFSCK_NOTIFY);
+               if (rc != 0) {
+                       CDEBUG(D_LFSCK, "%s: fail to notify %s %x for "
+                              "co-stop for %s: rc = %d\n",
+                              lfsck_lfsck2name(lfsck),
+                              (lr->lr_flags & LEF_TO_OST) ? "OST" : "MDT",
+                              ltd->ltd_index, lad->lad_name, rc);
+                       lfsck_tgt_put(ltd);
+               } else {
+                       rc = ptlrpc_set_wait(set);
                }
 
+               ptlrpc_set_destroy(set);
                lfsck_component_put(env, com);
        }
 
@@ -1820,6 +2156,139 @@ int lfsck_async_request(const struct lu_env *env, struct obd_export *exp,
        return 0;
 }
 
+int lfsck_start_assistant(const struct lu_env *env, struct lfsck_component *com,
+                         struct lfsck_start_param *lsp)
+{
+       struct lfsck_instance           *lfsck   = com->lc_lfsck;
+       struct lfsck_assistant_data     *lad     = com->lc_data;
+       struct ptlrpc_thread            *mthread = &lfsck->li_thread;
+       struct ptlrpc_thread            *athread = &lad->lad_thread;
+       struct lfsck_thread_args        *lta;
+       struct task_struct              *task;
+       int                              rc;
+       ENTRY;
+
+       lad->lad_assistant_status = 0;
+       lad->lad_post_result = 0;
+       lad->lad_to_post = 0;
+       lad->lad_to_double_scan = 0;
+       lad->lad_in_double_scan = 0;
+       lad->lad_exit = 0;
+       thread_set_flags(athread, 0);
+
+       lta = lfsck_thread_args_init(lfsck, com, lsp);
+       if (IS_ERR(lta))
+               RETURN(PTR_ERR(lta));
+
+       task = kthread_run(lfsck_assistant_engine, lta, lad->lad_name);
+       if (IS_ERR(task)) {
+               rc = PTR_ERR(task);
+               CERROR("%s: cannot start LFSCK assistant thread for %s: "
+                      "rc = %d\n", lfsck_lfsck2name(lfsck), lad->lad_name, rc);
+               lfsck_thread_args_fini(lta);
+       } else {
+               struct l_wait_info lwi = { 0 };
+
+               l_wait_event(mthread->t_ctl_waitq,
+                            thread_is_running(athread) ||
+                            thread_is_stopped(athread),
+                            &lwi);
+               if (unlikely(!thread_is_running(athread)))
+                       rc = lad->lad_assistant_status;
+               else
+                       rc = 0;
+       }
+
+       RETURN(rc);
+}
+
+int lfsck_checkpoint_generic(const struct lu_env *env,
+                            struct lfsck_component *com)
+{
+       struct lfsck_assistant_data     *lad     = com->lc_data;
+       struct ptlrpc_thread            *mthread = &com->lc_lfsck->li_thread;
+       struct ptlrpc_thread            *athread = &lad->lad_thread;
+       struct l_wait_info               lwi     = { 0 };
+
+       if (com->lc_new_checked == 0)
+               return LFSCK_CHECKPOINT_SKIP;
+
+       l_wait_event(mthread->t_ctl_waitq,
+                    list_empty(&lad->lad_req_list) ||
+                    !thread_is_running(mthread) ||
+                    thread_is_stopped(athread),
+                    &lwi);
+
+       if (!thread_is_running(mthread) || thread_is_stopped(athread))
+               return LFSCK_CHECKPOINT_SKIP;
+
+       return 0;
+}
+
+void lfsck_post_generic(const struct lu_env *env,
+                       struct lfsck_component *com, int *result)
+{
+       struct lfsck_assistant_data     *lad     = com->lc_data;
+       struct ptlrpc_thread            *athread = &lad->lad_thread;
+       struct ptlrpc_thread            *mthread = &com->lc_lfsck->li_thread;
+       struct l_wait_info               lwi     = { 0 };
+
+       lad->lad_post_result = *result;
+       if (*result <= 0)
+               lad->lad_exit = 1;
+       lad->lad_to_post = 1;
+
+       wake_up_all(&athread->t_ctl_waitq);
+       l_wait_event(mthread->t_ctl_waitq,
+                    (*result > 0 && list_empty(&lad->lad_req_list)) ||
+                    thread_is_stopped(athread),
+                    &lwi);
+
+       if (lad->lad_assistant_status < 0)
+               *result = lad->lad_assistant_status;
+}
+
+int lfsck_double_scan_generic(const struct lu_env *env,
+                             struct lfsck_component *com, int status)
+{
+       struct lfsck_assistant_data     *lad     = com->lc_data;
+       struct ptlrpc_thread            *mthread = &com->lc_lfsck->li_thread;
+       struct ptlrpc_thread            *athread = &lad->lad_thread;
+       struct l_wait_info               lwi     = { 0 };
+
+       if (status != LS_SCANNING_PHASE2)
+               lad->lad_exit = 1;
+       else
+               lad->lad_to_double_scan = 1;
+
+       wake_up_all(&athread->t_ctl_waitq);
+       l_wait_event(mthread->t_ctl_waitq,
+                    lad->lad_in_double_scan ||
+                    thread_is_stopped(athread),
+                    &lwi);
+
+       if (lad->lad_assistant_status < 0)
+               return lad->lad_assistant_status;
+
+       return 0;
+}
+
+void lfsck_quit_generic(const struct lu_env *env,
+                       struct lfsck_component *com)
+{
+       struct lfsck_assistant_data     *lad     = com->lc_data;
+       struct ptlrpc_thread            *mthread = &com->lc_lfsck->li_thread;
+       struct ptlrpc_thread            *athread = &lad->lad_thread;
+       struct l_wait_info               lwi     = { 0 };
+
+       lad->lad_exit = 1;
+       wake_up_all(&athread->t_ctl_waitq);
+       l_wait_event(mthread->t_ctl_waitq,
+                    thread_is_init(athread) ||
+                    thread_is_stopped(athread),
+                    &lwi);
+}
+
 /* external interfaces */
 
 int lfsck_get_speed(struct seq_file *m, struct dt_device *key)
@@ -2072,7 +2541,8 @@ static int lfsck_start_all(const struct lu_env *env,
        lr->lr_param = start->ls_flags;
        lr->lr_async_windows = bk->lb_async_windows;
        lr->lr_valid = LSV_SPEED_LIMIT | LSV_ERROR_HANDLE | LSV_DRYRUN |
-                      LSV_ASYNC_WINDOWS;
+                      LSV_ASYNC_WINDOWS | LSV_CREATE_OSTOBJ |
+                      LSV_CREATE_MDTOBJ;
 
        laia->laia_com = NULL;
        laia->laia_ltds = ltds;
@@ -2087,6 +2557,7 @@ static int lfsck_start_all(const struct lu_env *env,
 
                laia->laia_ltd = ltd;
                ltd->ltd_layout_done = 0;
+               ltd->ltd_namespace_done = 0;
                rc = lfsck_async_request(env, ltd->ltd_exp, lr, set,
                                         lfsck_async_interpret, laia,
                                         LFSCK_NOTIFY);
@@ -2287,7 +2758,7 @@ int lfsck_start(const struct lu_env *env, struct dt_device *key,
        }
 
 trigger:
-       lfsck->li_args_dir = LUDA_64BITHASH | LUDA_VERIFY;
+       lfsck->li_args_dir = LUDA_64BITHASH | LUDA_VERIFY | LUDA_TYPE;
        if (bk->lb_param & LPF_DRYRUN)
                lfsck->li_args_dir |= LUDA_VERIFY_DRYRUN;
 
@@ -2432,7 +2903,7 @@ out:
 EXPORT_SYMBOL(lfsck_stop);
 
 int lfsck_in_notify(const struct lu_env *env, struct dt_device *key,
-                   struct lfsck_request *lr)
+                   struct lfsck_request *lr, struct thandle *th)
 {
        int rc = -EOPNOTSUPP;
        ENTRY;
@@ -2470,6 +2941,11 @@ int lfsck_in_notify(const struct lu_env *env, struct dt_device *key,
        case LE_FID_ACCESSED:
        case LE_PEER_EXIT:
        case LE_CONDITIONAL_DESTROY:
+       case LE_CREATE_ORPHAN:
+       case LE_SKIP_NLINK_DECLARE:
+       case LE_SKIP_NLINK:
+       case LE_SET_LMV_MASTER:
+       case LE_SET_LMV_SLAVE:
        case LE_PAIRS_VERIFY: {
                struct lfsck_instance  *lfsck;
                struct lfsck_component *com;
@@ -2480,7 +2956,7 @@ int lfsck_in_notify(const struct lu_env *env, struct dt_device *key,
 
                com = lfsck_component_find(lfsck, lr->lr_active);
                if (likely(com != NULL)) {
-                       rc = com->lc_ops->lfsck_in_notify(env, com, lr);
+                       rc = com->lc_ops->lfsck_in_notify(env, com, lr, th);
                        lfsck_component_put(env, com);
                }
 
@@ -2564,6 +3040,7 @@ int lfsck_register(const struct lu_env *env, struct dt_device *key,
        INIT_LIST_HEAD(&lfsck->li_list_dir);
        INIT_LIST_HEAD(&lfsck->li_list_double_scan);
        INIT_LIST_HEAD(&lfsck->li_list_idle);
+       INIT_LIST_HEAD(&lfsck->li_list_lmv);
        atomic_set(&lfsck->li_ref, 1);
        atomic_set(&lfsck->li_double_scan_count, 0);
        init_waitqueue_head(&lfsck->li_thread.t_ctl_waitq);
@@ -2732,6 +3209,8 @@ int lfsck_add_target(const struct lu_env *env, struct dt_device *key,
        INIT_LIST_HEAD(&ltd->ltd_orphan_list);
        INIT_LIST_HEAD(&ltd->ltd_layout_list);
        INIT_LIST_HEAD(&ltd->ltd_layout_phase_list);
+       INIT_LIST_HEAD(&ltd->ltd_namespace_list);
+       INIT_LIST_HEAD(&ltd->ltd_namespace_phase_list);
        atomic_set(&ltd->ltd_ref, 1);
        ltd->ltd_index = index;
 
@@ -2831,6 +3310,7 @@ unlock:
                spin_lock(&ltds->ltd_lock);
                ltd->ltd_dead = 1;
                spin_unlock(&ltds->ltd_lock);
+               lfsck_stop_notify(env, lfsck, ltds, ltd, LFSCK_TYPE_NAMESPACE);
                lfsck_stop_notify(env, lfsck, ltds, ltd, LFSCK_TYPE_LAYOUT);
                lfsck_tgt_put(ltd);
        }