static int fld_insert_entry(const struct lu_env *env, struct lu_server_fld *fld, const struct lu_seq_range *range) { struct thandle *th; int rc; ENTRY; th = dt_trans_create(env, lu2dt_dev(fld->lsf_obj->do_lu.lo_dev)); if (IS_ERR(th)) RETURN(PTR_ERR(th)); rc = fld_declare_index_create(env, fld, range, th); if (rc != 0) { if (rc == -EEXIST) rc = 0; GOTO(out, rc); } rc = dt_trans_start_local(env, lu2dt_dev(fld->lsf_obj->do_lu.lo_dev), th); if (rc) GOTO(out, rc); rc = fld_index_create(env, fld, range, th); if (rc == -EEXIST) rc = 0; out: dt_trans_stop(env, lu2dt_dev(fld->lsf_obj->do_lu.lo_dev), th); RETURN(rc); }
/* This function implies that caller takes care about locking. */ int seq_store_write(struct lu_server_seq *seq, const struct lu_env *env, struct thandle *th) { struct dt_object *dt_obj = seq->lss_obj; struct seq_thread_info *info; struct dt_device *dt_dev; loff_t pos = 0; int rc; ENTRY; dt_dev = lu2dt_dev(seq->lss_obj->do_lu.lo_dev); info = lu_context_key_get(&env->le_ctx, &seq_thread_key); LASSERT(info != NULL); /* Store ranges in le format. */ range_cpu_to_le(&info->sti_space, &seq->lss_space); rc = dt_obj->do_body_ops->dbo_write(env, dt_obj, seq_store_buf(info), &pos, th, BYPASS_CAPA, 1); if (rc == sizeof(info->sti_space)) { CDEBUG(D_INFO, "%s: Space - "DRANGE"\n", seq->lss_name, PRANGE(&seq->lss_space)); rc = 0; } else if (rc >= 0) { rc = -EIO; } RETURN(rc); }
/* * Helper function for write record in llog. * It hides all transaction handling from caller. * Valid only with local llog. */ int llog_write(const struct lu_env *env, struct llog_handle *loghandle, struct llog_rec_hdr *rec, int idx) { struct dt_device *dt; struct thandle *th; int rc; ENTRY; LASSERT(loghandle); LASSERT(loghandle->lgh_ctxt); LASSERT(loghandle->lgh_obj != NULL); dt = lu2dt_dev(loghandle->lgh_obj->do_lu.lo_dev); th = dt_trans_create(env, dt); if (IS_ERR(th)) RETURN(PTR_ERR(th)); rc = llog_declare_write_rec(env, loghandle, rec, idx, th); if (rc) GOTO(out_trans, rc); th->th_wait_submit = 1; rc = dt_trans_start_local(env, dt, th); if (rc) GOTO(out_trans, rc); down_write(&loghandle->lgh_lock); rc = llog_write_rec(env, loghandle, rec, NULL, idx, th); up_write(&loghandle->lgh_lock); out_trans: dt_trans_stop(env, dt, th); RETURN(rc); }
int fld_index_create(struct lu_server_fld *fld, const struct lu_env *env, const struct lu_seq_range *range, struct thandle *th) { struct dt_object *dt_obj = fld->lsf_obj; struct dt_device *dt_dev; seqno_t start; int rc; ENTRY; start = range->lsr_start; LASSERT(range_is_sane(range)); dt_dev = lu2dt_dev(fld->lsf_obj->do_lu.lo_dev); rc = dt_obj->do_index_ops->dio_insert(env, dt_obj, fld_rec(env, range), fld_key(env, start), th, BYPASS_CAPA, 1); CDEBUG(D_INFO, "%s: insert given range : "DRANGE" rc = %d\n", fld->lsf_name, PRANGE(range), rc); RETURN(rc); }
/** * Helper function to open llog or create it if doesn't exist. * It hides all transaction handling from caller. */ int llog_open_create(const struct lu_env *env, struct llog_ctxt *ctxt, struct llog_handle **res, struct llog_logid *logid, char *name) { struct dt_device *d; struct thandle *th; int rc; rc = llog_open(env, ctxt, res, logid, name, LLOG_OPEN_NEW); if (rc) return rc; if (llog_exist(*res)) return 0; LASSERT((*res)->lgh_obj != NULL); d = lu2dt_dev((*res)->lgh_obj->do_lu.lo_dev); th = dt_trans_create(env, d); if (IS_ERR(th)) GOTO(out, rc = PTR_ERR(th)); rc = llog_declare_create(env, *res, th); if (rc == 0) { rc = dt_trans_start_local(env, d, th); if (rc == 0) rc = llog_create(env, *res, th); } dt_trans_stop(env, d, th); out: if (rc) llog_close(env, *res); return rc; }
/* * Helper function for write record in llog. * It hides all transaction handling from caller. * Valid only with local llog. */ int llog_write(const struct lu_env *env, struct llog_handle *loghandle, struct llog_rec_hdr *rec, struct llog_cookie *reccookie, int cookiecount, void *buf, int idx) { struct dt_device *dt; struct thandle *th; int rc; LASSERT(loghandle); LASSERT(loghandle->lgh_ctxt); LASSERT(loghandle->lgh_obj != NULL); dt = lu2dt_dev(loghandle->lgh_obj->do_lu.lo_dev); th = dt_trans_create(env, dt); if (IS_ERR(th)) return PTR_ERR(th); rc = llog_declare_write_rec(env, loghandle, rec, idx, th); if (rc) GOTO(out_trans, rc); rc = dt_trans_start_local(env, dt, th); if (rc) GOTO(out_trans, rc); down_write(&loghandle->lgh_lock); rc = llog_write_rec(env, loghandle, rec, reccookie, cookiecount, buf, idx, th); up_write(&loghandle->lgh_lock); out_trans: dt_trans_stop(env, dt, th); return rc; }
void fld_trans_stop(struct lu_server_fld *fld, const struct lu_env *env, struct thandle* th) { struct dt_device *dt_dev; dt_dev = lu2dt_dev(fld->lsf_obj->do_lu.lo_dev); dt_dev->dd_ops->dt_trans_stop(env, th); }
struct thandle *fld_trans_create(struct lu_server_fld *fld, const struct lu_env *env) { struct dt_device *dt_dev; dt_dev = lu2dt_dev(fld->lsf_obj->do_lu.lo_dev); return dt_dev->dd_ops->dt_trans_create(env, dt_dev); }
/* * 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 llog_truncate(const struct lu_env *env, struct dt_object *o) { struct lu_attr la; struct thandle *th; struct dt_device *d; int rc; ENTRY; LASSERT(o); d = lu2dt_dev(o->do_lu.lo_dev); LASSERT(d); rc = dt_attr_get(env, o, &la); if (rc) RETURN(rc); CDEBUG(D_OTHER, "original size "LPU64"\n", la.la_size); rc = sizeof(struct llog_log_hdr) + sizeof(struct llog_mini_rec); if (la.la_size < rc) { CERROR("too small llog: "LPU64"\n", la.la_size); RETURN(0); } /* drop 2 records */ la.la_size = la.la_size - (sizeof(struct llog_mini_rec) * 2); la.la_valid = LA_SIZE; th = dt_trans_create(env, d); if (IS_ERR(th)) RETURN(PTR_ERR(th)); rc = dt_declare_attr_set(env, o, &la, th); if (rc) GOTO(stop, rc); rc = dt_declare_punch(env, o, la.la_size, OBD_OBJECT_EOF, th); rc = dt_trans_start_local(env, d, th); if (rc) GOTO(stop, rc); rc = dt_punch(env, o, la.la_size, OBD_OBJECT_EOF, th); if (rc) GOTO(stop, rc); rc = dt_attr_set(env, o, &la, th); if (rc) GOTO(stop, rc); stop: dt_trans_stop(env, d, th); RETURN(rc); }
void seq_store_trans_stop(struct lu_server_seq *seq, const struct lu_env *env, struct thandle *th) { struct dt_device *dt_dev; ENTRY; dt_dev = lu2dt_dev(seq->lss_obj->do_lu.lo_dev); dt_dev->dd_ops->dt_trans_stop(env, th); }
static int mdd_connect_to_next(const struct lu_env *env, struct mdd_device *m, const char *nextdev) { struct obd_connect_data *data = NULL; struct lu_device *lud = mdd2lu_dev(m); struct obd_device *obd; int rc; ENTRY; LASSERT(m->mdd_child_exp == NULL); OBD_ALLOC(data, sizeof(*data)); if (data == NULL) GOTO(out, rc = -ENOMEM); obd = class_name2obd(nextdev); if (obd == NULL) { CERROR("can't locate next device: %s\n", nextdev); GOTO(out, rc = -ENOTCONN); } data->ocd_connect_flags = OBD_CONNECT_VERSION; data->ocd_version = LUSTRE_VERSION_CODE; rc = obd_connect(NULL, &m->mdd_child_exp, obd, &obd->obd_uuid, data, NULL); if (rc) { CERROR("cannot connect to next dev %s (%d)\n", nextdev, rc); GOTO(out, rc); } lud->ld_site = m->mdd_child_exp->exp_obd->obd_lu_dev->ld_site; LASSERT(lud->ld_site); m->mdd_child = lu2dt_dev(m->mdd_child_exp->exp_obd->obd_lu_dev); m->mdd_bottom = lu2dt_dev(lud->ld_site->ls_bottom_dev); lu_dev_add_linkage(lud->ld_site, lud); out: if (data) OBD_FREE(data, sizeof(*data)); RETURN(rc); }
struct thandle* fld_trans_start(struct lu_server_fld *fld, const struct lu_env *env, int credit) { struct fld_thread_info *info; struct dt_device *dt_dev; struct txn_param *p; dt_dev = lu2dt_dev(fld->lsf_obj->do_lu.lo_dev); info = lu_context_key_get(&env->le_ctx, &fld_thread_key); p = &info->fti_txn_param; txn_param_init(p, credit); return dt_dev->dd_ops->dt_trans_start(env, dt_dev, p); }
/** * Helper function to open llog or create it if doesn't exist. * It hides all transaction handling from caller. */ int llog_open_create(const struct lu_env *env, struct llog_ctxt *ctxt, struct llog_handle **res, struct llog_logid *logid, char *name) { struct dt_device *d; struct thandle *th; int rc; ENTRY; rc = llog_open(env, ctxt, res, logid, name, LLOG_OPEN_NEW); if (rc) RETURN(rc); if (llog_exist(*res)) RETURN(0); LASSERT((*res)->lgh_obj != NULL); d = lu2dt_dev((*res)->lgh_obj->do_lu.lo_dev); th = dt_trans_create(env, d); if (IS_ERR(th)) GOTO(out, rc = PTR_ERR(th)); /* Create update llog object synchronously, which * happens during inialization process see * lod_sub_prep_llog(), to make sure the update * llog object is created before corss-MDT writing * updates into the llog object */ if (ctxt->loc_flags & LLOG_CTXT_FLAG_NORMAL_FID) th->th_sync = 1; th->th_wait_submit = 1; rc = llog_declare_create(env, *res, th); if (rc == 0) { rc = dt_trans_start_local(env, d, th); if (rc == 0) rc = llog_create(env, *res, th); } dt_trans_stop(env, d, th); out: if (rc) llog_close(env, *res); RETURN(rc); }
/** * Implementation of dt_object_operations::do_object_lock * * Enqueue a lock (by ldlm_cli_enqueue()) of remote object on the remote MDT, * which will lock the object in the global namespace. And because the * cross-MDT locks are relatively rare compared with normal local MDT operation, * let's release it right away, instead of putting it into the LRU list. * * \param[in] env execution environment * \param[in] dt object to be locked * \param[out] lh lock handle * \param[in] einfo enqueue information * \param[in] policy lock policy * * \retval ELDLM_OK if locking the object succeeds. * \retval negative errno if locking fails. */ static int osp_md_object_lock(const struct lu_env *env, struct dt_object *dt, struct lustre_handle *lh, struct ldlm_enqueue_info *einfo, union ldlm_policy_data *policy) { struct ldlm_res_id *res_id; struct dt_device *dt_dev = lu2dt_dev(dt->do_lu.lo_dev); struct osp_device *osp = dt2osp_dev(dt_dev); struct ptlrpc_request *req; int rc = 0; __u64 flags = 0; enum ldlm_mode mode; res_id = einfo->ei_res_id; LASSERT(res_id != NULL); mode = ldlm_lock_match(osp->opd_obd->obd_namespace, LDLM_FL_BLOCK_GRANTED, res_id, einfo->ei_type, policy, einfo->ei_mode, lh, 0); if (mode > 0) return ELDLM_OK; if (einfo->ei_nonblock) flags |= LDLM_FL_BLOCK_NOWAIT; req = ldlm_enqueue_pack(osp->opd_exp, 0); if (IS_ERR(req)) RETURN(PTR_ERR(req)); rc = ldlm_cli_enqueue(osp->opd_exp, &req, einfo, res_id, (const union ldlm_policy_data *)policy, &flags, NULL, 0, LVB_T_NONE, lh, 0); ptlrpc_req_finished(req); if (rc == ELDLM_OK) { struct ldlm_lock *lock; lock = __ldlm_handle2lock(lh, 0); ldlm_set_cbpending(lock); LDLM_LOCK_PUT(lock); } return rc == ELDLM_OK ? 0 : -EIO; }
/* * Connect a quota master to the backend OSD device. * * \param env - is the environment passed by the caller * \param qmt - is the quota master target to be connected * \param cfg - is the configuration log record from which we need to extract * the service name of the backend OSD device to connect to. * * \retval - 0 on success, appropriate error on failure */ static int qmt_connect_to_osd(const struct lu_env *env, struct qmt_device *qmt, struct lustre_cfg *cfg) { struct obd_connect_data *data = NULL; struct obd_device *obd; struct lu_device *ld = qmt2lu_dev(qmt); int rc; ENTRY; LASSERT(qmt->qmt_child_exp == NULL); OBD_ALLOC_PTR(data); if (data == NULL) GOTO(out, rc = -ENOMEM); /* look-up OBD device associated with the backend OSD device. * The MDT is kind enough to pass the OBD name in QMT configuration */ obd = class_name2obd(lustre_cfg_string(cfg, 3)); if (obd == NULL) { CERROR("%s: can't locate backend osd device: %s\n", qmt->qmt_svname, lustre_cfg_string(cfg, 3)); GOTO(out, rc = -ENOTCONN); } data->ocd_connect_flags = OBD_CONNECT_VERSION; data->ocd_version = LUSTRE_VERSION_CODE; /* connect to OSD device */ rc = obd_connect(NULL, &qmt->qmt_child_exp, obd, &obd->obd_uuid, data, NULL); if (rc) { CERROR("%s: cannot connect to osd dev %s (%d)\n", qmt->qmt_svname, obd->obd_name, rc); GOTO(out, rc); } /* initialize site (although it isn't used anywhere) and lu_device * pointer to next device */ qmt->qmt_child = lu2dt_dev(qmt->qmt_child_exp->exp_obd->obd_lu_dev); ld->ld_site = qmt->qmt_child_exp->exp_obd->obd_lu_dev->ld_site; EXIT; out: if (data) OBD_FREE_PTR(data); return rc; }
int llog_destroy(const struct lu_env *env, struct llog_handle *handle) { struct llog_operations *lop; struct dt_device *dt; struct thandle *th; int rc; ENTRY; rc = llog_handle2ops(handle, &lop); if (rc < 0) RETURN(rc); if (lop->lop_destroy == NULL) RETURN(-EOPNOTSUPP); if (handle->lgh_obj == NULL) { /* if lgh_obj == NULL, then it is from client side destroy */ rc = lop->lop_destroy(env, handle, NULL); RETURN(rc); } if (!dt_object_exists(handle->lgh_obj)) RETURN(0); dt = lu2dt_dev(handle->lgh_obj->do_lu.lo_dev); th = dt_trans_create(env, dt); if (IS_ERR(th)) RETURN(PTR_ERR(th)); rc = llog_declare_destroy(env, handle, th); if (rc != 0) GOTO(out_trans, rc); rc = dt_trans_start_local(env, dt, th); if (rc < 0) GOTO(out_trans, rc); rc = lop->lop_destroy(env, handle, th); out_trans: dt_trans_stop(env, dt, th); RETURN(rc); }
/** * Implementation of dt_object_operations::do_object_lock * * Enqueue a lock (by ldlm_cli_enqueue()) of remote object on the remote MDT, * which will lock the object in the global namespace. And because the * cross-MDT locks are relatively rare compared with normal local MDT operation, * let's release it right away, instead of putting it into the LRU list. * * \param[in] env execution environment * \param[in] dt object to be locked * \param[out] lh lock handle * \param[in] einfo enqueue information * \param[in] policy lock policy * * \retval ELDLM_OK if locking the object succeeds. * \retval negative errno if locking fails. */ static int osp_md_object_lock(const struct lu_env *env, struct dt_object *dt, struct lustre_handle *lh, struct ldlm_enqueue_info *einfo, union ldlm_policy_data *policy) { struct ldlm_res_id *res_id; struct dt_device *dt_dev = lu2dt_dev(dt->do_lu.lo_dev); struct osp_device *osp = dt2osp_dev(dt_dev); struct lu_device *top_device; struct ptlrpc_request *req; int rc = 0; __u64 flags = LDLM_FL_NO_LRU; res_id = einfo->ei_res_id; LASSERT(res_id != NULL); if (einfo->ei_nonblock) flags |= LDLM_FL_BLOCK_NOWAIT; if (einfo->ei_mode & (LCK_EX | LCK_PW)) flags |= LDLM_FL_COS_INCOMPAT; req = ldlm_enqueue_pack(osp->opd_exp, 0); if (IS_ERR(req)) RETURN(PTR_ERR(req)); /* During recovery, it needs to let OSP send enqueue * without checking recoverying status, in case the * other target is being recovered at the same time, * and if we wait here for the import to be recovered, * it might cause deadlock */ top_device = dt_dev->dd_lu_dev.ld_site->ls_top_dev; if (top_device->ld_obd->obd_recovering) req->rq_allow_replay = 1; rc = ldlm_cli_enqueue(osp->opd_exp, &req, einfo, res_id, (const union ldlm_policy_data *)policy, &flags, NULL, 0, LVB_T_NONE, lh, 0); ptlrpc_req_finished(req); return rc == ELDLM_OK ? 0 : -EIO; }
struct thandle *seq_store_trans_start(struct lu_server_seq *seq, const struct lu_env *env, int credit, int sync) { struct seq_thread_info *info; struct dt_device *dt_dev; struct thandle *th; ENTRY; dt_dev = lu2dt_dev(seq->lss_obj->do_lu.lo_dev); info = lu_context_key_get(&env->le_ctx, &seq_thread_key); LASSERT(info != NULL); txn_param_init(&info->sti_txn, credit); if (sync) txn_param_sync(&info->sti_txn); th = dt_dev->dd_ops->dt_trans_start(env, dt_dev, &info->sti_txn); return th; }
int fld_index_delete(struct lu_server_fld *fld, const struct lu_env *env, struct lu_seq_range *range, struct thandle *th) { struct dt_object *dt_obj = fld->lsf_obj; struct dt_device *dt_dev; seqno_t seq = range->lsr_start; int rc; ENTRY; dt_dev = lu2dt_dev(fld->lsf_obj->do_lu.lo_dev); rc = dt_obj->do_index_ops->dio_delete(env, dt_obj, fld_key(env, seq), th, BYPASS_CAPA); CDEBUG(D_INFO, "%s: delete given range : "DRANGE" rc = %d\n", fld->lsf_name, PRANGE(range), rc); RETURN(rc); }
/** * Implementation of the llog_operations::lop_prev_block * * This function finds the llog block to return which contains * record with required index but in reverse order - from end of llog * to the beginning. * It is main part of reverse llog processing. * * \param[in] env execution environment * \param[in] loghandle llog handle of the current llog * \param[in] prev_idx target index to find * \param[in] buf pointer to data buffer to fill * \param[in] len required len to read, it is LLOG_CHUNK_SIZE usually. * * \retval 0 on successful buffer read * \retval negative value on error */ static int llog_osd_prev_block(const struct lu_env *env, struct llog_handle *loghandle, int prev_idx, void *buf, int len) { struct llog_thread_info *lgi = llog_info(env); struct dt_object *o; struct dt_device *dt; loff_t cur_offset; int rc; ENTRY; if (len == 0 || len & (LLOG_CHUNK_SIZE - 1)) RETURN(-EINVAL); CDEBUG(D_OTHER, "looking for log index %u\n", prev_idx); LASSERT(loghandle); LASSERT(loghandle->lgh_ctxt); o = loghandle->lgh_obj; LASSERT(o); LASSERT(dt_object_exists(o)); dt = lu2dt_dev(o->do_lu.lo_dev); LASSERT(dt); cur_offset = LLOG_CHUNK_SIZE; llog_skip_over(&cur_offset, 0, prev_idx); rc = dt_attr_get(env, o, &lgi->lgi_attr, BYPASS_CAPA); if (rc) GOTO(out, rc); while (cur_offset < lgi->lgi_attr.la_size) { struct llog_rec_hdr *rec, *last_rec; struct llog_rec_tail *tail; lgi->lgi_buf.lb_len = len; lgi->lgi_buf.lb_buf = buf; rc = dt_read(env, o, &lgi->lgi_buf, &cur_offset); if (rc < 0) { CERROR("%s: can't read llog block from log "DFID " offset "LPU64": rc = %d\n", o->do_lu.lo_dev->ld_obd->obd_name, PFID(lu_object_fid(&o->do_lu)), cur_offset, rc); GOTO(out, rc); } if (rc == 0) /* end of file, nothing to do */ GOTO(out, rc); if (rc < sizeof(*tail)) { CERROR("%s: invalid llog block at log id "DOSTID"/%u " "offset "LPU64"\n", o->do_lu.lo_dev->ld_obd->obd_name, POSTID(&loghandle->lgh_id.lgl_oi), loghandle->lgh_id.lgl_ogen, cur_offset); GOTO(out, rc = -EINVAL); } rec = buf; if (LLOG_REC_HDR_NEEDS_SWABBING(rec)) lustre_swab_llog_rec(rec); tail = (struct llog_rec_tail *)((char *)buf + rc - sizeof(struct llog_rec_tail)); /* get the last record in block */ last_rec = (struct llog_rec_hdr *)((char *)buf + rc - le32_to_cpu(tail->lrt_len)); if (LLOG_REC_HDR_NEEDS_SWABBING(last_rec)) lustre_swab_llog_rec(last_rec); LASSERT(last_rec->lrh_index == tail->lrt_index); /* this shouldn't happen */ if (tail->lrt_index == 0) { CERROR("%s: invalid llog tail at log id "DOSTID"/%u " "offset "LPU64"\n", o->do_lu.lo_dev->ld_obd->obd_name, POSTID(&loghandle->lgh_id.lgl_oi), loghandle->lgh_id.lgl_ogen, cur_offset); GOTO(out, rc = -EINVAL); } if (tail->lrt_index < prev_idx) continue; /* sanity check that the start of the new buffer is no farther * than the record that we wanted. This shouldn't happen. */ if (rec->lrh_index > prev_idx) { CERROR("%s: missed desired record? %u > %u\n", o->do_lu.lo_dev->ld_obd->obd_name, rec->lrh_index, prev_idx); GOTO(out, rc = -ENOENT); } GOTO(out, rc = 0); } GOTO(out, rc = -EIO); out: return rc; }
/** * Implementation of the llog_operations::lop_destroy * * This function destroys the llog and deletes also entry in the * llog directory in case of named llog. Llog should be opened prior that. * Destroy method is not part of external transaction and does everything * inside. * * \param[in] env execution environment * \param[in] loghandle llog handle of the current llog * * \retval 0 on successful destroy * \retval negative value on error */ static int llog_osd_destroy(const struct lu_env *env, struct llog_handle *loghandle) { struct llog_ctxt *ctxt; struct dt_object *o, *llog_dir = NULL; struct dt_device *d; struct thandle *th; char *name = NULL; int rc; ENTRY; ctxt = loghandle->lgh_ctxt; LASSERT(ctxt); o = loghandle->lgh_obj; LASSERT(o); d = lu2dt_dev(o->do_lu.lo_dev); LASSERT(d); LASSERT(d == ctxt->loc_exp->exp_obd->obd_lvfs_ctxt.dt); th = dt_trans_create(env, d); if (IS_ERR(th)) RETURN(PTR_ERR(th)); if (loghandle->lgh_name) { llog_dir = llog_osd_dir_get(env, ctxt); if (IS_ERR(llog_dir)) GOTO(out_trans, rc = PTR_ERR(llog_dir)); name = loghandle->lgh_name; rc = dt_declare_delete(env, llog_dir, (struct dt_key *)name, th); if (rc) GOTO(out_trans, rc); } dt_declare_ref_del(env, o, th); rc = dt_declare_destroy(env, o, th); if (rc) GOTO(out_trans, rc); rc = dt_trans_start_local(env, d, th); if (rc) GOTO(out_trans, rc); dt_write_lock(env, o, 0); if (dt_object_exists(o)) { if (name) { dt_read_lock(env, llog_dir, 0); rc = dt_delete(env, llog_dir, (struct dt_key *) name, th, BYPASS_CAPA); dt_read_unlock(env, llog_dir); if (rc) { CERROR("%s: can't remove llog %s: rc = %d\n", o->do_lu.lo_dev->ld_obd->obd_name, name, rc); GOTO(out_unlock, rc); } } dt_ref_del(env, o, th); rc = dt_destroy(env, o, th); if (rc) GOTO(out_unlock, rc); } out_unlock: dt_write_unlock(env, o); out_trans: dt_trans_stop(env, d, th); if (llog_dir != NULL) lu_object_put(env, &llog_dir->do_lu); RETURN(rc); }
static int llog_test_setup(struct obd_device *obd, struct lustre_cfg *lcfg) { struct obd_device *tgt; struct llog_ctxt *ctxt; struct dt_object *o; struct lu_env env; struct lu_context test_session; int rc; if (lcfg->lcfg_bufcount < 2) { CERROR("requires a TARGET OBD name\n"); return -EINVAL; } if (lcfg->lcfg_buflens[1] < 1) { CERROR("requires a TARGET OBD name\n"); return -EINVAL; } /* disk obd */ tgt = class_name2obd(lustre_cfg_string(lcfg, 1)); if (!tgt || !tgt->obd_attached || !tgt->obd_set_up) { CERROR("target device not attached or not set up (%s)\n", lustre_cfg_string(lcfg, 1)); return -EINVAL; } rc = lu_env_init(&env, LCT_LOCAL | LCT_MG_THREAD); if (rc) return rc; rc = lu_context_init(&test_session, LCT_SESSION); if (rc) GOTO(cleanup_env, rc); test_session.lc_thread = (struct ptlrpc_thread *)current; lu_context_enter(&test_session); env.le_ses = &test_session; CWARN("Setup llog-test device over %s device\n", lustre_cfg_string(lcfg, 1)); OBD_SET_CTXT_MAGIC(&obd->obd_lvfs_ctxt); obd->obd_lvfs_ctxt.dt = lu2dt_dev(tgt->obd_lu_dev); rc = llog_setup(&env, tgt, &tgt->obd_olg, LLOG_TEST_ORIG_CTXT, tgt, &llog_osd_ops); if (rc) GOTO(cleanup_session, rc); /* use MGS llog dir for tests */ ctxt = llog_get_context(tgt, LLOG_CONFIG_ORIG_CTXT); LASSERT(ctxt); o = ctxt->loc_dir; llog_ctxt_put(ctxt); ctxt = llog_get_context(tgt, LLOG_TEST_ORIG_CTXT); LASSERT(ctxt); ctxt->loc_dir = o; llog_ctxt_put(ctxt); llog_test_rand = cfs_rand(); rc = llog_run_tests(&env, tgt); if (rc) llog_test_cleanup(obd); cleanup_session: lu_context_exit(&test_session); lu_context_fini(&test_session); cleanup_env: lu_env_fini(&env); return rc; }
static int llog_osd_destroy(const struct lu_env *env, struct llog_handle *loghandle) { struct llog_thread_info *lgi = llog_info(env); struct llog_ctxt *ctxt; struct dt_object *o, *llog_dir = NULL; struct dt_device *d; struct thandle *th; char *name = NULL; int rc; ENTRY; ctxt = loghandle->lgh_ctxt; LASSERT(ctxt); o = loghandle->lgh_obj; LASSERT(o); d = lu2dt_dev(o->do_lu.lo_dev); LASSERT(d); LASSERT(d == ctxt->loc_exp->exp_obd->obd_lvfs_ctxt.dt); th = dt_trans_create(env, d); if (IS_ERR(th)) RETURN(PTR_ERR(th)); if (loghandle->lgh_name) { llog_dir = llog_osd_dir_get(env, ctxt); if (IS_ERR(llog_dir)) GOTO(out_trans, rc = PTR_ERR(llog_dir)); dt_declare_ref_del(env, o, th); name = loghandle->lgh_name; rc = dt_declare_delete(env, llog_dir, (struct dt_key *)name, th); if (rc) GOTO(out_trans, rc); } dt_declare_ref_del(env, o, th); rc = dt_declare_destroy(env, o, th); if (rc) GOTO(out_trans, rc); rc = dt_trans_start_local(env, d, th); if (rc) GOTO(out_trans, rc); dt_write_lock(env, o, 0); if (dt_object_exists(o)) { if (name) { dt_ref_del(env, o, th); dt_read_lock(env, llog_dir, 0); rc = dt_delete(env, llog_dir, (struct dt_key *) name, th, BYPASS_CAPA); dt_read_unlock(env, llog_dir); if (rc) { CERROR("%s: can't remove llog %s: rc = %d\n", o->do_lu.lo_dev->ld_obd->obd_name, name, rc); GOTO(out_unlock, rc); } } /* * XXX: compatibility bits * on old filesystems llogs are referenced by the name * on the new ones they are referenced by OI and by * the name */ rc = dt_attr_get(env, o, &lgi->lgi_attr, NULL); if (rc) GOTO(out_unlock, rc); LASSERT(lgi->lgi_attr.la_nlink < 2); if (lgi->lgi_attr.la_nlink == 1) dt_ref_del(env, o, th); rc = dt_destroy(env, o, th); if (rc) GOTO(out_unlock, rc); } out_unlock: dt_write_unlock(env, o); out_trans: dt_trans_stop(env, d, th); if (llog_dir != NULL) lu_object_put(env, &llog_dir->do_lu); RETURN(rc); }
/* sets: * - cur_offset to the furthest point read in the log file * - cur_idx to the log index preceeding cur_offset * returns -EIO/-EINVAL on error */ static int llog_osd_next_block(const struct lu_env *env, struct llog_handle *loghandle, int *cur_idx, int next_idx, __u64 *cur_offset, void *buf, int len) { struct llog_thread_info *lgi = llog_info(env); struct dt_object *o; struct dt_device *dt; int rc; ENTRY; LASSERT(env); LASSERT(lgi); if (len == 0 || len & (LLOG_CHUNK_SIZE - 1)) RETURN(-EINVAL); CDEBUG(D_OTHER, "looking for log index %u (cur idx %u off "LPU64")\n", next_idx, *cur_idx, *cur_offset); LASSERT(loghandle); LASSERT(loghandle->lgh_ctxt); o = loghandle->lgh_obj; LASSERT(o); LASSERT(dt_object_exists(o)); dt = lu2dt_dev(o->do_lu.lo_dev); LASSERT(dt); rc = dt_attr_get(env, o, &lgi->lgi_attr, BYPASS_CAPA); if (rc) GOTO(out, rc); while (*cur_offset < lgi->lgi_attr.la_size) { struct llog_rec_hdr *rec, *last_rec; struct llog_rec_tail *tail; llog_skip_over(cur_offset, *cur_idx, next_idx); /* read up to next LLOG_CHUNK_SIZE block */ lgi->lgi_buf.lb_len = LLOG_CHUNK_SIZE - (*cur_offset & (LLOG_CHUNK_SIZE - 1)); lgi->lgi_buf.lb_buf = buf; /* Note: read lock is not needed around la_size get above at * the time of dt_attr_get(). There are only two cases that * matter. Either la_size == cur_offset, in which case the * entire read is skipped, or la_size > cur_offset and the loop * is entered and this thread is blocked at dt_read_lock() * until the write is completed. When the write completes, then * the dt_read() will be done with the full length, and will * get the full data. */ dt_read_lock(env, o, 0); rc = dt_read(env, o, &lgi->lgi_buf, cur_offset); dt_read_unlock(env, o); if (rc < 0) { CERROR("%s: can't read llog block from log "DFID " offset "LPU64": rc = %d\n", o->do_lu.lo_dev->ld_obd->obd_name, PFID(lu_object_fid(&o->do_lu)), *cur_offset, rc); GOTO(out, rc); } if (rc < len) { /* signal the end of the valid buffer to * llog_process */ memset(buf + rc, 0, len - rc); } if (rc == 0) /* end of file, nothing to do */ GOTO(out, rc); if (rc < sizeof(*tail)) { CERROR("%s: invalid llog block at log id "LPU64"/%u " "offset "LPU64"\n", o->do_lu.lo_dev->ld_obd->obd_name, loghandle->lgh_id.lgl_oid, loghandle->lgh_id.lgl_ogen, *cur_offset); GOTO(out, rc = -EINVAL); } rec = buf; if (LLOG_REC_HDR_NEEDS_SWABBING(rec)) lustre_swab_llog_rec(rec); tail = (struct llog_rec_tail *)((char *)buf + rc - sizeof(struct llog_rec_tail)); /* get the last record in block */ last_rec = (struct llog_rec_hdr *)((char *)buf + rc - le32_to_cpu(tail->lrt_len)); if (LLOG_REC_HDR_NEEDS_SWABBING(last_rec)) lustre_swab_llog_rec(last_rec); LASSERT(last_rec->lrh_index == tail->lrt_index); *cur_idx = tail->lrt_index; /* this shouldn't happen */ if (tail->lrt_index == 0) { CERROR("%s: invalid llog tail at log id "LPU64"/%u " "offset "LPU64"\n", o->do_lu.lo_dev->ld_obd->obd_name, loghandle->lgh_id.lgl_oid, loghandle->lgh_id.lgl_ogen, *cur_offset); GOTO(out, rc = -EINVAL); } if (tail->lrt_index < next_idx) continue; /* sanity check that the start of the new buffer is no farther * than the record that we wanted. This shouldn't happen. */ if (rec->lrh_index > next_idx) { CERROR("%s: missed desired record? %u > %u\n", o->do_lu.lo_dev->ld_obd->obd_name, rec->lrh_index, next_idx); GOTO(out, rc = -ENOENT); } GOTO(out, rc = 0); } GOTO(out, rc = -EIO); out: return rc; }
/** * Implementation of the llog_operations::lop_next_block * * This function finds the the next llog block to return which contains * record with required index. It is main part of llog processing. * * \param[in] env execution environment * \param[in] loghandle llog handle of the current llog * \param[in,out] cur_idx index preceeding cur_offset * \param[in] next_idx target index to find * \param[in,out] cur_offset furtherst point read in the file * \param[in] buf pointer to data buffer to fill * \param[in] len required len to read, it is * LLOG_CHUNK_SIZE usually. * * \retval 0 on successful buffer read * \retval negative value on error */ static int llog_osd_next_block(const struct lu_env *env, struct llog_handle *loghandle, int *cur_idx, int next_idx, __u64 *cur_offset, void *buf, int len) { struct llog_thread_info *lgi = llog_info(env); struct dt_object *o; struct dt_device *dt; int rc; ENTRY; LASSERT(env); LASSERT(lgi); if (len == 0 || len & (LLOG_CHUNK_SIZE - 1)) RETURN(-EINVAL); CDEBUG(D_OTHER, "looking for log index %u (cur idx %u off "LPU64")\n", next_idx, *cur_idx, *cur_offset); LASSERT(loghandle); LASSERT(loghandle->lgh_ctxt); o = loghandle->lgh_obj; LASSERT(o); LASSERT(dt_object_exists(o)); dt = lu2dt_dev(o->do_lu.lo_dev); LASSERT(dt); rc = dt_attr_get(env, o, &lgi->lgi_attr, BYPASS_CAPA); if (rc) GOTO(out, rc); while (*cur_offset < lgi->lgi_attr.la_size) { struct llog_rec_hdr *rec, *last_rec; struct llog_rec_tail *tail; llog_skip_over(cur_offset, *cur_idx, next_idx); /* read up to next LLOG_CHUNK_SIZE block */ lgi->lgi_buf.lb_len = LLOG_CHUNK_SIZE - (*cur_offset & (LLOG_CHUNK_SIZE - 1)); lgi->lgi_buf.lb_buf = buf; rc = dt_read(env, o, &lgi->lgi_buf, cur_offset); if (rc < 0) { CERROR("%s: can't read llog block from log "DFID " offset "LPU64": rc = %d\n", o->do_lu.lo_dev->ld_obd->obd_name, PFID(lu_object_fid(&o->do_lu)), *cur_offset, rc); GOTO(out, rc); } if (rc < len) { /* signal the end of the valid buffer to * llog_process */ memset(buf + rc, 0, len - rc); } if (rc == 0) /* end of file, nothing to do */ GOTO(out, rc); if (rc < sizeof(*tail)) { CERROR("%s: invalid llog block at log id "DOSTID"/%u " "offset "LPU64"\n", o->do_lu.lo_dev->ld_obd->obd_name, POSTID(&loghandle->lgh_id.lgl_oi), loghandle->lgh_id.lgl_ogen, *cur_offset); GOTO(out, rc = -EINVAL); } rec = buf; if (LLOG_REC_HDR_NEEDS_SWABBING(rec)) lustre_swab_llog_rec(rec); tail = (struct llog_rec_tail *)((char *)buf + rc - sizeof(struct llog_rec_tail)); /* get the last record in block */ last_rec = (struct llog_rec_hdr *)((char *)buf + rc - tail->lrt_len); if (LLOG_REC_HDR_NEEDS_SWABBING(last_rec)) lustre_swab_llog_rec(last_rec); LASSERT(last_rec->lrh_index == tail->lrt_index); *cur_idx = tail->lrt_index; /* this shouldn't happen */ if (tail->lrt_index == 0) { CERROR("%s: invalid llog tail at log id "DOSTID"/%u " "offset "LPU64"\n", o->do_lu.lo_dev->ld_obd->obd_name, POSTID(&loghandle->lgh_id.lgl_oi), loghandle->lgh_id.lgl_ogen, *cur_offset); GOTO(out, rc = -EINVAL); } if (tail->lrt_index < next_idx) continue; /* sanity check that the start of the new buffer is no farther * than the record that we wanted. This shouldn't happen. */ if (rec->lrh_index > next_idx) { CERROR("%s: missed desired record? %u > %u\n", o->do_lu.lo_dev->ld_obd->obd_name, rec->lrh_index, next_idx); GOTO(out, rc = -ENOENT); } /* Trim unsupported extensions for compat w/ older clients */ if (!(loghandle->lgh_hdr->llh_flags & LLOG_F_EXT_JOBID)) changelog_block_trim_ext(rec, last_rec, CLF_VERSION | CLF_RENAME); GOTO(out, rc = 0); } GOTO(out, rc = -EIO); out: return rc; }
/* returns negative on error; 0 if success; 1 if success & log destroyed */ int llog_cancel_rec(const struct lu_env *env, struct llog_handle *loghandle, int index) { struct llog_thread_info *lgi = llog_info(env); struct dt_device *dt; struct llog_log_hdr *llh = loghandle->lgh_hdr; struct thandle *th; int rc; int rc1; bool subtract_count = false; ENTRY; CDEBUG(D_RPCTRACE, "Canceling %d in log "DOSTID"\n", index, POSTID(&loghandle->lgh_id.lgl_oi)); if (index == 0) { CERROR("Can't cancel index 0 which is header\n"); RETURN(-EINVAL); } LASSERT(loghandle != NULL); LASSERT(loghandle->lgh_ctxt != NULL); LASSERT(loghandle->lgh_obj != NULL); dt = lu2dt_dev(loghandle->lgh_obj->do_lu.lo_dev); th = dt_trans_create(env, dt); if (IS_ERR(th)) RETURN(PTR_ERR(th)); rc = llog_declare_write_rec(env, loghandle, &llh->llh_hdr, index, th); if (rc < 0) GOTO(out_trans, rc); if ((llh->llh_flags & LLOG_F_ZAP_WHEN_EMPTY)) rc = llog_declare_destroy(env, loghandle, th); th->th_wait_submit = 1; rc = dt_trans_start_local(env, dt, th); if (rc < 0) GOTO(out_trans, rc); down_write(&loghandle->lgh_lock); /* clear bitmap */ mutex_lock(&loghandle->lgh_hdr_mutex); if (!ext2_clear_bit(index, LLOG_HDR_BITMAP(llh))) { CDEBUG(D_RPCTRACE, "Catalog index %u already clear?\n", index); GOTO(out_unlock, rc); } loghandle->lgh_hdr->llh_count--; subtract_count = true; /* Pass this index to llog_osd_write_rec(), which will use the index * to only update the necesary bitmap. */ lgi->lgi_cookie.lgc_index = index; /* update header */ rc = llog_write_rec(env, loghandle, &llh->llh_hdr, &lgi->lgi_cookie, LLOG_HEADER_IDX, th); if (rc != 0) GOTO(out_unlock, rc); if ((llh->llh_flags & LLOG_F_ZAP_WHEN_EMPTY) && (llh->llh_count == 1) && ((loghandle->lgh_last_idx == LLOG_HDR_BITMAP_SIZE(llh) - 1) || (loghandle->u.phd.phd_cat_handle != NULL && loghandle->u.phd.phd_cat_handle->u.chd.chd_current_log != loghandle))) { /* never try to destroy it again */ llh->llh_flags &= ~LLOG_F_ZAP_WHEN_EMPTY; rc = llog_trans_destroy(env, loghandle, th); if (rc < 0) { /* Sigh, can not destroy the final plain llog, but * the bitmap has been clearly, so the record can not * be accessed anymore, let's return 0 for now, and * the orphan will be handled by LFSCK. */ CERROR("%s: can't destroy empty llog #"DOSTID "#%08x: rc = %d\n", loghandle->lgh_ctxt->loc_obd->obd_name, POSTID(&loghandle->lgh_id.lgl_oi), loghandle->lgh_id.lgl_ogen, rc); GOTO(out_unlock, rc); } rc = LLOG_DEL_PLAIN; } out_unlock: mutex_unlock(&loghandle->lgh_hdr_mutex); up_write(&loghandle->lgh_lock); out_trans: rc1 = dt_trans_stop(env, dt, th); if (rc == 0) rc = rc1; if (rc < 0 && subtract_count) { mutex_lock(&loghandle->lgh_hdr_mutex); loghandle->lgh_hdr->llh_count++; ext2_set_bit(index, LLOG_HDR_BITMAP(llh)); mutex_unlock(&loghandle->lgh_hdr_mutex); } RETURN(rc); }