int lfsck_bookmark_setup(const struct lu_env *env, struct lfsck_instance *lfsck) { struct dt_object *root; struct dt_object *obj; int rc; ENTRY; root = dt_locate(env, lfsck->li_bottom, &lfsck->li_local_root_fid); if (IS_ERR(root)) RETURN(PTR_ERR(root)); if (unlikely(!dt_try_as_dir(env, root))) { lfsck_object_put(env, root); RETURN(-ENOTDIR); } obj = local_file_find_or_create(env, lfsck->li_los, root, LFSCK_BOOKMARK, S_IFREG | S_IRUGO | S_IWUSR); lfsck_object_put(env, root); if (IS_ERR(obj)) RETURN(PTR_ERR(obj)); lfsck->li_bookmark_obj = obj; rc = lfsck_bookmark_load(env, lfsck); if (rc == 0) { struct lfsck_bookmark *mb = &lfsck->li_bookmark_ram; /* It is upgraded from old release, set it as * LFSCK_ASYNC_WIN_DEFAULT to avoid memory pressure. */ if (unlikely(mb->lb_async_windows == 0)) { mb->lb_async_windows = LFSCK_ASYNC_WIN_DEFAULT; mutex_lock(&lfsck->li_mutex); rc = lfsck_bookmark_store(env, lfsck); mutex_unlock(&lfsck->li_mutex); } } else if (rc == -ENODATA) { rc = lfsck_bookmark_init(env, lfsck); } RETURN(rc); }
static void lfsck_close_dir(const struct lu_env *env, struct lfsck_instance *lfsck) { struct dt_object *dir_obj = lfsck->li_obj_dir; const struct dt_it_ops *dir_iops = &dir_obj->do_index_ops->dio_it; struct dt_it *dir_di = lfsck->li_di_dir; lfsck_di_dir_put(env, lfsck); dir_iops->fini(env, dir_di); lfsck->li_obj_dir = NULL; lfsck_object_put(env, dir_obj); }
static int lfsck_master_oit_engine(const struct lu_env *env, struct lfsck_instance *lfsck) { struct lfsck_thread_info *info = lfsck_env_info(env); const struct dt_it_ops *iops = &lfsck->li_obj_oit->do_index_ops->dio_it; struct dt_it *di = lfsck->li_di_oit; struct lu_fid *fid = &info->lti_fid; struct lfsck_bookmark *bk = &lfsck->li_bookmark_ram; struct ptlrpc_thread *thread = &lfsck->li_thread; __u32 idx = lfsck_dev_idx(lfsck->li_bottom); int rc; ENTRY; do { struct dt_object *target; bool update_lma = false; if (lfsck->li_di_dir != NULL) { rc = lfsck_master_dir_engine(env, lfsck); if (rc <= 0) RETURN(rc); } if (unlikely(lfsck->li_oit_over)) RETURN(1); if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_DELAY1) && cfs_fail_val > 0) { struct l_wait_info lwi; lwi = LWI_TIMEOUT(cfs_time_seconds(cfs_fail_val), NULL, NULL); l_wait_event(thread->t_ctl_waitq, !thread_is_running(thread), &lwi); } if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_CRASH)) RETURN(0); lfsck->li_current_oit_processed = 1; lfsck->li_new_scanned++; rc = iops->rec(env, di, (struct dt_rec *)fid, 0); if (rc != 0) { lfsck_fail(env, lfsck, true); if (rc < 0 && bk->lb_param & LPF_FAILOUT) RETURN(rc); else goto checkpoint; } if (fid_is_idif(fid)) { __u32 idx1 = fid_idif_ost_idx(fid); LASSERT(!lfsck->li_master); /* It is an old format device, update the LMA. */ if (idx != idx1) { struct ost_id *oi = &info->lti_oi; fid_to_ostid(fid, oi); ostid_to_fid(fid, oi, idx); update_lma = true; } } else if (!fid_is_norm(fid) && !fid_is_igif(fid) && !fid_is_last_id(fid) && !fid_is_root(fid) && !fid_seq_is_dot(fid_seq(fid))) { /* If the FID/object is only used locally and invisible * to external nodes, then LFSCK will not handle it. */ goto checkpoint; } target = lfsck_object_find(env, lfsck, fid); if (target == NULL) { goto checkpoint; } else if (IS_ERR(target)) { lfsck_fail(env, lfsck, true); if (bk->lb_param & LPF_FAILOUT) RETURN(PTR_ERR(target)); else goto checkpoint; } /* XXX: Currently, skip remote object, the consistency for * remote object will be processed in LFSCK phase III. */ if (dt_object_exists(target) && !dt_object_remote(target)) { if (update_lma) rc = lfsck_update_lma(env, lfsck, target); if (rc == 0) rc = lfsck_exec_oit(env, lfsck, target); } lfsck_object_put(env, target); if (rc != 0 && bk->lb_param & LPF_FAILOUT) RETURN(rc); checkpoint: rc = lfsck_checkpoint(env, lfsck); if (rc != 0 && bk->lb_param & LPF_FAILOUT) RETURN(rc); /* Rate control. */ lfsck_control_speed(lfsck); if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_FATAL1)) { spin_lock(&lfsck->li_lock); thread_set_flags(thread, SVC_STOPPING); spin_unlock(&lfsck->li_lock); RETURN(-EINVAL); } rc = iops->next(env, di); if (unlikely(rc > 0)) lfsck->li_oit_over = 1; else if (likely(rc == 0)) lfsck->li_current_oit_processed = 0; if (unlikely(!thread_is_running(thread))) RETURN(0); } while (rc == 0 || lfsck->li_di_dir != NULL); RETURN(rc); }
static int lfsck_master_dir_engine(const struct lu_env *env, struct lfsck_instance *lfsck) { struct lfsck_thread_info *info = lfsck_env_info(env); const struct dt_it_ops *iops = &lfsck->li_obj_dir->do_index_ops->dio_it; struct dt_it *di = lfsck->li_di_dir; struct lu_dirent *ent = &info->lti_ent; struct lu_fid *fid = &info->lti_fid; struct lfsck_bookmark *bk = &lfsck->li_bookmark_ram; struct ptlrpc_thread *thread = &lfsck->li_thread; int rc; ENTRY; do { struct dt_object *child; if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_DELAY2) && cfs_fail_val > 0) { struct l_wait_info lwi; lwi = LWI_TIMEOUT(cfs_time_seconds(cfs_fail_val), NULL, NULL); l_wait_event(thread->t_ctl_waitq, !thread_is_running(thread), &lwi); } lfsck->li_new_scanned++; rc = iops->rec(env, di, (struct dt_rec *)ent, lfsck->li_args_dir); lfsck_unpack_ent(ent, &lfsck->li_cookie_dir); if (rc != 0) { lfsck_fail(env, lfsck, true); if (bk->lb_param & LPF_FAILOUT) RETURN(rc); else goto checkpoint; } if (ent->lde_attrs & LUDA_IGNORE) goto checkpoint; *fid = ent->lde_fid; child = lfsck_object_find(env, lfsck, fid); if (child == NULL) { goto checkpoint; } else if (IS_ERR(child)) { lfsck_fail(env, lfsck, true); if (bk->lb_param & LPF_FAILOUT) RETURN(PTR_ERR(child)); else goto checkpoint; } /* XXX: Currently, skip remote object, the consistency for * remote object will be processed in LFSCK phase III. */ if (dt_object_exists(child) && !dt_object_remote(child)) rc = lfsck_exec_dir(env, lfsck, child, ent); lfsck_object_put(env, child); if (rc != 0 && bk->lb_param & LPF_FAILOUT) RETURN(rc); checkpoint: rc = lfsck_checkpoint(env, lfsck); if (rc != 0 && bk->lb_param & LPF_FAILOUT) RETURN(rc); /* Rate control. */ lfsck_control_speed(lfsck); if (unlikely(!thread_is_running(thread))) RETURN(0); if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_FATAL2)) { spin_lock(&lfsck->li_lock); thread_set_flags(thread, SVC_STOPPING); spin_unlock(&lfsck->li_lock); RETURN(-EINVAL); } rc = iops->next(env, di); } while (rc == 0); if (rc > 0 && !lfsck->li_oit_over) lfsck_close_dir(env, lfsck); RETURN(rc); }
static int lfsck_namespace_reset(const struct lu_env *env, struct lfsck_component *com, bool init) { struct lfsck_instance *lfsck = com->lc_lfsck; struct lfsck_namespace *ns = com->lc_file_ram; struct dt_object *root; struct dt_object *dto; int rc; ENTRY; root = dt_locate(env, lfsck->li_bottom, &lfsck->li_local_root_fid); if (IS_ERR(root)) RETURN(PTR_ERR(root)); if (unlikely(!dt_try_as_dir(env, root))) { lu_object_put(env, &root->do_lu); RETURN(-ENOTDIR); } down_write(&com->lc_sem); if (init) { memset(ns, 0, sizeof(*ns)); } else { __u32 count = ns->ln_success_count; __u64 last_time = ns->ln_time_last_complete; memset(ns, 0, sizeof(*ns)); ns->ln_success_count = count; ns->ln_time_last_complete = last_time; } ns->ln_magic = LFSCK_NAMESPACE_MAGIC; ns->ln_status = LS_INIT; rc = local_object_unlink(env, lfsck->li_bottom, root, lfsck_namespace_name); if (rc != 0) GOTO(out, rc); lfsck_object_put(env, com->lc_obj); com->lc_obj = NULL; dto = local_index_find_or_create(env, lfsck->li_los, root, lfsck_namespace_name, S_IFREG | S_IRUGO | S_IWUSR, &dt_lfsck_features); if (IS_ERR(dto)) GOTO(out, rc = PTR_ERR(dto)); com->lc_obj = dto; rc = dto->do_ops->do_index_try(env, dto, &dt_lfsck_features); if (rc != 0) GOTO(out, rc); rc = lfsck_namespace_store(env, com, true); GOTO(out, rc); out: up_write(&com->lc_sem); lu_object_put(env, &root->do_lu); return rc; }
/** * \retval +ve repaired * \retval 0 no need to repair * \retval -ve error cases */ static int lfsck_namespace_double_scan_one(const struct lu_env *env, struct lfsck_component *com, struct dt_object *child, __u8 flags) { struct lfsck_thread_info *info = lfsck_env_info(env); struct lu_attr *la = &info->lti_la; struct lu_name *cname = &info->lti_name; struct lu_fid *pfid = &info->lti_fid; struct lu_fid *cfid = &info->lti_fid2; struct lfsck_instance *lfsck = com->lc_lfsck; struct lfsck_bookmark *bk = &lfsck->li_bookmark_ram; struct lfsck_namespace *ns = com->lc_file_ram; struct linkea_data ldata = { 0 }; struct thandle *handle = NULL; bool locked = false; bool update = false; int rc; ENTRY; if (com->lc_journal) { again: LASSERT(!locked); update = false; com->lc_journal = 1; handle = dt_trans_create(env, lfsck->li_next); if (IS_ERR(handle)) RETURN(rc = PTR_ERR(handle)); rc = dt_declare_xattr_set(env, child, lfsck_buf_get_const(env, NULL, DEFAULT_LINKEA_SIZE), XATTR_NAME_LINK, 0, handle); if (rc != 0) GOTO(stop, rc); rc = dt_trans_start(env, lfsck->li_next, handle); if (rc != 0) GOTO(stop, rc); dt_write_lock(env, child, MOR_TGT_CHILD); locked = true; } if (unlikely(lfsck_is_dead_obj(child))) GOTO(stop, rc = 0); rc = dt_attr_get(env, child, la, BYPASS_CAPA); if (rc == 0) rc = lfsck_links_read(env, child, &ldata); if (rc != 0) { if ((bk->lb_param & LPF_DRYRUN) && (rc == -EINVAL || rc == -ENODATA)) rc = 1; GOTO(stop, rc); } linkea_first_entry(&ldata); while (ldata.ld_lee != NULL) { struct dt_object *parent = NULL; rc = lfsck_linkea_entry_unpack(lfsck, &ldata, cname, pfid); if (rc > 0) update = true; if (!fid_is_sane(pfid)) goto shrink; parent = lfsck_object_find(env, lfsck, pfid); if (parent == NULL) goto shrink; else if (IS_ERR(parent)) GOTO(stop, rc = PTR_ERR(parent)); if (!dt_object_exists(parent)) goto shrink; /* XXX: Currently, skip remote object, the consistency for * remote object will be processed in LFSCK phase III. */ if (dt_object_remote(parent)) { lfsck_object_put(env, parent); linkea_next_entry(&ldata); continue; } if (unlikely(!dt_try_as_dir(env, parent))) goto shrink; /* To guarantee the 'name' is terminated with '0'. */ memcpy(info->lti_key, cname->ln_name, cname->ln_namelen); info->lti_key[cname->ln_namelen] = 0; cname->ln_name = info->lti_key; rc = dt_lookup(env, parent, (struct dt_rec *)cfid, (const struct dt_key *)cname->ln_name, BYPASS_CAPA); if (rc != 0 && rc != -ENOENT) { lfsck_object_put(env, parent); GOTO(stop, rc); } if (rc == 0) { if (lu_fid_eq(cfid, lfsck_dto2fid(child))) { lfsck_object_put(env, parent); linkea_next_entry(&ldata); continue; } goto shrink; } /* If there is no name entry in the parent dir and the object * link count is less than the linkea entries count, then the * linkea entry should be removed. */ if (ldata.ld_leh->leh_reccount > la->la_nlink) goto shrink; /* XXX: For the case of there is a linkea entry, but without * name entry pointing to the object and its hard links * count is not less than the object name entries count, * then seems we should add the 'missed' name entry back * to namespace, but before LFSCK phase III finished, we * do not know whether the object has some inconsistency * on other MDTs. So now, do NOT add the name entry back * to the namespace, but keep the linkEA entry. LU-2914 */ lfsck_object_put(env, parent); linkea_next_entry(&ldata); continue; shrink: if (parent != NULL) lfsck_object_put(env, parent); if (bk->lb_param & LPF_DRYRUN) RETURN(1); CDEBUG(D_LFSCK, "Remove linkEA: "DFID"[%.*s], "DFID"\n", PFID(lfsck_dto2fid(child)), cname->ln_namelen, cname->ln_name, PFID(pfid)); linkea_del_buf(&ldata, cname); update = true; } if (update) { if (!com->lc_journal) { com->lc_journal = 1; goto again; } rc = lfsck_links_write(env, child, &ldata, handle); } GOTO(stop, rc); stop: if (locked) { /* XXX: For the case linkea entries count does not match the object hard * links count, we cannot update the later one simply. Before LFSCK * phase III finished, we cannot know whether there are some remote * name entries to be repaired or not. LU-2914 */ if (rc == 0 && !lfsck_is_dead_obj(child) && ldata.ld_leh != NULL && ldata.ld_leh->leh_reccount != la->la_nlink) CWARN("%s: the object "DFID" linkEA entry count %u " "may not match its hardlink count %u\n", lfsck_lfsck2name(lfsck), PFID(cfid), ldata.ld_leh->leh_reccount, la->la_nlink); dt_write_unlock(env, child); } if (handle != NULL) dt_trans_stop(env, lfsck->li_next, handle); if (rc == 0 && update) { ns->ln_objs_nlink_repaired++; rc = 1; } return rc; }
static int lfsck_namespace_double_scan_main(void *args) { struct lfsck_thread_args *lta = args; const struct lu_env *env = <a->lta_env; struct lfsck_component *com = lta->lta_com; struct lfsck_instance *lfsck = com->lc_lfsck; struct ptlrpc_thread *thread = &lfsck->li_thread; struct lfsck_bookmark *bk = &lfsck->li_bookmark_ram; struct lfsck_namespace *ns = com->lc_file_ram; struct dt_object *obj = com->lc_obj; const struct dt_it_ops *iops = &obj->do_index_ops->dio_it; struct dt_object *target; struct dt_it *di; struct dt_key *key; struct lu_fid fid; int rc; __u8 flags = 0; ENTRY; com->lc_new_checked = 0; com->lc_new_scanned = 0; com->lc_time_last_checkpoint = cfs_time_current(); com->lc_time_next_checkpoint = com->lc_time_last_checkpoint + cfs_time_seconds(LFSCK_CHECKPOINT_INTERVAL); di = iops->init(env, obj, 0, BYPASS_CAPA); if (IS_ERR(di)) GOTO(out, rc = PTR_ERR(di)); fid_cpu_to_be(&fid, &ns->ln_fid_latest_scanned_phase2); rc = iops->get(env, di, (const struct dt_key *)&fid); if (rc < 0) GOTO(fini, rc); /* Skip the start one, which either has been processed or non-exist. */ rc = iops->next(env, di); if (rc != 0) GOTO(put, rc); if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_NO_DOUBLESCAN)) GOTO(put, rc = 0); do { if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_DELAY3) && cfs_fail_val > 0) { struct l_wait_info lwi; lwi = LWI_TIMEOUT(cfs_time_seconds(cfs_fail_val), NULL, NULL); l_wait_event(thread->t_ctl_waitq, !thread_is_running(thread), &lwi); } key = iops->key(env, di); fid_be_to_cpu(&fid, (const struct lu_fid *)key); target = lfsck_object_find(env, lfsck, &fid); down_write(&com->lc_sem); if (target == NULL) { rc = 0; goto checkpoint; } else if (IS_ERR(target)) { rc = PTR_ERR(target); goto checkpoint; } /* XXX: Currently, skip remote object, the consistency for * remote object will be processed in LFSCK phase III. */ if (dt_object_exists(target) && !dt_object_remote(target)) { rc = iops->rec(env, di, (struct dt_rec *)&flags, 0); if (rc == 0) rc = lfsck_namespace_double_scan_one(env, com, target, flags); } lfsck_object_put(env, target); checkpoint: com->lc_new_checked++; com->lc_new_scanned++; ns->ln_fid_latest_scanned_phase2 = fid; if (rc > 0) ns->ln_objs_repaired_phase2++; else if (rc < 0) ns->ln_objs_failed_phase2++; up_write(&com->lc_sem); if ((rc == 0) || ((rc > 0) && !(bk->lb_param & LPF_DRYRUN))) { lfsck_namespace_delete(env, com, &fid); } else if (rc < 0) { flags |= LLF_REPAIR_FAILED; lfsck_namespace_update(env, com, &fid, flags, true); } if (rc < 0 && bk->lb_param & LPF_FAILOUT) GOTO(put, rc); if (unlikely(cfs_time_beforeq(com->lc_time_next_checkpoint, cfs_time_current())) && com->lc_new_checked != 0) { down_write(&com->lc_sem); ns->ln_run_time_phase2 += cfs_duration_sec(cfs_time_current() + HALF_SEC - com->lc_time_last_checkpoint); ns->ln_time_last_checkpoint = cfs_time_current_sec(); ns->ln_objs_checked_phase2 += com->lc_new_checked; com->lc_new_checked = 0; rc = lfsck_namespace_store(env, com, false); up_write(&com->lc_sem); if (rc != 0) GOTO(put, rc); com->lc_time_last_checkpoint = cfs_time_current(); com->lc_time_next_checkpoint = com->lc_time_last_checkpoint + cfs_time_seconds(LFSCK_CHECKPOINT_INTERVAL); } lfsck_control_speed_by_self(com); if (unlikely(!thread_is_running(thread))) GOTO(put, rc = 0); rc = iops->next(env, di); } while (rc == 0); GOTO(put, rc); put: iops->put(env, di); fini: iops->fini(env, di); out: down_write(&com->lc_sem); ns->ln_run_time_phase2 += cfs_duration_sec(cfs_time_current() + HALF_SEC - lfsck->li_time_last_checkpoint); ns->ln_time_last_checkpoint = cfs_time_current_sec(); ns->ln_objs_checked_phase2 += com->lc_new_checked; com->lc_new_checked = 0; if (rc > 0) { com->lc_journal = 0; ns->ln_status = LS_COMPLETED; if (!(bk->lb_param & LPF_DRYRUN)) ns->ln_flags &= ~(LF_SCANNED_ONCE | LF_INCONSISTENT); ns->ln_time_last_complete = ns->ln_time_last_checkpoint; ns->ln_success_count++; } else if (rc == 0) { ns->ln_status = lfsck->li_status; if (ns->ln_status == 0) ns->ln_status = LS_STOPPED; } else { ns->ln_status = LS_FAILED; } if (ns->ln_status != LS_PAUSED) { spin_lock(&lfsck->li_lock); cfs_list_del_init(&com->lc_link); cfs_list_add_tail(&com->lc_link, &lfsck->li_list_idle); spin_unlock(&lfsck->li_lock); } rc = lfsck_namespace_store(env, com, false); up_write(&com->lc_sem); if (atomic_dec_and_test(&lfsck->li_double_scan_count)) wake_up_all(&thread->t_ctl_waitq); lfsck_thread_args_fini(lta); return rc; }