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 &&
* 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)
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);
__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,
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);
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))
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;
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) &&
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)
{
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);
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"
}
$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"
}
$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"
}
$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"
}
$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"
}
$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"
}
$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"
}
$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"
}
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"
}
$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"
}
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"
}
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"
}
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"
}
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"
}
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"
}
$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"
}
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"
}
$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"
}
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"
}
$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"
}
$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"
}
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"
}
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"
}
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"
}
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"
}
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"
}
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"
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"
}
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"
}
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"
}
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"
}
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
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.