int linkea_links_new(struct linkea_data *ldata, struct lu_buf *buf, const struct lu_name *cname, const struct lu_fid *pfid) { int rc; rc = linkea_data_new(ldata, buf); if (!rc) rc = linkea_add_buf(ldata, cname, pfid); return rc; }
static int lfsck_namespace_exec_dir(const struct lu_env *env, struct lfsck_component *com, struct dt_object *obj, struct lu_dirent *ent) { struct lfsck_thread_info *info = lfsck_env_info(env); struct lu_attr *la = &info->lti_la; 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 }; const struct lu_fid *pfid = lfsck_dto2fid(lfsck->li_obj_dir); const struct lu_fid *cfid = lfsck_dto2fid(obj); const struct lu_name *cname; struct thandle *handle = NULL; bool repaired = false; bool locked = false; bool remove; bool newdata; int count = 0; int rc; ENTRY; cname = lfsck_name_get_const(env, ent->lde_name, ent->lde_namelen); down_write(&com->lc_sem); com->lc_new_checked++; if (ent->lde_attrs & LUDA_UPGRADE) { ns->ln_flags |= LF_UPGRADE; repaired = true; } else if (ent->lde_attrs & LUDA_REPAIR) { ns->ln_flags |= LF_INCONSISTENT; repaired = true; } if (ent->lde_name[0] == '.' && (ent->lde_namelen == 1 || (ent->lde_namelen == 2 && ent->lde_name[1] == '.') || fid_is_dot_lustre(&ent->lde_fid))) GOTO(out, rc = 0); if (!(bk->lb_param & LPF_DRYRUN) && (com->lc_journal || repaired)) { again: LASSERT(!locked); com->lc_journal = 1; handle = dt_trans_create(env, lfsck->li_next); if (IS_ERR(handle)) GOTO(out, rc = PTR_ERR(handle)); rc = lfsck_declare_namespace_exec_dir(env, obj, 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, obj, MOR_TGT_CHILD); locked = true; } rc = lfsck_namespace_check_exist(env, lfsck, obj, ent->lde_name); if (rc != 0) GOTO(stop, rc); rc = lfsck_links_read(env, obj, &ldata); if (rc == 0) { count = ldata.ld_leh->leh_reccount; rc = linkea_links_find(&ldata, cname, pfid); if ((rc == 0) && (count == 1 || !S_ISDIR(lfsck_object_type(obj)))) goto record; ns->ln_flags |= LF_INCONSISTENT; /* For dir, if there are more than one linkea entries, or the * linkea entry does not match the name entry, then remove all * and add the correct one. */ if (S_ISDIR(lfsck_object_type(obj))) { remove = true; newdata = true; } else { remove = false; newdata = false; } goto nodata; } else if (unlikely(rc == -EINVAL)) { count = 1; ns->ln_flags |= LF_INCONSISTENT; /* The magic crashed, we are not sure whether there are more * corrupt data in the linkea, so remove all linkea entries. */ remove = true; newdata = true; goto nodata; } else if (rc == -ENODATA) { count = 1; ns->ln_flags |= LF_UPGRADE; remove = false; newdata = true; nodata: if (bk->lb_param & LPF_DRYRUN) { repaired = true; goto record; } if (!com->lc_journal) goto again; if (remove) { LASSERT(newdata); rc = dt_xattr_del(env, obj, XATTR_NAME_LINK, handle, BYPASS_CAPA); if (rc != 0) GOTO(stop, rc); } if (newdata) { rc = linkea_data_new(&ldata, &lfsck_env_info(env)->lti_linkea_buf); if (rc != 0) GOTO(stop, rc); } rc = linkea_add_buf(&ldata, cname, pfid); if (rc != 0) GOTO(stop, rc); rc = lfsck_links_write(env, obj, &ldata, handle); if (rc != 0) GOTO(stop, rc); count = ldata.ld_leh->leh_reccount; repaired = true; } else { GOTO(stop, rc); } record: LASSERT(count > 0); rc = dt_attr_get(env, obj, la, BYPASS_CAPA); if (rc != 0) GOTO(stop, rc); if ((count == 1) && (la->la_nlink == 1 || S_ISDIR(lfsck_object_type(obj)))) /* Usually, it is for single linked object or dir, do nothing.*/ GOTO(stop, rc); /* Following modification will be in another transaction. */ if (handle != NULL) { LASSERT(dt_write_locked(env, obj)); dt_write_unlock(env, obj); locked = false; dt_trans_stop(env, lfsck->li_next, handle); handle = NULL; } ns->ln_mlinked_checked++; rc = lfsck_namespace_update(env, com, cfid, count != la->la_nlink ? LLF_UNMATCH_NLINKS : 0, false); GOTO(out, rc); stop: if (locked) dt_write_unlock(env, obj); if (handle != NULL) dt_trans_stop(env, lfsck->li_next, handle); out: if (rc < 0) { ns->ln_items_failed++; if (lfsck_pos_is_zero(&ns->ln_pos_first_inconsistent)) lfsck_pos_fill(env, lfsck, &ns->ln_pos_first_inconsistent, false); if (!(bk->lb_param & LPF_FAILOUT)) rc = 0; } else { if (repaired) { ns->ln_items_repaired++; if (bk->lb_param & LPF_DRYRUN && lfsck_pos_is_zero(&ns->ln_pos_first_inconsistent)) lfsck_pos_fill(env, lfsck, &ns->ln_pos_first_inconsistent, false); } else { com->lc_journal = 0; } rc = 0; } up_write(&com->lc_sem); return rc; }