+/**
+ * Repair dangling name entry.
+ *
+ * For the name entry with dangling reference, we need to repare the
+ * inconsistency according to the LFSCK sponsor's requirement:
+ *
+ * 1) Keep the inconsistency there and report the inconsistency case,
+ * then give the chance to the application to find related issues,
+ * and the users can make the decision about how to handle it with
+ * more human knownledge. (by default)
+ *
+ * 2) Re-create the missed MDT-object with the FID information.
+ *
+ * \param[in] env pointer to the thread context
+ * \param[in] com pointer to the lfsck component
+ * \param[in] child pointer to the object corresponding to the dangling
+ * name entry
+ * \param[in] lnr pointer to the namespace request that contains the
+ * name's name, parent object, parent's LMV, and ect.
+ *
+ * \retval positive number if no need to repair
+ * \retval zero for repaired successfully
+ * \retval negative error number on failure
+ */
+int lfsck_namespace_repair_dangling(const struct lu_env *env,
+ struct lfsck_component *com,
+ struct dt_object *child,
+ struct lfsck_namespace_req *lnr)
+{
+ struct lfsck_thread_info *info = lfsck_env_info(env);
+ struct lu_attr *la = &info->lti_la;
+ struct dt_allocation_hint *hint = &info->lti_hint;
+ struct dt_object_format *dof = &info->lti_dof;
+ struct dt_insert_rec *rec = &info->lti_dt_rec;
+ struct dt_object *parent = lnr->lnr_obj;
+ const struct lu_name *cname;
+ struct linkea_data ldata = { 0 };
+ struct lustre_handle lh = { 0 };
+ struct lu_buf linkea_buf;
+ struct lfsck_instance *lfsck = com->lc_lfsck;
+ struct lfsck_bookmark *bk = &lfsck->li_bookmark_ram;
+ struct dt_device *dev = lfsck_obj2dt_dev(child);
+ struct thandle *th = NULL;
+ int rc = 0;
+ __u16 type = lnr->lnr_type;
+ bool create;
+ ENTRY;
+
+ cname = lfsck_name_get_const(env, lnr->lnr_name, lnr->lnr_namelen);
+ if (bk->lb_param & LPF_CREATE_MDTOBJ)
+ create = true;
+ else
+ create = false;
+
+ if (!create || bk->lb_param & LPF_DRYRUN)
+ GOTO(log, rc = 0);
+
+ rc = linkea_data_new(&ldata, &info->lti_linkea_buf2);
+ if (rc != 0)
+ GOTO(log, rc);
+
+ rc = linkea_add_buf(&ldata, cname, lfsck_dto2fid(parent));
+ if (rc != 0)
+ GOTO(log, rc);
+
+ rc = lfsck_ibits_lock(env, lfsck, parent, &lh,
+ MDS_INODELOCK_UPDATE, LCK_EX);
+ if (rc != 0)
+ GOTO(log, rc);
+
+ rc = lfsck_namespace_check_exist(env, parent, child, lnr->lnr_name);
+ if (rc != 0)
+ GOTO(log, rc);
+
+ th = dt_trans_create(env, dev);
+ if (IS_ERR(th))
+ GOTO(log, rc = PTR_ERR(th));
+
+ /* Set the ctime as zero, then others can know it is created for
+ * repairing dangling name entry by LFSCK. And if the LFSCK made
+ * wrong decision and the real MDT-object has been found later,
+ * then the LFSCK has chance to fix the incosistency properly. */
+ memset(la, 0, sizeof(*la));
+ la->la_mode = (type & S_IFMT) | 0600;
+ la->la_valid = LA_TYPE | LA_MODE | LA_UID | LA_GID |
+ LA_ATIME | LA_MTIME | LA_CTIME;
+
+ child->do_ops->do_ah_init(env, hint, parent, child,
+ la->la_mode & S_IFMT);
+
+ memset(dof, 0, sizeof(*dof));
+ dof->dof_type = dt_mode_to_dft(type);
+ /* If the target is a regular file, then the LFSCK will only create
+ * the MDT-object without stripes (dof->dof_reg.striped = 0). related
+ * OST-objects will be created when write open. */
+
+ /* 1a. create child. */
+ rc = dt_declare_create(env, child, la, hint, dof, th);
+ if (rc != 0)
+ GOTO(stop, rc);
+
+ if (S_ISDIR(type)) {
+ if (unlikely(!dt_try_as_dir(env, child)))
+ GOTO(stop, rc = -ENOTDIR);
+
+ /* 2a. insert dot into child dir */
+ rec->rec_type = S_IFDIR;
+ rec->rec_fid = lfsck_dto2fid(child);
+ rc = dt_declare_insert(env, child,
+ (const struct dt_rec *)rec,
+ (const struct dt_key *)dot, th);
+ if (rc != 0)
+ GOTO(stop, rc);
+
+ /* 3a. insert dotdot into child dir */
+ rec->rec_fid = lfsck_dto2fid(parent);
+ rc = dt_declare_insert(env, child,
+ (const struct dt_rec *)rec,
+ (const struct dt_key *)dotdot, th);
+ if (rc != 0)
+ GOTO(stop, rc);
+
+ /* 4a. increase child nlink */
+ rc = dt_declare_ref_add(env, child, th);
+ if (rc != 0)
+ GOTO(stop, rc);
+ }
+
+ /* 5a. insert linkEA for child */
+ lfsck_buf_init(&linkea_buf, ldata.ld_buf->lb_buf,
+ ldata.ld_leh->leh_len);
+ rc = dt_declare_xattr_set(env, child, &linkea_buf,
+ XATTR_NAME_LINK, 0, th);
+ if (rc != 0)
+ GOTO(stop, rc);
+
+ rc = dt_trans_start(env, dev, th);
+ if (rc != 0)
+ GOTO(stop, rc = (rc == -EEXIST ? 1 : rc));
+
+ dt_write_lock(env, child, 0);
+ /* 1b. create child */
+ rc = dt_create(env, child, la, hint, dof, th);
+ if (rc != 0)
+ GOTO(unlock, rc = (rc == -EEXIST ? 1 : rc));
+
+ if (S_ISDIR(type)) {
+ if (unlikely(!dt_try_as_dir(env, child)))
+ GOTO(unlock, rc = -ENOTDIR);
+
+ /* 2b. insert dot into child dir */
+ rec->rec_type = S_IFDIR;
+ rec->rec_fid = lfsck_dto2fid(child);
+ rc = dt_insert(env, child, (const struct dt_rec *)rec,
+ (const struct dt_key *)dot, th, BYPASS_CAPA, 1);
+ if (rc != 0)
+ GOTO(unlock, rc);
+
+ /* 3b. insert dotdot into child dir */
+ rec->rec_fid = lfsck_dto2fid(parent);
+ rc = dt_insert(env, child, (const struct dt_rec *)rec,
+ (const struct dt_key *)dotdot, th,
+ BYPASS_CAPA, 1);
+ if (rc != 0)
+ GOTO(unlock, rc);
+
+ /* 4b. increase child nlink */
+ rc = dt_ref_add(env, child, th);
+ if (rc != 0)
+ GOTO(unlock, rc);
+ }
+
+ /* 5b. insert linkEA for child. */
+ rc = dt_xattr_set(env, child, &linkea_buf,
+ XATTR_NAME_LINK, 0, th, BYPASS_CAPA);
+
+ GOTO(unlock, rc);
+
+unlock:
+ dt_write_unlock(env, child);
+
+stop:
+ dt_trans_stop(env, dev, th);
+
+log:
+ lfsck_ibits_unlock(&lh, LCK_EX);
+ CDEBUG(D_LFSCK, "%s: namespace LFSCK assistant found dangling "
+ "reference for: parent "DFID", child "DFID", type %u, "
+ "name %s. %s: rc = %d\n", lfsck_lfsck2name(lfsck),
+ PFID(lfsck_dto2fid(parent)), PFID(lfsck_dto2fid(child)),
+ type, cname->ln_name,
+ create ? "Create the lost OST-object as required" :
+ "Keep the MDT-object there by default", rc);
+
+ if (rc <= 0) {
+ struct lfsck_namespace *ns = com->lc_file_ram;
+
+ ns->ln_flags |= LF_INCONSISTENT;
+ }
+
+ return rc;
+}
+