static int lfsck_namespace_check_exist(const struct lu_env *env, struct lfsck_instance *lfsck, struct dt_object *obj, const char *name) { struct dt_object *dir = lfsck->li_obj_dir; struct lu_fid *fid = &lfsck_env_info(env)->lti_fid; int rc; ENTRY; if (unlikely(lfsck_is_dead_obj(obj))) RETURN(LFSCK_NAMEENTRY_DEAD); rc = dt_lookup(env, dir, (struct dt_rec *)fid, (const struct dt_key *)name, BYPASS_CAPA); if (rc == -ENOENT) RETURN(LFSCK_NAMEENTRY_REMOVED); if (rc < 0) RETURN(rc); if (!lu_fid_eq(fid, lfsck_dto2fid(obj))) RETURN(LFSCK_NAMEENTRY_RECREATED); RETURN(0); }
/* * Write a global record * * \param env - is the environment passed by the caller * \param obj - is the on-disk global index to be updated * \param id - index to be updated * \param rec - record to be written */ int lquota_disk_write_glb(const struct lu_env *env, struct dt_object *obj, __u64 id, struct lquota_glb_rec *rec) { struct dt_device *dev = lu2dt_dev(obj->do_lu.lo_dev); struct thandle *th; struct dt_key *key = (struct dt_key *)&id; int rc; ENTRY; th = dt_trans_create(env, dev); if (IS_ERR(th)) RETURN(PTR_ERR(th)); /* the entry with 0 key can always be found in IAM file. */ if (id == 0) { rc = dt_declare_delete(env, obj, key, th); if (rc) GOTO(out, rc); } rc = dt_declare_insert(env, obj, (struct dt_rec *)rec, key, th); if (rc) GOTO(out, rc); rc = dt_trans_start_local(env, dev, th); if (rc) GOTO(out, rc); dt_write_lock(env, obj, 0); if (id == 0) { struct lquota_glb_rec *tmp; OBD_ALLOC_PTR(tmp); if (tmp == NULL) GOTO(out_lock, rc = -ENOMEM); rc = dt_lookup(env, obj, (struct dt_rec *)tmp, key, BYPASS_CAPA); OBD_FREE_PTR(tmp); if (rc == 0) { rc = dt_delete(env, obj, key, th, BYPASS_CAPA); if (rc) GOTO(out_lock, rc); } rc = 0; } rc = dt_insert(env, obj, (struct dt_rec *)rec, key, th, BYPASS_CAPA, 1); out_lock: dt_write_unlock(env, obj); out: dt_trans_stop(env, dev, th); RETURN(rc); }
static int out_index_lookup(struct tgt_session_info *tsi) { const struct lu_env *env = tsi->tsi_env; struct tgt_thread_info *tti = tgt_th_info(env); struct object_update *update = tti->tti_u.update.tti_update; struct dt_object *obj = tti->tti_u.update.tti_dt_object; char *name; int rc; ENTRY; if (unlikely(update->ou_result_size < sizeof(tti->tti_fid1))) return -EPROTO; if (!lu_object_exists(&obj->do_lu)) RETURN(-ENOENT); name = object_update_param_get(update, 0, NULL); if (IS_ERR(name)) { CERROR("%s: empty name for lookup: rc = %ld\n", tgt_name(tsi->tsi_tgt), PTR_ERR(name)); RETURN(PTR_ERR(name)); } dt_read_lock(env, obj, MOR_TGT_CHILD); if (!dt_try_as_dir(env, obj)) GOTO(out_unlock, rc = -ENOTDIR); rc = dt_lookup(env, obj, (struct dt_rec *)&tti->tti_fid1, (struct dt_key *)name); if (rc < 0) GOTO(out_unlock, rc); if (rc == 0) rc += 1; out_unlock: dt_read_unlock(env, obj); CDEBUG(D_INFO, "lookup "DFID" %s get "DFID" rc %d\n", PFID(lu_object_fid(&obj->do_lu)), name, PFID(&tti->tti_fid1), rc); CDEBUG(D_INFO, "%s: insert lookup reply %p index %d: rc = %d\n", tgt_name(tsi->tsi_tgt), tti->tti_u.update.tti_update_reply, 0, rc); object_update_result_insert(tti->tti_u.update.tti_update_reply, &tti->tti_fid1, sizeof(tti->tti_fid1), tti->tti_u.update.tti_update_reply_index, rc); RETURN(rc); }
static int lfsck_namespace_lookup(const struct lu_env *env, struct lfsck_component *com, const struct lu_fid *fid, __u8 *flags) { struct lu_fid *key = &lfsck_env_info(env)->lti_fid; int rc; fid_cpu_to_be(key, fid); rc = dt_lookup(env, com->lc_obj, (struct dt_rec *)flags, (const struct dt_key *)key, BYPASS_CAPA); return rc; }
static int out_index_lookup(struct tgt_session_info *tsi) { const struct lu_env *env = tsi->tsi_env; struct tgt_thread_info *tti = tgt_th_info(env); struct update *update = tti->tti_u.update.tti_update; struct dt_object *obj = tti->tti_u.update.tti_dt_object; char *name; int rc; ENTRY; if (!lu_object_exists(&obj->do_lu)) RETURN(-ENOENT); name = (char *)update_param_buf(update, 0, NULL); if (name == NULL) { CERROR("%s: empty name for lookup: rc = %d\n", tgt_name(tsi->tsi_tgt), -EPROTO); RETURN(err_serious(-EPROTO)); } dt_read_lock(env, obj, MOR_TGT_CHILD); if (!dt_try_as_dir(env, obj)) GOTO(out_unlock, rc = -ENOTDIR); rc = dt_lookup(env, obj, (struct dt_rec *)&tti->tti_fid1, (struct dt_key *)name, NULL); if (rc < 0) GOTO(out_unlock, rc); if (rc == 0) rc += 1; CDEBUG(D_INFO, "lookup "DFID" %s get "DFID" rc %d\n", PFID(lu_object_fid(&obj->do_lu)), name, PFID(&tti->tti_fid1), rc); fid_cpu_to_le(&tti->tti_fid1, &tti->tti_fid1); out_unlock: dt_read_unlock(env, obj); CDEBUG(D_INFO, "%s: insert lookup reply %p index %d: rc = %d\n", tgt_name(tsi->tsi_tgt), tti->tti_u.update.tti_update_reply, 0, rc); update_insert_reply(tti->tti_u.update.tti_update_reply, &tti->tti_fid1, sizeof(tti->tti_fid1), 0, rc); RETURN(rc); }
/* * Retrieve quota settings from disk for a particular identifier. * * \param env - is the environment passed by the caller * \param obj - is the on-disk index where quota settings are stored. * \param id - is the key to be updated * \param rec - is the output record where to store quota settings. * * \retval - 0 on success, appropriate error on failure */ int lquota_disk_read(const struct lu_env *env, struct dt_object *obj, union lquota_id *id, struct dt_rec *rec) { int rc; ENTRY; LASSERT(dt_object_exists(obj)); LASSERT(obj->do_index_ops != NULL); /* lookup on-disk record from index file */ dt_read_lock(env, obj, 0); rc = dt_lookup(env, obj, rec, (struct dt_key *)&id->qid_uid); dt_read_unlock(env, obj); RETURN(rc); }
static int out_index_lookup(struct mdt_thread_info *info) { struct update *update = info->mti_u.update.mti_update; const struct lu_env *env = info->mti_env; struct dt_object *obj = info->mti_u.update.mti_dt_object; char *name; int rc; ENTRY; if (!lu_object_exists(&obj->do_lu)) RETURN(-ENOENT); name = (char *)update_param_buf(update, 0, NULL); if (name == NULL) { CERROR("%s: empty name for lookup: rc = %d\n", mdt_obd_name(info->mti_mdt), -EPROTO); RETURN(err_serious(-EPROTO)); } dt_read_lock(env, obj, MOR_TGT_CHILD); if (!dt_try_as_dir(env, obj)) GOTO(out_unlock, rc = -ENOTDIR); rc = dt_lookup(env, obj, (struct dt_rec *)&info->mti_tmp_fid1, (struct dt_key *)name, NULL); if (rc < 0) GOTO(out_unlock, rc); if (rc == 0) rc += 1; CDEBUG(D_INFO, "lookup "DFID" %s get "DFID" rc %d\n", PFID(lu_object_fid(&obj->do_lu)), name, PFID(&info->mti_tmp_fid1), rc); fid_cpu_to_le(&info->mti_tmp_fid1, &info->mti_tmp_fid1); out_unlock: dt_read_unlock(env, obj); update_insert_reply(info->mti_u.update.mti_update_reply, &info->mti_tmp_fid1, sizeof(info->mti_tmp_fid1), 0, rc); RETURN(rc); }
/* * Helper routine to retrieve slave information. * This function converts a quotactl request into quota/accounting object * operations. It is independant of the slave stack which is only accessible * from the OSD layer. * * \param env - is the environment passed by the caller * \param dev - is the dt_device this quotactl is executed on * \param oqctl - is the quotactl request */ int lquotactl_slv(const struct lu_env *env, struct dt_device *dev, struct obd_quotactl *oqctl) { struct lquota_thread_info *qti = lquota_info(env); __u64 key; struct dt_object *obj; struct obd_dqblk *dqblk = &oqctl->qc_dqblk; int rc; ENTRY; if (oqctl->qc_cmd != Q_GETOQUOTA) { /* as in many other places, dev->dd_lu_dev.ld_obd->obd_name * point to an invalid obd_name, to be fixed in LU-1574 */ CERROR("%s: Unsupported quotactl command: %x\n", dev->dd_lu_dev.ld_obd->obd_name, oqctl->qc_cmd); RETURN(-EOPNOTSUPP); } if (oqctl->qc_type < 0 || oqctl->qc_type >= LL_MAXQUOTAS) RETURN(-EOPNOTSUPP); /* qc_id is a 32-bit field while a key has 64 bits */ key = oqctl->qc_id; /* Step 1: collect accounting information */ obj = acct_obj_lookup(env, dev, oqctl->qc_type); if (IS_ERR(obj)) RETURN(-EOPNOTSUPP); if (obj->do_index_ops == NULL) GOTO(out, rc = -EINVAL); /* lookup record storing space accounting information for this ID */ rc = dt_lookup(env, obj, (struct dt_rec *)&qti->qti_acct_rec, (struct dt_key *)&key); if (rc < 0) GOTO(out, rc); memset(&oqctl->qc_dqblk, 0, sizeof(struct obd_dqblk)); dqblk->dqb_curspace = qti->qti_acct_rec.bspace; dqblk->dqb_curinodes = qti->qti_acct_rec.ispace; dqblk->dqb_valid = QIF_USAGE; dt_object_put(env, obj); /* Step 2: collect enforcement information */ obj = quota_obj_lookup(env, dev, oqctl->qc_type); if (IS_ERR(obj)) RETURN(0); if (obj->do_index_ops == NULL) GOTO(out, rc = 0); memset(&qti->qti_slv_rec, 0, sizeof(qti->qti_slv_rec)); /* lookup record storing enforcement information for this ID */ rc = dt_lookup(env, obj, (struct dt_rec *)&qti->qti_slv_rec, (struct dt_key *)&key); if (rc < 0 && rc != -ENOENT) GOTO(out, rc = 0); if (lu_device_is_md(dev->dd_lu_dev.ld_site->ls_top_dev)) { dqblk->dqb_ihardlimit = qti->qti_slv_rec.qsr_granted; dqblk->dqb_bhardlimit = 0; } else { dqblk->dqb_ihardlimit = 0; dqblk->dqb_bhardlimit = qti->qti_slv_rec.qsr_granted; } dqblk->dqb_valid |= QIF_LIMITS; GOTO(out, rc = 0); out: dt_object_put(env, obj); return rc; }
/* * Update a record in a quota index file. * * \param env - is the environment passed by the caller * \param th - is the transaction to use for disk writes * \param obj - is the on-disk index to be updated. * \param id - is the key to be updated * \param rec - is the input record containing the new quota settings. * \param flags - can be LQUOTA_BUMP_VER or LQUOTA_SET_VER. * \param ver - is the new version of the index if LQUOTA_SET_VER is set or is * used to return the new version of the index when * LQUOTA_BUMP_VER is set. * * \retval - 0 on success, appropriate error on failure */ int lquota_disk_write(const struct lu_env *env, struct thandle *th, struct dt_object *obj, union lquota_id *id, struct dt_rec *rec, __u32 flags, __u64 *ver) { struct lquota_thread_info *qti = lquota_info(env); struct dt_key *key = (struct dt_key *)&id->qid_uid; int rc; ENTRY; LASSERT(dt_object_exists(obj)); LASSERT(obj->do_index_ops != NULL); /* lock index */ dt_write_lock(env, obj, 0); /* check whether there is already an existing record for this ID */ rc = dt_lookup(env, obj, (struct dt_rec *)&qti->qti_rec, key, BYPASS_CAPA); if (rc == 0) { /* delete existing record in order to replace it */ rc = dt_delete(env, obj, key, th, BYPASS_CAPA); if (rc) GOTO(out, rc); } else if (rc == -ENOENT) { /* probably first insert */ rc = 0; } else { GOTO(out, rc); } if (rec != NULL) { /* insert record with updated quota settings */ rc = dt_insert(env, obj, rec, key, th, BYPASS_CAPA, 1); if (rc) { /* try to insert the old one */ rc = dt_insert(env, obj, (struct dt_rec *)&qti->qti_rec, key, th, BYPASS_CAPA, 1); LASSERTF(rc == 0, "failed to insert record in quota " "index "DFID, PFID(lu_object_fid(&obj->do_lu))); GOTO(out, rc); } } if (flags != 0) { LASSERT(ver); if (flags & LQUOTA_BUMP_VER) { /* caller wants to bump the version, let's first read * it */ *ver = dt_version_get(env, obj); (*ver)++; } else { LASSERT(flags & LQUOTA_SET_VER); } dt_version_set(env, obj, *ver, th); } EXIT; out: dt_write_unlock(env, obj); return rc; }
/** * \retval +ve repaired * \retval 0 no need to repair * \retval -ve error cases */ static int lfsck_namespace_double_scan_one(const struct lu_env *env, struct lfsck_component *com, struct dt_object *child, __u8 flags) { struct lfsck_thread_info *info = lfsck_env_info(env); struct lu_attr *la = &info->lti_la; struct lu_name *cname = &info->lti_name; struct lu_fid *pfid = &info->lti_fid; struct lu_fid *cfid = &info->lti_fid2; 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 }; struct thandle *handle = NULL; bool locked = false; bool update = false; int rc; ENTRY; if (com->lc_journal) { again: LASSERT(!locked); update = false; com->lc_journal = 1; handle = dt_trans_create(env, lfsck->li_next); if (IS_ERR(handle)) RETURN(rc = PTR_ERR(handle)); rc = dt_declare_xattr_set(env, child, lfsck_buf_get_const(env, NULL, DEFAULT_LINKEA_SIZE), XATTR_NAME_LINK, 0, 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, child, MOR_TGT_CHILD); locked = true; } if (unlikely(lfsck_is_dead_obj(child))) GOTO(stop, rc = 0); rc = dt_attr_get(env, child, la, BYPASS_CAPA); if (rc == 0) rc = lfsck_links_read(env, child, &ldata); if (rc != 0) { if ((bk->lb_param & LPF_DRYRUN) && (rc == -EINVAL || rc == -ENODATA)) rc = 1; GOTO(stop, rc); } linkea_first_entry(&ldata); while (ldata.ld_lee != NULL) { struct dt_object *parent = NULL; rc = lfsck_linkea_entry_unpack(lfsck, &ldata, cname, pfid); if (rc > 0) update = true; if (!fid_is_sane(pfid)) goto shrink; parent = lfsck_object_find(env, lfsck, pfid); if (parent == NULL) goto shrink; else if (IS_ERR(parent)) GOTO(stop, rc = PTR_ERR(parent)); if (!dt_object_exists(parent)) goto shrink; /* XXX: Currently, skip remote object, the consistency for * remote object will be processed in LFSCK phase III. */ if (dt_object_remote(parent)) { lfsck_object_put(env, parent); linkea_next_entry(&ldata); continue; } if (unlikely(!dt_try_as_dir(env, parent))) goto shrink; /* To guarantee the 'name' is terminated with '0'. */ memcpy(info->lti_key, cname->ln_name, cname->ln_namelen); info->lti_key[cname->ln_namelen] = 0; cname->ln_name = info->lti_key; rc = dt_lookup(env, parent, (struct dt_rec *)cfid, (const struct dt_key *)cname->ln_name, BYPASS_CAPA); if (rc != 0 && rc != -ENOENT) { lfsck_object_put(env, parent); GOTO(stop, rc); } if (rc == 0) { if (lu_fid_eq(cfid, lfsck_dto2fid(child))) { lfsck_object_put(env, parent); linkea_next_entry(&ldata); continue; } goto shrink; } /* If there is no name entry in the parent dir and the object * link count is less than the linkea entries count, then the * linkea entry should be removed. */ if (ldata.ld_leh->leh_reccount > la->la_nlink) goto shrink; /* XXX: For the case of there is a linkea entry, but without * name entry pointing to the object and its hard links * count is not less than the object name entries count, * then seems we should add the 'missed' name entry back * to namespace, but before LFSCK phase III finished, we * do not know whether the object has some inconsistency * on other MDTs. So now, do NOT add the name entry back * to the namespace, but keep the linkEA entry. LU-2914 */ lfsck_object_put(env, parent); linkea_next_entry(&ldata); continue; shrink: if (parent != NULL) lfsck_object_put(env, parent); if (bk->lb_param & LPF_DRYRUN) RETURN(1); CDEBUG(D_LFSCK, "Remove linkEA: "DFID"[%.*s], "DFID"\n", PFID(lfsck_dto2fid(child)), cname->ln_namelen, cname->ln_name, PFID(pfid)); linkea_del_buf(&ldata, cname); update = true; } if (update) { if (!com->lc_journal) { com->lc_journal = 1; goto again; } rc = lfsck_links_write(env, child, &ldata, handle); } GOTO(stop, rc); stop: if (locked) { /* XXX: For the case linkea entries count does not match the object hard * links count, we cannot update the later one simply. Before LFSCK * phase III finished, we cannot know whether there are some remote * name entries to be repaired or not. LU-2914 */ if (rc == 0 && !lfsck_is_dead_obj(child) && ldata.ld_leh != NULL && ldata.ld_leh->leh_reccount != la->la_nlink) CWARN("%s: the object "DFID" linkEA entry count %u " "may not match its hardlink count %u\n", lfsck_lfsck2name(lfsck), PFID(cfid), ldata.ld_leh->leh_reccount, la->la_nlink); dt_write_unlock(env, child); } if (handle != NULL) dt_trans_stop(env, lfsck->li_next, handle); if (rc == 0 && update) { ns->ln_objs_nlink_repaired++; rc = 1; } return rc; }