From f1918fee9a8459a522f37530da5c5a0aa4bab551 Mon Sep 17 00:00:00 2001 From: Fan Yong Date: Sun, 27 Jul 2014 07:49:29 +0800 Subject: [PATCH] LU-4788 lfsck: verify .lustre/lost+found at the LFSCK start /ROOT/.lustre/lost+found/ is a special directory to hold the objects that the LFSCK does not exactly know how to handle, such as orphans. So before the LFSCK scanning the system, the consistency of such directory needs to be verified firstly to allow the users it during the LFSCK. fid_seq_is_dot_lustre() is a duplication of fid_seq_is_dot(), drop it and cleanup the code. Signed-off-by: Fan Yong Change-Id: I95cac84bed1ae16c8c86e495db0120d964395b5e Reviewed-on: http://review.whamcloud.com/10987 Reviewed-by: Andreas Dilger Reviewed-by: Alex Zhuravlev Tested-by: Jenkins Tested-by: Maloo Reviewed-by: Oleg Drokin --- lustre/include/lustre_fid.h | 7 +- lustre/lfsck/lfsck_engine.c | 15 ++ lustre/lfsck/lfsck_internal.h | 11 + lustre/lfsck/lfsck_lib.c | 483 +++++++++++++++++++++++++++++++++++++++++ lustre/lfsck/lfsck_namespace.c | 202 ++++++++++++++++- lustre/mdt/mdt_reint.c | 4 +- lustre/tests/sanity-lfsck.sh | 66 +++--- 7 files changed, 746 insertions(+), 42 deletions(-) diff --git a/lustre/include/lustre_fid.h b/lustre/include/lustre_fid.h index 83f52c3..6436632 100644 --- a/lustre/include/lustre_fid.h +++ b/lustre/include/lustre_fid.h @@ -260,11 +260,6 @@ static inline int fid_is_root(const struct lu_fid *fid) fid_oid(fid) == 1)); } -static inline int fid_seq_is_dot_lustre(__u64 seq) -{ - return unlikely(seq == FID_SEQ_DOT_LUSTRE); -} - static inline int fid_is_dot_lustre(const struct lu_fid *fid) { return unlikely(fid_seq(fid) == FID_SEQ_DOT_LUSTRE && @@ -309,7 +304,7 @@ static inline int fid_is_namespace_visible(const struct lu_fid *fid) * object or not. It is caller's duty to check more if needed. */ return (!fid_is_last_id(fid) && (fid_seq_is_norm(seq) || fid_seq_is_igif(seq))) || - fid_is_root(fid) || fid_seq_is_dot_lustre(seq); + fid_is_root(fid) || fid_seq_is_dot(seq); } static inline int fid_seq_in_fldb(__u64 seq) diff --git a/lustre/lfsck/lfsck_engine.c b/lustre/lfsck/lfsck_engine.c index 663f9e1..39a0b3c 100644 --- a/lustre/lfsck/lfsck_engine.c +++ b/lustre/lfsck/lfsck_engine.c @@ -821,6 +821,21 @@ int lfsck_master_engine(void *args) int rc; ENTRY; + if (lfsck->li_master && + (!list_empty(&lfsck->li_list_scan) || + !list_empty(&lfsck->li_list_double_scan))) { + rc = lfsck_verify_lpf(env, lfsck); + /* Fail to verify the .lustre/lost+found/MDTxxxx/ may be not + * fatal, because the .lustre/lost+found/ maybe not accessed + * by the LFSCK if it does not add orphans or others to such + * directory. So go ahead until hit failure when really uses + * the directory. */ + if (rc != 0) + CDEBUG(D_LFSCK, "%s: master engine fail to verify the " + ".lustre/lost+found/, go ahead: rc = %d\n", + lfsck_lfsck2name(lfsck), rc); + } + oit_di = oit_iops->init(env, oit_obj, lfsck->li_args_oit, BYPASS_CAPA); if (IS_ERR(oit_di)) { rc = PTR_ERR(oit_di); diff --git a/lustre/lfsck/lfsck_internal.h b/lustre/lfsck/lfsck_internal.h index f9bd20e..eb0af97 100644 --- a/lustre/lfsck/lfsck_internal.h +++ b/lustre/lfsck/lfsck_internal.h @@ -586,6 +586,7 @@ int lfsck_ibits_lock(const struct lu_env *env, struct lfsck_instance *lfsck, __u64 bits, ldlm_mode_t mode); void lfsck_ibits_unlock(struct lustre_handle *lh, ldlm_mode_t mode); int lfsck_create_lpf(const struct lu_env *env, struct lfsck_instance *lfsck); +int lfsck_verify_lpf(const struct lu_env *env, struct lfsck_instance *lfsck); struct lfsck_instance *lfsck_instance_find(struct dt_device *key, bool ref, bool unlink); struct lfsck_component *lfsck_component_find(struct lfsck_instance *lfsck, @@ -632,6 +633,16 @@ int lfsck_set_param(const struct lu_env *env, struct lfsck_instance *lfsck, int lfsck_verify_linkea(const struct lu_env *env, struct dt_device *dev, struct dt_object *obj, const struct lu_name *cname, const struct lu_fid *pfid); +int lfsck_links_get_first(const struct lu_env *env, struct dt_object *obj, + char *name, struct lu_fid *pfid); +int lfsck_remove_name_entry(const struct lu_env *env, + struct lfsck_instance *lfsck, + struct dt_object *parent, + const char *name, __u32 type); +int lfsck_update_name_entry(const struct lu_env *env, + struct lfsck_instance *lfsck, + struct dt_object *parent, const char *name, + const struct lu_fid *pfid, __u32 type); int lfsck_namespace_setup(const struct lu_env *env, struct lfsck_instance *lfsck); diff --git a/lustre/lfsck/lfsck_lib.c b/lustre/lfsck/lfsck_lib.c index 325f7e7..9a7980e 100644 --- a/lustre/lfsck/lfsck_lib.c +++ b/lustre/lfsck/lfsck_lib.c @@ -98,6 +98,11 @@ const char *lfsck_param_names[] = { NULL }; +enum lfsck_verify_lpf_types { + LVLT_BY_BOOKMARK = 0, + LVLT_BY_NAMEENTRY = 1, +}; + const char *lfsck_status2names(enum lfsck_status status) { if (unlikely(status < 0 || status >= LS_MAX)) @@ -865,6 +870,484 @@ out: return rc; } +/** + * Scan .lustre/lost+found for bad name entries and remove them. + * + * The valid name entry should be "MDTxxxx", the "xxxx" is the MDT device + * index in the system. Any other formatted name is invalid and should be + * removed. + * + * \param[in] env pointer to the thread context + * \param[in] lfsck pointer to the lfsck instance + * \param[in] parent pointer to the lost+found object + * + * \retval 0 for success + * \retval negative error number on failure + */ +static int lfsck_scan_lpf_bad_entries(const struct lu_env *env, + struct lfsck_instance *lfsck, + struct dt_object *parent) +{ + struct lu_dirent *ent = + (struct lu_dirent *)lfsck_env_info(env)->lti_key; + const struct dt_it_ops *iops = &parent->do_index_ops->dio_it; + struct dt_it *it; + int rc; + ENTRY; + + it = iops->init(env, parent, LUDA_64BITHASH, BYPASS_CAPA); + if (IS_ERR(it)) + RETURN(PTR_ERR(it)); + + rc = iops->load(env, it, 0); + if (rc == 0) + rc = iops->next(env, it); + else if (rc > 0) + rc = 0; + + while (rc == 0) { + int off = 3; + + rc = iops->rec(env, it, (struct dt_rec *)ent, LUDA_64BITHASH); + if (rc != 0) + 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; + } + + /* name length must be strlen("MDTxxxx") */ + if (ent->lde_namelen != 7) + goto remove; + + if (memcmp(ent->lde_name, "MDT", off) != 0) + goto remove; + + while (off < 7 && isxdigit(ent->lde_name[off])) + off++; + + if (off != 7) { + +remove: + rc = lfsck_remove_name_entry(env, lfsck, parent, + ent->lde_name, S_IFDIR); + if (rc != 0) + break; + } + +next: + rc = iops->next(env, it); + } + + iops->put(env, it); + iops->fini(env, it); + + RETURN(rc > 0 ? 0 : rc); +} + +static int lfsck_update_lpf_entry(const struct lu_env *env, + struct lfsck_instance *lfsck, + struct dt_object *parent, + struct dt_object *child, + const char *name, + enum lfsck_verify_lpf_types type) +{ + int rc; + + if (type == LVLT_BY_BOOKMARK) { + rc = lfsck_update_name_entry(env, lfsck, parent, name, + lfsck_dto2fid(child), S_IFDIR); + } else /* if (type == LVLT_BY_NAMEENTRY) */ { + lfsck->li_bookmark_ram.lb_lpf_fid = *lfsck_dto2fid(child); + rc = lfsck_bookmark_store(env, lfsck); + + CDEBUG(D_LFSCK, "%s: update LPF fid "DFID + " in the bookmark file: rc = %d\n", + lfsck_lfsck2name(lfsck), + PFID(lfsck_dto2fid(child)), rc); + } + + return rc; +} + +/** + * Check whether the @child back references the @parent. + * + * Two cases: + * 1) The child's FID is stored in the bookmark file. If the child back + * references the parent (LU_LPF_FID object) via its ".." entry, then + * insert the name (MDTxxxx) to the .lustre/lost+found; otherwise, if + * the child back references another parent2, then: + * 1.1) If the parent2 recognizes the child, then update the bookmark file; + * 1.2) Otherwise, the LFSCK cannot know whether there will be parent3 that + * references the child. So keep them there. As the LFSCK processing, + * the parent3 may be found, then when the LFSCK run next time, the + * inconsistency can be repaired. + * + * 2) The child's FID is stored in the .lustre/lost+found/ sub-directory name + * entry (MDTxxxx). If the child back references the parent (LU_LPF_FID obj) + * via its ".." entry, then update the bookmark file, otherwise, if the child + * back references another parent2, then: + * 2.1) If the parent2 recognizes the child, then remove the sub-directory + * from .lustre/lost+found/; + * 2.2) Otherwise, if the parent2 does not recognizes the child, trust the + * sub-directory name entry and update the child; + * 2.3) Otherwise, if we do not know whether the parent2 recognizes the child + * or not, then keep them there. + * + * \param[in] env pointer to the thread context + * \param[in] lfsck pointer to the lfsck instance + * \param[in] parent pointer to the lost+found object + * \param[in] child pointer to the lost+found sub-directory object + * \param[in] name the name for lost+found sub-directory object + * \param[out] fid pointer to the buffer to hold the FID of the object + * (called it as parent2) that is referenced via the + * child's dotdot entry; it also can be the FID that + * is referenced by the name entry under the parent2. + * \param[in] type to indicate where the child's FID is stored in + * + * \retval positive number for uncertain inconsistency + * \retval 0 for success + * \retval negative error number on failure + */ +static int lfsck_verify_lpf_pairs(const struct lu_env *env, + struct lfsck_instance *lfsck, + struct dt_object *parent, + struct dt_object *child, const char *name, + struct lu_fid *fid, + enum lfsck_verify_lpf_types type) +{ + struct lfsck_thread_info *info = lfsck_env_info(env); + char *name2 = info->lti_key; + struct lu_fid *fid2 = &info->lti_fid3; + struct dt_object *parent2 = NULL; + struct lustre_handle lh = { 0 }; + int rc; + ENTRY; + + fid_zero(fid); + rc = dt_lookup(env, child, (struct dt_rec *)fid, + (const struct dt_key *)dotdot, BYPASS_CAPA); + if (rc != 0) + GOTO(linkea, rc); + + if (!fid_is_sane(fid)) + GOTO(linkea, rc = -EINVAL); + + if (lu_fid_eq(fid, &LU_LPF_FID)) { + const struct lu_name *cname; + + if (lfsck->li_lpf_obj == NULL) { + lu_object_get(&child->do_lu); + lfsck->li_lpf_obj = child; + } + + cname = lfsck_name_get_const(env, name, strlen(name)); + rc = lfsck_verify_linkea(env, lfsck->li_bottom, child, cname, + &LU_LPF_FID); + if (rc == 0) + rc = lfsck_update_lpf_entry(env, lfsck, parent, child, + name, type); + + GOTO(out_done, rc); + } + + parent2 = lfsck_object_find_by_dev(env, lfsck->li_next, fid); + if (IS_ERR(parent2)) + GOTO(linkea, parent2); + + if (!dt_object_exists(parent2)) { + lu_object_put(env, &parent2->do_lu); + + GOTO(linkea, parent2 = ERR_PTR(-ENOENT)); + } + + if (!dt_try_as_dir(env, parent2)) { + lu_object_put(env, &parent2->do_lu); + + GOTO(linkea, parent2 = ERR_PTR(-ENOTDIR)); + } + +linkea: + /* To prevent rename/unlink race */ + rc = lfsck_ibits_lock(env, lfsck, child, &lh, + MDS_INODELOCK_UPDATE, LCK_PR); + if (rc != 0) + GOTO(out_put, rc); + + dt_read_lock(env, child, 0); + rc = lfsck_links_get_first(env, child, name2, fid2); + if (rc != 0) { + dt_read_unlock(env, child); + lfsck_ibits_unlock(&lh, LCK_PR); + + GOTO(out_put, rc = 1); + } + + /* It is almost impossible that the bookmark file (or the name entry) + * and the linkEA hit the same data corruption. Trust the linkEA. */ + if (lu_fid_eq(fid2, &LU_LPF_FID) && strcmp(name, name2) == 0) { + dt_read_unlock(env, child); + lfsck_ibits_unlock(&lh, LCK_PR); + + *fid = *fid2; + if (lfsck->li_lpf_obj == NULL) { + lu_object_get(&child->do_lu); + lfsck->li_lpf_obj = child; + } + + /* Update the child's dotdot entry */ + rc = lfsck_update_name_entry(env, lfsck, child, dotdot, + &LU_LPF_FID, S_IFDIR); + if (rc == 0) + rc = lfsck_update_lpf_entry(env, lfsck, parent, child, + name, type); + + GOTO(out_put, rc); + } + + if (parent2 == NULL || IS_ERR(parent2)) { + dt_read_unlock(env, child); + lfsck_ibits_unlock(&lh, LCK_PR); + + GOTO(out_done, rc = 1); + } + + rc = dt_lookup(env, parent2, (struct dt_rec *)fid, + (const struct dt_key *)name2, BYPASS_CAPA); + dt_read_unlock(env, child); + lfsck_ibits_unlock(&lh, LCK_PR); + if (rc != 0 && rc != -ENOENT) + GOTO(out_put, rc); + + if (rc == -ENOENT || !lu_fid_eq(fid, lfsck_dto2fid(child))) { + if (type == LVLT_BY_BOOKMARK) + GOTO(out_put, rc = 1); + + /* Trust the name entry, update the child's dotdot entry. */ + rc = lfsck_update_name_entry(env, lfsck, child, dotdot, + &LU_LPF_FID, S_IFDIR); + + GOTO(out_put, rc); + } + + if (type == LVLT_BY_BOOKMARK) { + /* Invalid FID record in the bookmark file, reset it. */ + fid_zero(&lfsck->li_bookmark_ram.lb_lpf_fid); + rc = lfsck_bookmark_store(env, lfsck); + + CDEBUG(D_LFSCK, "%s: reset invalid LPF fid "DFID + " in the bookmark file: rc = %d\n", + lfsck_lfsck2name(lfsck), PFID(lfsck_dto2fid(child)), rc); + } else /* if (type == LVLT_BY_NAMEENTRY) */ { + /* The name entry is wrong, remove it. */ + rc = lfsck_remove_name_entry(env, lfsck, parent, name, S_IFDIR); + } + + GOTO(out_put, rc); + +out_put: + if (parent2 != NULL && !IS_ERR(parent2)) + lu_object_put(env, &parent2->do_lu); + +out_done: + return rc; +} + +/** + * Verify the /ROOT/.lustre/lost+found/ directory. + * + * /ROOT/.lustre/lost+found/ is a special directory to hold the objects that + * the LFSCK does not exactly know how to handle, such as orphans. So before + * the LFSCK scanning the system, the consistency of such directory needs to + * be verified firstly to allow the users to use it during the LFSCK. + * + * \param[in] env pointer to the thread context + * \param[in] lfsck pointer to the lfsck instance + * + * \retval positive number for uncertain inconsistency + * \retval 0 for success + * \retval negative error number on failure + */ +int lfsck_verify_lpf(const struct lu_env *env, struct lfsck_instance *lfsck) +{ + struct lfsck_thread_info *info = lfsck_env_info(env); + struct lu_fid *pfid = &info->lti_fid; + struct lu_fid *cfid = &info->lti_fid2; + struct lfsck_bookmark *bk = &lfsck->li_bookmark_ram; + struct dt_object *parent = NULL; + /* child1's FID is in the bookmark file. */ + struct dt_object *child1 = NULL; + /* child2's FID is in the name entry MDTxxxx. */ + struct dt_object *child2 = NULL; + struct dt_device *dev = lfsck->li_bottom; + const struct lu_name *cname; + char name[8]; + int node = lfsck_dev_idx(dev); + int rc = 0; + ENTRY; + + LASSERT(lfsck->li_master); + + if (node == 0) { + parent = lfsck_object_find_by_dev(env, dev, &LU_LPF_FID); + } else { + struct lfsck_tgt_desc *ltd; + + ltd = lfsck_tgt_get(&lfsck->li_mdt_descs, 0); + if (unlikely(ltd == NULL)) + RETURN(-ENXIO); + + parent = lfsck_object_find_by_dev(env, ltd->ltd_tgt, + &LU_LPF_FID); + lfsck_tgt_put(ltd); + } + + if (IS_ERR(parent)) + RETURN(PTR_ERR(parent)); + + LASSERT(dt_object_exists(parent)); + + if (unlikely(!dt_try_as_dir(env, parent))) + GOTO(put, rc = -ENOTDIR); + + if (node == 0) { + rc = lfsck_scan_lpf_bad_entries(env, lfsck, parent); + if (rc != 0) + CDEBUG(D_LFSCK, "%s: scan .lustre/lost+found/ " + "for bad sub-directories: rc = %d\n", + lfsck_lfsck2name(lfsck), rc); + } + + if (!fid_is_zero(&bk->lb_lpf_fid)) { + if (unlikely(!fid_is_norm(&bk->lb_lpf_fid))) { + struct lu_fid tfid = bk->lb_lpf_fid; + + /* Invalid FID record in the bookmark file, reset it. */ + fid_zero(&bk->lb_lpf_fid); + rc = lfsck_bookmark_store(env, lfsck); + + CDEBUG(D_LFSCK, "%s: reset invalid LPF fid "DFID + " in the bookmark file: rc = %d\n", + lfsck_lfsck2name(lfsck), PFID(&tfid), rc); + + if (rc != 0) + GOTO(put, rc); + } else { + child1 = lfsck_object_find_by_dev(env, dev, + &bk->lb_lpf_fid); + if (IS_ERR(child1)) + GOTO(put, rc = PTR_ERR(child1)); + + if (unlikely(!dt_object_exists(child1) || + dt_object_remote(child1)) || + !S_ISDIR(lfsck_object_type(child1))) { + /* Invalid FID record in the bookmark file, + * reset it. */ + fid_zero(&bk->lb_lpf_fid); + rc = lfsck_bookmark_store(env, lfsck); + + CDEBUG(D_LFSCK, "%s: reset invalid LPF fid "DFID + " in the bookmark file: rc = %d\n", + lfsck_lfsck2name(lfsck), + PFID(lfsck_dto2fid(child1)), rc); + + if (rc != 0) + GOTO(put, rc); + + lu_object_put(env, &child1->do_lu); + child1 = NULL; + } else if (unlikely(!dt_try_as_dir(env, child1))) { + GOTO(put, rc = -ENOTDIR); + } + } + } + + 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 != 0) + GOTO(put, rc); + + /* Invalid FID in the name entry, remove the name entry. */ + if (!fid_is_norm(cfid)) { + rc = lfsck_remove_name_entry(env, lfsck, parent, name, S_IFDIR); + if (rc != 0) + GOTO(put, rc); + + goto check_child1; + } + + child2 = lfsck_object_find_by_dev(env, dev, cfid); + if (IS_ERR(child2)) + GOTO(put, rc = PTR_ERR(child2)); + + if (unlikely(!dt_object_exists(child2) || + dt_object_remote(child2)) || + !S_ISDIR(lfsck_object_type(child2))) { + rc = lfsck_remove_name_entry(env, lfsck, parent, name, + S_IFDIR); + if (rc != 0) + GOTO(put, rc); + + goto check_child1; + } + + if (unlikely(!dt_try_as_dir(env, child2))) + GOTO(put, rc = -ENOTDIR); + + if (child1 == NULL) { + rc = lfsck_verify_lpf_pairs(env, lfsck, parent, child2, name, + pfid, LVLT_BY_NAMEENTRY); + } else if (!lu_fid_eq(cfid, &bk->lb_lpf_fid)) { + rc = lfsck_verify_lpf_pairs(env, lfsck, parent, child1, name, + pfid, LVLT_BY_BOOKMARK); + if (!lu_fid_eq(pfid, &LU_LPF_FID)) + rc = lfsck_verify_lpf_pairs(env, lfsck, parent, child2, + name, pfid, + LVLT_BY_NAMEENTRY); + } else { + if (lfsck->li_lpf_obj == NULL) { + lu_object_get(&child2->do_lu); + lfsck->li_lpf_obj = child2; + } + + cname = lfsck_name_get_const(env, name, strlen(name)); + rc = lfsck_verify_linkea(env, dev, child2, cname, &LU_LPF_FID); + } + + GOTO(put, rc); + +check_child1: + if (child1 != NULL) + rc = lfsck_verify_lpf_pairs(env, lfsck, parent, child1, name, + pfid, LVLT_BY_BOOKMARK); + + GOTO(put, rc); + +put: + if (lfsck->li_lpf_obj != NULL && + unlikely(!dt_try_as_dir(env, lfsck->li_lpf_obj))) + rc = -ENOTDIR; + + if (child2 != NULL && !IS_ERR(child2)) + lu_object_put(env, &child2->do_lu); + if (child1 != NULL && !IS_ERR(child1)) + lu_object_put(env, &child1->do_lu); + if (parent != NULL && !IS_ERR(parent)) + lu_object_put(env, &parent->do_lu); + + return rc; +} + static int lfsck_fid_init(struct lfsck_instance *lfsck) { struct lfsck_bookmark *bk = &lfsck->li_bookmark_ram; diff --git a/lustre/lfsck/lfsck_namespace.c b/lustre/lfsck/lfsck_namespace.c index 92ae407..dc4bb5e 100644 --- a/lustre/lfsck/lfsck_namespace.c +++ b/lustre/lfsck/lfsck_namespace.c @@ -892,7 +892,7 @@ static int lfsck_namespace_exec_dir(const struct lu_env *env, if (ent->lde_name[0] == '.' && (ent->lde_namelen == 1 || (ent->lde_namelen == 2 && ent->lde_name[1] == '.') || - fid_seq_is_dot_lustre(fid_seq(&ent->lde_fid)))) + fid_seq_is_dot(fid_seq(&ent->lde_fid)))) GOTO(out, rc = 0); if (!(bk->lb_param & LPF_DRYRUN) && @@ -1677,6 +1677,206 @@ stop: return rc; } +/** + * Get the name and parent directory's FID from the first linkEA entry. + * + * \param[in] env pointer to the thread context + * \param[in] obj pointer to the object which get linkEA from + * \param[out] name pointer to the buffer to hold the name + * in the first linkEA entry + * \param[out] pfid pointer to the buffer to hold the parent + * directory's FID in the first linkEA entry + * + * \retval 0 for success + * \retval negative error number on failure + */ +int lfsck_links_get_first(const struct lu_env *env, struct dt_object *obj, + char *name, struct lu_fid *pfid) +{ + struct lu_name *cname = &lfsck_env_info(env)->lti_name; + struct linkea_data ldata = { 0 }; + int rc; + + rc = lfsck_links_read(env, obj, &ldata); + if (rc != 0) + return rc; + + linkea_first_entry(&ldata); + if (ldata.ld_lee == NULL) + return -ENODATA; + + linkea_entry_unpack(ldata.ld_lee, &ldata.ld_reclen, cname, pfid); + /* To guarantee the 'name' is terminated with '0'. */ + memcpy(name, cname->ln_name, cname->ln_namelen); + name[cname->ln_namelen] = 0; + + return 0; +} + +/** + * Remove the name entry from the parent directory. + * + * No need to care about the object referenced by the name entry, + * either the name entry is invalid or redundant, or the referenced + * object has been processed has been or will be handled by others. + * + * \param[in] env pointer to the thread context + * \param[in] lfsck pointer to the lfsck instance + * \param[in] parent pointer to the lost+found object + * \param[in] name the name for the name entry to be removed + * \param[in] type the type for the name entry to be removed + * + * \retval 0 for success + * \retval negative error number on failure + */ +int lfsck_remove_name_entry(const struct lu_env *env, + struct lfsck_instance *lfsck, + struct dt_object *parent, + const char *name, __u32 type) +{ + struct dt_device *dev = lfsck->li_next; + struct thandle *th; + struct lustre_handle lh = { 0 }; + int rc; + ENTRY; + + rc = lfsck_ibits_lock(env, lfsck, parent, &lh, + MDS_INODELOCK_UPDATE, LCK_EX); + if (rc != 0) + RETURN(rc); + + th = dt_trans_create(env, dev); + if (IS_ERR(th)) + GOTO(unlock, rc = PTR_ERR(th)); + + rc = dt_declare_delete(env, parent, (const struct dt_key *)name, th); + if (rc != 0) + GOTO(stop, rc); + + if (S_ISDIR(type)) { + rc = dt_declare_ref_del(env, parent, th); + if (rc != 0) + GOTO(stop, rc); + } + + rc = dt_trans_start(env, dev, th); + if (rc != 0) + GOTO(stop, rc); + + rc = dt_delete(env, parent, (const struct dt_key *)name, th, + BYPASS_CAPA); + if (rc != 0) + GOTO(stop, rc); + + if (S_ISDIR(type)) { + dt_write_lock(env, parent, 0); + rc = dt_ref_del(env, parent, th); + dt_write_unlock(env, parent); + } + + GOTO(stop, rc); + +stop: + dt_trans_stop(env, dev, th); + +unlock: + lfsck_ibits_unlock(&lh, LCK_EX); + + CDEBUG(D_LFSCK, "%s: remove name entry "DFID"/%s " + "with type %o: rc = %d\n", lfsck_lfsck2name(lfsck), + PFID(lfsck_dto2fid(parent)), name, type, rc); + + return rc; +} + +/** + * Update the object's name entry with the given FID. + * + * \param[in] env pointer to the thread context + * \param[in] lfsck pointer to the lfsck instance + * \param[in] parent pointer to the parent directory that holds + * the name entry + * \param[in] name the name for the entry to be updated + * \param[in] pfid the new PFID for the name entry + * \param[in] type the type for the name entry to be updated + * + * \retval 0 for success + * \retval negative error number on failure + */ +int lfsck_update_name_entry(const struct lu_env *env, + struct lfsck_instance *lfsck, + struct dt_object *parent, const char *name, + const struct lu_fid *pfid, __u32 type) +{ + struct dt_insert_rec *rec = &lfsck_env_info(env)->lti_dt_rec; + struct dt_device *dev = lfsck->li_next; + struct lustre_handle lh = { 0 }; + struct thandle *th; + int rc; + bool exists = true; + ENTRY; + + rc = lfsck_ibits_lock(env, lfsck, parent, &lh, + MDS_INODELOCK_UPDATE, LCK_EX); + if (rc != 0) + RETURN(rc); + + th = dt_trans_create(env, dev); + if (IS_ERR(th)) + GOTO(unlock, rc = PTR_ERR(th)); + + rc = dt_declare_delete(env, parent, (const struct dt_key *)name, th); + if (rc != 0) + GOTO(stop, rc); + + rec->rec_type = type; + rec->rec_fid = pfid; + rc = dt_declare_insert(env, parent, (const struct dt_rec *)rec, + (const struct dt_key *)name, th); + if (rc != 0) + GOTO(stop, rc); + + rc = dt_declare_ref_add(env, parent, th); + if (rc != 0) + GOTO(stop, rc); + + rc = dt_trans_start(env, dev, th); + if (rc != 0) + GOTO(stop, rc); + + rc = dt_delete(env, parent, (const struct dt_key *)name, th, + BYPASS_CAPA); + if (rc == -ENOENT) { + exists = false; + rc = 0; + } + + if (rc != 0) + GOTO(stop, rc); + + rc = dt_insert(env, parent, (const struct dt_rec *)rec, + (const struct dt_key *)name, th, BYPASS_CAPA, 1); + if (rc == 0 && S_ISDIR(type) && !exists) { + dt_write_lock(env, parent, 0); + rc = dt_ref_add(env, parent, th); + dt_write_unlock(env, parent); + } + + GOTO(stop, rc); + +stop: + dt_trans_stop(env, dev, th); + +unlock: + lfsck_ibits_unlock(&lh, LCK_EX); + + CDEBUG(D_LFSCK, "%s: update name entry "DFID"/%s with the FID "DFID + " and the type %o: rc = %d\n", lfsck_lfsck2name(lfsck), + PFID(lfsck_dto2fid(parent)), name, PFID(pfid), type, rc); + + return rc; +} + int lfsck_namespace_setup(const struct lu_env *env, struct lfsck_instance *lfsck) { diff --git a/lustre/mdt/mdt_reint.c b/lustre/mdt/mdt_reint.c index d2c36c2..1f79e2c 100644 --- a/lustre/mdt/mdt_reint.c +++ b/lustre/mdt/mdt_reint.c @@ -1978,8 +1978,8 @@ static int mdt_reint_rename_or_migrate(struct mdt_thread_info *info, if (info->mti_dlm_req) ldlm_request_cancel(req, info->mti_dlm_req, 0); - if (fid_is_obf(rr->rr_fid1) || fid_is_dot_lustre(rr->rr_fid1) || - fid_is_obf(rr->rr_fid2) || fid_is_dot_lustre(rr->rr_fid2)) + if (!fid_is_md_operative(rr->rr_fid1) || + !fid_is_md_operative(rr->rr_fid2)) RETURN(-EPERM); rc = mdt_rename_lock(info, &rename_lh, rename_lock); diff --git a/lustre/tests/sanity-lfsck.sh b/lustre/tests/sanity-lfsck.sh index 796a556..ffe205a 100644 --- a/lustre/tests/sanity-lfsck.sh +++ b/lustre/tests/sanity-lfsck.sh @@ -127,7 +127,7 @@ test_0() { do_facet $SINGLEMDS $LCTL set_param fail_loc=0 fail_val=0 wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_namespace | - awk '/^status/ { print \\\$2 }'" "completed" 6 || { + awk '/^status/ { print \\\$2 }'" "completed" 32 || { $SHOW_NAMESPACE error "(9) unexpected status" } @@ -141,7 +141,7 @@ test_0() { $START_NAMESPACE -r || error "(11) Fail to reset LFSCK!" wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_namespace | - awk '/^status/ { print \\\$2 }'" "completed" 6 || { + awk '/^status/ { print \\\$2 }'" "completed" 32 || { $SHOW_NAMESPACE error "(12) unexpected status" } @@ -170,7 +170,7 @@ test_1a() { $START_NAMESPACE -r || error "(3) Fail to start LFSCK for namespace!" wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_namespace | - awk '/^status/ { print \\\$2 }'" "completed" 6 || { + awk '/^status/ { print \\\$2 }'" "completed" 32 || { $SHOW_NAMESPACE error "(4) unexpected status" } @@ -213,7 +213,7 @@ test_1b() $START_NAMESPACE -r || error "(3) Fail to start LFSCK for namespace!" wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_namespace | - awk '/^status/ { print \\\$2 }'" "completed" 6 || { + awk '/^status/ { print \\\$2 }'" "completed" 32 || { $SHOW_NAMESPACE error "(4) unexpected status" } @@ -251,7 +251,7 @@ test_2a() { $START_NAMESPACE -r || error "(3) Fail to start LFSCK for namespace!" wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_namespace | - awk '/^status/ { print \\\$2 }'" "completed" 6 || { + awk '/^status/ { print \\\$2 }'" "completed" 32 || { $SHOW_NAMESPACE error "(4) unexpected status" } @@ -291,7 +291,7 @@ test_2b() $START_NAMESPACE -r || error "(3) Fail to start LFSCK for namespace!" wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_namespace | - awk '/^status/ { print \\\$2 }'" "completed" 6 || { + awk '/^status/ { print \\\$2 }'" "completed" 32 || { $SHOW_NAMESPACE error "(4) unexpected status" } @@ -326,7 +326,7 @@ test_2c() $START_NAMESPACE -r || error "(3) Fail to start LFSCK for namespace!" wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_namespace | - awk '/^status/ { print \\\$2 }'" "completed" 6 || { + awk '/^status/ { print \\\$2 }'" "completed" 32 || { $SHOW_NAMESPACE error "(4) unexpected status" } @@ -367,7 +367,7 @@ test_4() $START_NAMESPACE -r || error "(4) Fail to start LFSCK for namespace!" wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_namespace | - awk '/^flags/ { print \\\$2 }'" "inconsistent" 6 || { + awk '/^flags/ { print \\\$2 }'" "inconsistent" 32 || { $SHOW_NAMESPACE error "(5) unexpected status" } @@ -379,7 +379,7 @@ test_4() do_facet $SINGLEMDS $LCTL set_param fail_loc=0 fail_val=0 wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_namespace | - awk '/^status/ { print \\\$2 }'" "completed" 6 || { + awk '/^status/ { print \\\$2 }'" "completed" 32 || { $SHOW_NAMESPACE error "(7) unexpected status" } @@ -425,7 +425,7 @@ test_5() $START_NAMESPACE -r || error "(4) Fail to start LFSCK for namespace!" wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_namespace | - awk '/^flags/ { print \\\$2 }'" "inconsistent,upgrade" 6 || { + awk '/^flags/ { print \\\$2 }'" "inconsistent,upgrade" 32 || { $SHOW_NAMESPACE error "(5) unexpected status" } @@ -437,7 +437,7 @@ test_5() do_facet $SINGLEMDS $LCTL set_param fail_loc=0 fail_val=0 wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_namespace | - awk '/^status/ { print \\\$2 }'" "completed" 6 || { + awk '/^status/ { print \\\$2 }'" "completed" 32 || { $SHOW_NAMESPACE error "(7) unexpected status" } @@ -489,7 +489,7 @@ test_6a() { do_facet $SINGLEMDS $LCTL set_param fail_loc=0x80001608 wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_namespace | - awk '/^status/ { print \\\$2 }'" "failed" 6 || { + awk '/^status/ { print \\\$2 }'" "failed" 32 || { $SHOW_NAMESPACE error "(4) unexpected status" } @@ -515,7 +515,7 @@ test_6a() { do_facet $SINGLEMDS $LCTL set_param fail_loc=0 fail_val=0 wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_namespace | - awk '/^status/ { print \\\$2 }'" "completed" 6 || { + awk '/^status/ { print \\\$2 }'" "completed" 32 || { $SHOW_NAMESPACE error "(8) unexpected status" } @@ -540,7 +540,7 @@ test_6b() { do_facet $SINGLEMDS $LCTL set_param fail_loc=0x80001609 wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_namespace | - awk '/^status/ { print \\\$2 }'" "failed" 6 || { + awk '/^status/ { print \\\$2 }'" "failed" 32 || { $SHOW_NAMESPACE error "(4) unexpected status" } @@ -577,7 +577,7 @@ test_6b() { do_facet $SINGLEMDS $LCTL set_param fail_loc=0 fail_val=0 wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_namespace | - awk '/^status/ { print \\\$2 }'" "completed" 6 || { + awk '/^status/ { print \\\$2 }'" "completed" 32 || { $SHOW_NAMESPACE error "(8) unexpected status" } @@ -631,7 +631,7 @@ test_7b() $START_NAMESPACE -r || error "(3) Fail to start LFSCK for namespace!" wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_namespace | - awk '/^status/ { print \\\$2 }'" "scanning-phase2" 6 || { + awk '/^status/ { print \\\$2 }'" "scanning-phase2" 32 || { $SHOW_NAMESPACE error "(4) unexpected status" } @@ -702,7 +702,7 @@ test_8() do_facet $SINGLEMDS $LCTL set_param fail_loc=0x80001609 wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_namespace | - awk '/^status/ { print \\\$2 }'" "failed" 6 || { + awk '/^status/ { print \\\$2 }'" "failed" 32 || { $SHOW_NAMESPACE error "(10) unexpected status" } @@ -789,7 +789,7 @@ test_8() $START_NAMESPACE || error "(21) Fail to start LFSCK for namespace!" wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_namespace | - awk '/^status/ { print \\\$2 }'" "scanning-phase2" 6 || { + awk '/^status/ { print \\\$2 }'" "scanning-phase2" 32 || { $SHOW_NAMESPACE error "(22) unexpected status" } @@ -801,7 +801,7 @@ test_8() do_facet $SINGLEMDS $LCTL set_param fail_loc=0 fail_val=0 wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_namespace | - awk '/^status/ { print \\\$2 }'" "completed" 6 || { + awk '/^status/ { print \\\$2 }'" "completed" 32 || { $SHOW_NAMESPACE error "(24) unexpected status" } @@ -949,7 +949,7 @@ test_9b() { $LCTL set_param -n mdd.${MDT_DEV}.lfsck_speed_limit 0 wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_namespace | - awk '/^status/ { print \\\$2 }'" "completed" 6 || { + awk '/^status/ { print \\\$2 }'" "completed" 32 || { $SHOW_NAMESPACE error "(11) unexpected status" } @@ -1022,7 +1022,7 @@ test_10() $LCTL set_param -n mdd.${MDT_DEV}.lfsck_speed_limit 0 wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_namespace | - awk '/^status/ { print \\\$2 }'" "completed" 6 || { + awk '/^status/ { print \\\$2 }'" "completed" 32 || { $SHOW_NAMESPACE error "(16) unexpected status" } @@ -1075,7 +1075,7 @@ test_11a() { wait_update_facet ost1 "$LCTL get_param -n \ obdfilter.${OST_DEV}.lfsck_layout | - awk '/^status/ { print \\\$2 }'" "completed" 6 || { + awk '/^status/ { print \\\$2 }'" "completed" 32 || { $SHOW_LAYOUT_ON_OST error "(6) unexpected status" } @@ -1124,7 +1124,7 @@ test_11b() { wait_update_facet ost1 "$LCTL get_param -n \ obdfilter.${OST_DEV}.lfsck_layout | - awk '/^status/ { print \\\$2 }'" "completed" 6 || { + awk '/^status/ { print \\\$2 }'" "completed" 32 || { $SHOW_LAYOUT_ON_OST error "(6) unexpected status" } @@ -1267,7 +1267,7 @@ test_13() { wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_layout | - awk '/^status/ { print \\\$2 }'" "completed" 6 || { + awk '/^status/ { print \\\$2 }'" "completed" 32 || { $SHOW_LAYOUT error "(2) unexpected status" } @@ -1312,7 +1312,7 @@ test_14() { wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_layout | - awk '/^status/ { print \\\$2 }'" "completed" 6 || { + awk '/^status/ { print \\\$2 }'" "completed" 32 || { $SHOW_LAYOUT error "(3) unexpected status" } @@ -1330,7 +1330,7 @@ test_14() { wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_layout | - awk '/^status/ { print \\\$2 }'" "completed" 6 || { + awk '/^status/ { print \\\$2 }'" "completed" 32 || { $SHOW_LAYOUT error "(7) unexpected status" } @@ -1340,7 +1340,7 @@ test_14() { echo "'stat' should success after layout LFSCK repairing" wait_update_facet client "stat $DIR/$tdir/guard | - awk '/Size/ { print \\\$2 }'" "0" 6 || { + awk '/Size/ { print \\\$2 }'" "0" 32 || { stat $DIR/$tdir/guard $SHOW_LAYOUT error "(8) unexpected size" @@ -1379,7 +1379,7 @@ test_15a() { wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_layout | - awk '/^status/ { print \\\$2 }'" "completed" 6 || { + awk '/^status/ { print \\\$2 }'" "completed" 32 || { $SHOW_LAYOUT error "(2) unexpected status" } @@ -1418,7 +1418,7 @@ test_15b() { wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_layout | - awk '/^status/ { print \\\$2 }'" "completed" 6 || { + awk '/^status/ { print \\\$2 }'" "completed" 32 || { $SHOW_LAYOUT error "(2) unexpected status" } @@ -1455,7 +1455,7 @@ test_16() { wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_layout | - awk '/^status/ { print \\\$2 }'" "completed" 6 || { + awk '/^status/ { print \\\$2 }'" "completed" 32 || { $SHOW_LAYOUT error "(2) unexpected status" } @@ -1506,7 +1506,7 @@ test_17() { wait_update_facet $SINGLEMDS "$LCTL get_param -n \ mdd.${MDT_DEV}.lfsck_layout | - awk '/^status/ { print \\\$2 }'" "completed" 6 || { + awk '/^status/ { print \\\$2 }'" "completed" 32 || { $SHOW_LAYOUT error "(3) unexpected status" } @@ -1905,7 +1905,7 @@ test_18d() { wait_update_facet mds1 "$LCTL get_param -n \ mdd.$(facet_svc mds1).lfsck_layout | - awk '/^status/ { print \\\$2 }'" "scanning-phase2" 6 || + awk '/^status/ { print \\\$2 }'" "scanning-phase2" 32 || error "(3.0) MDS1 is not the expected 'scanning-phase2'" do_facet $SINGLEMDS $LCTL set_param fail_val=0 fail_loc=0 @@ -1999,7 +1999,7 @@ test_18e() { wait_update_facet mds1 "$LCTL get_param -n \ mdd.$(facet_svc mds1).lfsck_layout | - awk '/^status/ { print \\\$2 }'" "scanning-phase2" 6 || + awk '/^status/ { print \\\$2 }'" "scanning-phase2" 32 || error "(3) MDS1 is not the expected 'scanning-phase2'" # to guarantee all updates are synced. -- 1.8.3.1