void linkea_entry_unpack(const struct link_ea_entry *lee, int *reclen, struct lu_name *lname, struct lu_fid *pfid) { *reclen = (lee->lee_reclen[0] << 8) | lee->lee_reclen[1]; memcpy(pfid, &lee->lee_parent_fid, sizeof(*pfid)); fid_be_to_cpu(pfid, pfid); lname->ln_name = lee->lee_name; lname->ln_namelen = *reclen - sizeof(struct link_ea_entry); }
/** get (name+parent_id) for an entry * \param linkno hardlink index * \retval -ENODATA after last link * \retval -ERANGE if namelen is too small */ int Lustre_GetNameParent(const char *path, int linkno, lustre_fid *pfid, char *name, int namelen) { int rc, i, len; char buf[4096]; struct linkea_data ldata = { 0 }; struct lu_buf lb = { 0 }; rc = lgetxattr(path, XATTR_NAME_LINK, buf, sizeof(buf)); if (rc < 0) return -errno; lb.lb_buf = buf; lb.lb_len = sizeof(buf); ldata.ld_buf = &lb; ldata.ld_leh = (struct link_ea_header *)buf; ldata.ld_lee = LINKEA_FIRST_ENTRY(ldata); ldata.ld_reclen = (ldata.ld_lee->lee_reclen[0] << 8) | ldata.ld_lee->lee_reclen[1]; if (linkno >= ldata.ld_leh->leh_reccount) /* beyond last link */ return -ENODATA; for (i = 0; i < linkno; i++) { ldata.ld_lee = LINKEA_NEXT_ENTRY(ldata); ldata.ld_reclen = (ldata.ld_lee->lee_reclen[0] << 8) | ldata.ld_lee->lee_reclen[1]; } memcpy(pfid, &ldata.ld_lee->lee_parent_fid, sizeof(*pfid)); fid_be_to_cpu(pfid, pfid); if (!fid_is_sane(pfid)) { DisplayLog(LVL_MAJOR, __func__, "insane fid: "DFID, PFID(pfid)); return -EPROTO; } len = ldata.ld_reclen - sizeof(struct link_ea_entry); if (len >= namelen) return -ERANGE; strncpy(name, ldata.ld_lee->lee_name, len); name[len] = '\0'; return 0; }
static int osd_find_parent_fid(const struct lu_env *env, struct dt_object *o, struct lu_fid *fid) { struct link_ea_header *leh; struct link_ea_entry *lee; struct lu_buf buf; int rc; ENTRY; buf.lb_buf = osd_oti_get(env)->oti_buf; buf.lb_len = sizeof(osd_oti_get(env)->oti_buf); rc = osd_xattr_get(env, o, &buf, XATTR_NAME_LINK, BYPASS_CAPA); if (rc == -ERANGE) { rc = osd_xattr_get(env, o, &LU_BUF_NULL, XATTR_NAME_LINK, BYPASS_CAPA); if (rc < 0) RETURN(rc); LASSERT(rc > 0); OBD_ALLOC(buf.lb_buf, rc); if (buf.lb_buf == NULL) RETURN(-ENOMEM); buf.lb_len = rc; rc = osd_xattr_get(env, o, &buf, XATTR_NAME_LINK, BYPASS_CAPA); } if (rc < 0) GOTO(out, rc); if (rc < sizeof(*leh) + sizeof(*lee)) GOTO(out, rc = -EINVAL); leh = buf.lb_buf; if (leh->leh_magic == __swab32(LINK_EA_MAGIC)) { leh->leh_magic = LINK_EA_MAGIC; leh->leh_reccount = __swab32(leh->leh_reccount); leh->leh_len = __swab64(leh->leh_len); } if (leh->leh_magic != LINK_EA_MAGIC) GOTO(out, rc = -EINVAL); if (leh->leh_reccount == 0) GOTO(out, rc = -ENODATA); lee = (struct link_ea_entry *)(leh + 1); fid_be_to_cpu(fid, (const struct lu_fid *)&lee->lee_parent_fid); rc = 0; out: if (buf.lb_buf != osd_oti_get(env)->oti_buf) OBD_FREE(buf.lb_buf, buf.lb_len); #if 0 /* this block can be enabled for additional verification * it's trying to match FID from LinkEA vs. FID from LMA */ if (rc == 0) { struct lu_fid fid2; int rc2; rc2 = osd_find_parent_by_dnode(env, o, &fid2); if (rc2 == 0) if (lu_fid_eq(fid, &fid2) == 0) CERROR("wrong parent: "DFID" != "DFID"\n", PFID(fid), PFID(&fid2)); } #endif /* no LinkEA is found, let's try to find the fid in parent's LMA */ if (unlikely(rc != 0)) rc = osd_find_parent_by_dnode(env, o, fid); RETURN(rc); }
int decode_linkea(const char *fname) { char buf[BUFFER_SIZE]; struct link_ea_header *leh; ssize_t size; struct link_ea_entry *lee; int i; __u64 length; int reclen; struct lu_fid pfid; size = getxattr(fname, "trusted.link", buf, BUFFER_SIZE); if (size < 0) { if (errno == ERANGE) { fprintf(stderr, "%s: failed to read trusted.link " "xattr, the buffer size %u might be too " "small\n", fname, BUFFER_SIZE); } else { fprintf(stderr, "%s: failed to read trusted.link xattr: %s\n", fname, strerror(errno)); } return -1; } leh = (struct link_ea_header *)buf; if (leh->leh_magic == __swab32(LINK_EA_MAGIC)) { leh->leh_magic = LINK_EA_MAGIC; leh->leh_reccount = __swab32(leh->leh_reccount); leh->leh_len = __swab64(leh->leh_len); } if (leh->leh_magic != LINK_EA_MAGIC) { fprintf(stderr, "%s: magic mismatch, expected 0x%lx, got 0x%x\n", fname, LINK_EA_MAGIC, leh->leh_magic); return -1; } if (leh->leh_reccount == 0) { fprintf(stderr, "%s: empty record count\n", fname); return -1; } if (leh->leh_len > size) { fprintf(stderr, "%s: invalid length %llu, should smaller than %zd\n", fname, leh->leh_len, size); return -1; } length = sizeof(struct link_ea_header); lee = (struct link_ea_entry *)(leh + 1); printf("%s: count %u\n", fname, leh->leh_reccount); for (i = 0; i < leh->leh_reccount; i++) { reclen = (lee->lee_reclen[0] << 8) | lee->lee_reclen[1]; length += reclen; if (length > leh->leh_len) { fprintf(stderr, "%s: length exceeded, expected %lld, got %lld\n", fname, leh->leh_len, length); return -1; } memcpy(&pfid, &lee->lee_parent_fid, sizeof(pfid)); fid_be_to_cpu(&pfid, &pfid); printf(" %d: pfid "DFID", name '%s'\n", i, PFID(&pfid), lee->lee_name); lee = (struct link_ea_entry *)((char *)lee + reclen); } if (length != leh->leh_len) { fprintf(stderr, "%s: length mismatch, expected %lld, got %lld\n", fname, leh->leh_len, length); return -1; } return 0; }
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; }