/* * Update version of an index file * * \param env - is the environment passed by the caller * \param dev - is the backend dt device storing the index file * \param obj - is the on-disk index that should be updated * \param ver - is the new version */ int lquota_disk_update_ver(const struct lu_env *env, struct dt_device *dev, struct dt_object *obj, __u64 ver) { struct thandle *th; int rc; ENTRY; th = dt_trans_create(env, dev); if (IS_ERR(th)) RETURN(PTR_ERR(th)); rc = dt_declare_version_set(env, obj, th); if (rc) GOTO(out, rc); rc = dt_trans_start_local(env, dev, th); if (rc) GOTO(out, rc); th->th_sync = 1; dt_version_set(env, obj, ver, th); EXIT; out: dt_trans_stop(env, dev, th); return rc; }
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); }
/** * 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, 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); }
static int mdd_convert_linkea(const struct lu_env *env, struct mdd_device *mdd, struct mdd_object *o, const struct lu_name *name) { struct thandle *th; struct lu_fid oldfid; int rc; ENTRY; th = dt_trans_create(env, mdd->mdd_child); if (IS_ERR(th)) RETURN(PTR_ERR(th)); rc = mdd_declare_links_add(env, o, th, NULL); if (rc) GOTO(out, rc); rc = dt_trans_start_local(env, mdd->mdd_child, th); if (rc) GOTO(out, rc); oldfid.f_seq = FID_SEQ_LOCAL_FILE; oldfid.f_oid = MDD_ROOT_INDEX_OID; oldfid.f_ver = 0; rc = mdd_links_rename(env, o, &oldfid, name, &mdd->mdd_root_fid, name, th, NULL, 0, 1); if (rc == -ENOENT || rc == -EEXIST) rc = 0; out: dt_trans_stop(env, mdd->mdd_child, th); 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; }
static int mdd_convert_lma(const struct lu_env *env, struct mdd_device *mdd, struct mdd_object *o) { struct lustre_mdt_attrs *lma; struct thandle *th; struct lu_fid fid; struct lu_buf buf; int rc; ENTRY; lu_root_fid(&fid); lma = (struct lustre_mdt_attrs *)&mdd_env_info(env)->mti_xattr_buf; lustre_lma_init(lma, &fid, 0, 0); lustre_lma_swab(lma); buf.lb_buf = lma; buf.lb_len = sizeof(*lma); th = dt_trans_create(env, mdd->mdd_child); if (IS_ERR(th)) RETURN(PTR_ERR(th)); rc = mdo_declare_xattr_set(env, o, &buf, XATTR_NAME_LMA, 0, th); if (rc) GOTO(out, rc); rc = dt_trans_start_local(env, mdd->mdd_child, th); if (rc) GOTO(out, rc); rc = mdo_xattr_set(env, o, &buf, XATTR_NAME_LMA, 0, th, BYPASS_CAPA); out: dt_trans_stop(env, mdd->mdd_child, th); RETURN(rc); }
/** * Write fid into last_oid/last_seq file. **/ int osp_write_last_oid_seq_files(struct lu_env *env, struct osp_device *osp, struct lu_fid *fid, int sync) { struct osp_thread_info *oti = osp_env_info(env); struct lu_buf *lb_oid = &oti->osi_lb; struct lu_buf *lb_oseq = &oti->osi_lb2; loff_t oid_off; loff_t oseq_off; struct thandle *th; int rc; ENTRY; /* Note: through f_oid is only 32bits, it will also write * 64 bits for oid to keep compatiblity with the previous * version. */ lb_oid->lb_buf = &fid->f_oid; lb_oid->lb_len = sizeof(obd_id); oid_off = sizeof(obd_id) * osp->opd_index; lb_oseq->lb_buf = &fid->f_seq; lb_oseq->lb_len = sizeof(obd_id); oseq_off = sizeof(obd_id) * osp->opd_index; th = dt_trans_create(env, osp->opd_storage); if (IS_ERR(th)) RETURN(PTR_ERR(th)); th->th_sync |= sync; rc = dt_declare_record_write(env, osp->opd_last_used_oid_file, lb_oid->lb_len, oid_off, th); if (rc != 0) GOTO(out, rc); rc = dt_declare_record_write(env, osp->opd_last_used_seq_file, lb_oseq->lb_len, oseq_off, th); if (rc != 0) GOTO(out, rc); rc = dt_trans_start_local(env, osp->opd_storage, th); if (rc != 0) GOTO(out, rc); rc = dt_record_write(env, osp->opd_last_used_oid_file, lb_oid, &oid_off, th); if (rc != 0) { CERROR("%s: can not write to last seq file: rc = %d\n", osp->opd_obd->obd_name, rc); GOTO(out, rc); } rc = dt_record_write(env, osp->opd_last_used_seq_file, lb_oseq, &oseq_off, th); if (rc) { CERROR("%s: can not write to last seq file: rc = %d\n", osp->opd_obd->obd_name, rc); GOTO(out, rc); } out: dt_trans_stop(env, osp->opd_storage, th); RETURN(rc); }
/** * Write the special file which contains the list of llog catalogs IDs * * This function writes the CATALOG file which contains the array of llog * catalogs IDs. It is used mostly to store OSP llogs indexed by OST/MDT * number. * * \param[in] env execution environment * \param[in] d corresponding storage device * \param[in] idx position to start from, usually OST/MDT index * \param[in] count how many catalog IDs to write * \param[out] idarray the buffer with the data to write. * \param[in] fid LLOG_CATALOGS_OID for CATALOG object * * \retval 0 on successful write of catalog IDs * \retval negative value on error */ int llog_osd_put_cat_list(const struct lu_env *env, struct dt_device *d, int idx, int count, struct llog_catid *idarray, const struct lu_fid *fid) { struct llog_thread_info *lgi = llog_info(env); struct dt_object *o = NULL; struct thandle *th; int rc, size; if (count == 0) RETURN(0); LASSERT(d); size = sizeof(*idarray) * count; lgi->lgi_off = idx * sizeof(*idarray); lgi->lgi_fid = *fid; o = dt_locate(env, d, &lgi->lgi_fid); if (IS_ERR(o)) RETURN(PTR_ERR(o)); if (!dt_object_exists(o)) GOTO(out, rc = -ENOENT); rc = dt_attr_get(env, o, &lgi->lgi_attr, BYPASS_CAPA); if (rc) GOTO(out, rc); if (!S_ISREG(lgi->lgi_attr.la_mode)) { CERROR("%s: CATALOGS is not a regular file!: mode = %o\n", o->do_lu.lo_dev->ld_obd->obd_name, lgi->lgi_attr.la_mode); GOTO(out, rc = -ENOENT); } th = dt_trans_create(env, d); if (IS_ERR(th)) GOTO(out, rc = PTR_ERR(th)); lgi->lgi_buf.lb_len = size; lgi->lgi_buf.lb_buf = idarray; rc = dt_declare_record_write(env, o, &lgi->lgi_buf, lgi->lgi_off, th); if (rc) GOTO(out, rc); rc = dt_trans_start_local(env, d, th); if (rc) GOTO(out_trans, rc); rc = dt_record_write(env, o, &lgi->lgi_buf, &lgi->lgi_off, th); if (rc) CDEBUG(D_INODE, "can't write CATALOGS at index %d: rc = %d\n", idx, rc); out_trans: dt_trans_stop(env, d, th); out: lu_object_put(env, &o->do_lu); RETURN(rc); }
static int lfsck_namespace_delete(const struct lu_env *env, struct lfsck_component *com, const struct lu_fid *fid) { struct lfsck_instance *lfsck = com->lc_lfsck; struct lu_fid *key = &lfsck_env_info(env)->lti_fid; struct thandle *handle; struct dt_object *obj = com->lc_obj; int rc; ENTRY; handle = dt_trans_create(env, lfsck->li_bottom); if (IS_ERR(handle)) RETURN(PTR_ERR(handle)); rc = dt_declare_delete(env, obj, (const struct dt_key *)fid, handle); if (rc != 0) GOTO(out, rc); rc = dt_trans_start_local(env, lfsck->li_bottom, handle); if (rc != 0) GOTO(out, rc); fid_cpu_to_be(key, fid); rc = dt_delete(env, obj, (const struct dt_key *)key, handle, BYPASS_CAPA); GOTO(out, rc); out: dt_trans_stop(env, lfsck->li_bottom, handle); return rc; }
static int lfsck_update_lma(const struct lu_env *env, struct lfsck_instance *lfsck, struct dt_object *obj) { struct lfsck_thread_info *info = lfsck_env_info(env); struct lfsck_bookmark *bk = &lfsck->li_bookmark_ram; struct dt_device *dt = lfsck->li_bottom; struct lustre_mdt_attrs *lma = &info->lti_lma; struct lu_buf *buf; struct thandle *th; int fl; int rc; ENTRY; if (bk->lb_param & LPF_DRYRUN) RETURN(0); buf = lfsck_buf_get(env, info->lti_lma_old, LMA_OLD_SIZE); rc = dt_xattr_get(env, obj, buf, XATTR_NAME_LMA, BYPASS_CAPA); if (rc < 0) { if (rc != -ENODATA) RETURN(rc); fl = LU_XATTR_CREATE; lustre_lma_init(lma, lfsck_dto2fid(obj), LMAC_FID_ON_OST, 0); } else { if (rc != LMA_OLD_SIZE && rc != sizeof(struct lustre_mdt_attrs)) RETURN(-EINVAL); fl = LU_XATTR_REPLACE; lustre_lma_swab(lma); lustre_lma_init(lma, lfsck_dto2fid(obj), lma->lma_compat | LMAC_FID_ON_OST, lma->lma_incompat); } lustre_lma_swab(lma); th = dt_trans_create(env, dt); if (IS_ERR(th)) RETURN(PTR_ERR(th)); buf = lfsck_buf_get(env, lma, sizeof(*lma)); rc = dt_declare_xattr_set(env, obj, buf, XATTR_NAME_LMA, fl, th); if (rc != 0) GOTO(stop, rc); rc = dt_trans_start(env, dt, th); if (rc != 0) GOTO(stop, rc); rc = dt_xattr_set(env, obj, buf, XATTR_NAME_LMA, fl, th, BYPASS_CAPA); GOTO(stop, rc); stop: dt_trans_stop(env, dt, th); return rc; }
/* * 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); }
static int lfsck_namespace_store(const struct lu_env *env, struct lfsck_component *com, bool init) { struct dt_object *obj = com->lc_obj; struct lfsck_instance *lfsck = com->lc_lfsck; struct thandle *handle; int len = com->lc_file_size; int rc; ENTRY; lfsck_namespace_cpu_to_le((struct lfsck_namespace *)com->lc_file_disk, (struct lfsck_namespace *)com->lc_file_ram); handle = dt_trans_create(env, lfsck->li_bottom); if (IS_ERR(handle)) { rc = PTR_ERR(handle); CERROR("%s: fail to create trans for storing lfsck_namespace: " "rc = %d\n", lfsck_lfsck2name(lfsck), rc); RETURN(rc); } rc = dt_declare_xattr_set(env, obj, lfsck_buf_get(env, com->lc_file_disk, len), XATTR_NAME_LFSCK_NAMESPACE, 0, handle); if (rc != 0) { CERROR("%s: fail to declare trans for storing lfsck_namespace: " "rc = %d\n", lfsck_lfsck2name(lfsck), rc); GOTO(out, rc); } rc = dt_trans_start_local(env, lfsck->li_bottom, handle); if (rc != 0) { CERROR("%s: fail to start trans for storing lfsck_namespace: " "rc = %d\n", lfsck_lfsck2name(lfsck), rc); GOTO(out, rc); } rc = dt_xattr_set(env, obj, lfsck_buf_get(env, com->lc_file_disk, len), XATTR_NAME_LFSCK_NAMESPACE, init ? LU_XATTR_CREATE : LU_XATTR_REPLACE, handle, BYPASS_CAPA); if (rc != 0) CERROR("%s: fail to store lfsck_namespace: len = %d, " "rc = %d\n", lfsck_lfsck2name(lfsck), len, rc); GOTO(out, rc); out: dt_trans_stop(env, lfsck->li_bottom, handle); return rc; }
int lfsck_bookmark_store(const struct lu_env *env, struct lfsck_instance *lfsck) { struct thandle *handle; struct dt_object *obj = lfsck->li_bookmark_obj; loff_t pos = 0; int len = sizeof(struct lfsck_bookmark); int rc; ENTRY; lfsck_bookmark_cpu_to_le(&lfsck->li_bookmark_disk, &lfsck->li_bookmark_ram); handle = dt_trans_create(env, lfsck->li_bottom); if (IS_ERR(handle)) { rc = PTR_ERR(handle); CERROR("%s: fail to create trans for storing lfsck_bookmark: " "rc = %d\n", lfsck_lfsck2name(lfsck), rc); RETURN(rc); } rc = dt_declare_record_write(env, obj, lfsck_buf_get(env, &lfsck->li_bookmark_disk, len), 0, handle); if (rc != 0) { CERROR("%s: fail to declare trans for storing lfsck_bookmark: " "rc = %d\n", lfsck_lfsck2name(lfsck), rc); GOTO(out, rc); } rc = dt_trans_start_local(env, lfsck->li_bottom, handle); if (rc != 0) { CERROR("%s: fail to start trans for storing lfsck_bookmark: " "rc = %d\n", lfsck_lfsck2name(lfsck), rc); GOTO(out, rc); } rc = dt_record_write(env, obj, lfsck_buf_get(env, &lfsck->li_bookmark_disk, len), &pos, handle); if (rc != 0) CERROR("%s: fail to store lfsck_bookmark: expected = %d, " "rc = %d\n", lfsck_lfsck2name(lfsck), len, rc); GOTO(out, rc); out: dt_trans_stop(env, lfsck->li_bottom, handle); return rc; }
static int out_tx_start(const struct lu_env *env, struct dt_device *dt, struct thandle_exec_args *ta) { memset(ta, 0, sizeof(*ta)); ta->ta_handle = dt_trans_create(env, dt); if (IS_ERR(ta->ta_handle)) { CERROR("%s: start handle error: rc = %ld\n", dt_obd_name(dt), PTR_ERR(ta->ta_handle)); return PTR_ERR(ta->ta_handle); } ta->ta_dev = dt; /*For phase I, sync for cross-ref operation*/ ta->ta_handle->th_sync = 1; return 0; }
/** * Create new transaction in OFD. * * This function creates a transaction with dt_trans_create() * and makes it synchronous if required by the export state. * * \param[in] env execution environment * \param[in] ofd OFD device * * \retval struct thandle if transaction was created successfully * \retval ERR_PTR on negative value in case of error */ struct thandle *ofd_trans_create(const struct lu_env *env, struct ofd_device *ofd) { struct ofd_thread_info *info = ofd_info(env); struct thandle *th; LASSERT(info); th = dt_trans_create(env, ofd->ofd_osd); if (IS_ERR(th)) return th; /* export can require sync operations */ if (info->fti_exp != NULL) th->th_sync |= info->fti_exp->exp_need_sync; return th; }
/** * 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); }
static int out_tx_start(const struct lu_env *env, struct mdt_device *mdt, struct thandle_exec_args *th) { struct dt_device *dt = mdt->mdt_bottom; memset(th, 0, sizeof(*th)); th->ta_handle = dt_trans_create(env, dt); if (IS_ERR(th->ta_handle)) { CERROR("%s: start handle error: rc = %ld\n", mdt2obd_dev(mdt)->obd_name, PTR_ERR(th->ta_handle)); return PTR_ERR(th->ta_handle); } th->ta_dev = dt; /*For phase I, sync for cross-ref operation*/ th->ta_handle->th_sync = 1; return 0; }
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); }
static int write_capa_keys(const struct lu_env *env, struct mdt_device *mdt, struct lustre_capa_key *keys) { struct mdt_thread_info *mti; struct lustre_capa_key *tmp; struct thandle *th; loff_t off = 0; int i, rc; mti = lu_context_key_get(&env->le_ctx, &mdt_thread_key); th = dt_trans_create(env, mdt->mdt_bottom); if (IS_ERR(th)) RETURN(PTR_ERR(th)); rc = dt_declare_record_write(env, mdt->mdt_ck_obj, mdt_buf_const(env, NULL, sizeof(*tmp) * 3), 0, th); if (rc) goto stop; rc = dt_trans_start_local(env, mdt->mdt_bottom, th); if (rc) goto stop; tmp = &mti->mti_capa_key; for (i = 0; i < 2; i++) { lck_cpu_to_le(tmp, &keys[i]); rc = dt_record_write(env, mdt->mdt_ck_obj, mdt_buf_const(env, tmp, sizeof(*tmp)), &off, th); if (rc) break; } stop: dt_trans_stop(env, mdt->mdt_bottom, th); CDEBUG(D_INFO, "write capability keys rc = %d:\n", rc); return rc; }
/* * To enable DNE functionality we need FID of /ROOT directory * (which is / as seen by the clients) to belong to MDT0 and * not to FID_SEQ_LOCAL_FILE or some other local sequence, * which can be used by any node, so can't be part of FLDB. * * Pre-production code was using FID_SEQ_LOCAL_FILE for /ROOT * making few existing setups incompatibile with DNE. This * applies to ZFS-based setups only as ldiskfs-based setups * are still using IGIF to identify /ROOT. * * The intention of this code is to fix on-disk state to use * FID_SEQ_ROOT for /ROOT: * - "." and ".." references in /ROOT itself and it`s subdirectories * - LinkEA in all the objects listed in /ROOT * * Given only ZFS is affected where "." and ".." are not stored, we need to: * - delete "." and ".." from /ROOT and its subdirectories * - rename references in LinkEA in all the objects listed in /ROOT * * This code is subject for removal in 2.5 */ static int mdd_convert_remove_dots(const struct lu_env *env, struct mdd_device *mdd, struct mdd_object *o) { struct thandle *th; const struct dt_key *dot = (const struct dt_key *)"."; const struct dt_key *dotdot = (const struct dt_key *)".."; int rc; if (dt_try_as_dir(env, mdd_object_child(o)) == 0) RETURN(-ENOTDIR); /* remove "."/".." and do not insert them back - not stored in ZFS */ th = dt_trans_create(env, mdd->mdd_child); if (IS_ERR(th)) RETURN(PTR_ERR(th)); rc = dt_declare_delete(env, mdd_object_child(o), dot, th); if (rc) GOTO(out, rc); rc = dt_declare_delete(env, mdd_object_child(o), dotdot, th); if (rc) GOTO(out, rc); rc = dt_trans_start_local(env, mdd->mdd_child, th); if (rc) GOTO(out, rc); /* ignore non-existing "."/".." - we stored them on disk for * pre-production systems, but this is not how regular ZFS works */ rc = dt_delete(env, mdd_object_child(o), dot, th, BYPASS_CAPA); if (rc == -ENOENT) rc = 0; if (rc) GOTO(out, rc); rc = dt_delete(env, mdd_object_child(o), dotdot, th, BYPASS_CAPA); if (rc == -ENOENT) rc = 0; if (rc) GOTO(out, rc); out: dt_trans_stop(env, mdd->mdd_child, th); RETURN(rc); }
static int out_tx_start(const struct lu_env *env, struct dt_device *dt, struct thandle_exec_args *ta, struct obd_export *exp) { ta->ta_argno = 0; ta->ta_handle = dt_trans_create(env, dt); if (IS_ERR(ta->ta_handle)) { int rc; rc = PTR_ERR(ta->ta_handle); ta->ta_handle = NULL; CERROR("%s: start handle error: rc = %d\n", dt_obd_name(dt), rc); return rc; } if (exp->exp_need_sync) ta->ta_handle->th_sync = 1; return 0; }
int lfsck_bookmark_store(const struct lu_env *env, struct lfsck_instance *lfsck) { struct thandle *handle; struct dt_object *obj = lfsck->li_bookmark_obj; struct dt_device *dev = lfsck_obj2dev(obj); loff_t pos = 0; int len = sizeof(struct lfsck_bookmark); int rc; ENTRY; lfsck_bookmark_cpu_to_le(&lfsck->li_bookmark_disk, &lfsck->li_bookmark_ram); handle = dt_trans_create(env, dev); if (IS_ERR(handle)) GOTO(log, rc = PTR_ERR(handle)); rc = dt_declare_record_write(env, obj, lfsck_buf_get(env, &lfsck->li_bookmark_disk, len), 0, handle); if (rc != 0) GOTO(out, rc); rc = dt_trans_start_local(env, dev, handle); if (rc != 0) GOTO(out, rc); rc = dt_record_write(env, obj, lfsck_buf_get(env, &lfsck->li_bookmark_disk, len), &pos, handle); GOTO(out, rc); out: dt_trans_stop(env, dev, handle); log: if (rc != 0) CDEBUG(D_LFSCK, "%s: fail to store lfsck_bookmark: rc = %d\n", lfsck_lfsck2name(lfsck), rc); 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; }
/** * Read the special file which contains the list of llog catalogs IDs * * This function reads the CATALOGS file which contains the array of llog * catalogs IDs. The main purpose of this file is to store OSP llogs indexed * by OST/MDT number. * * \param[in] env execution environment * \param[in] d corresponding storage device * \param[in] idx position to start from, usually OST/MDT index * \param[in] count how many catalog IDs to read * \param[out] idarray the buffer for the data. If it is NULL then * function returns just number of catalog IDs * in the file. * \param[in] fid LLOG_CATALOGS_OID for CATALOG object * * \retval 0 on successful read of catalog IDs * \retval negative value on error * \retval positive value which is number of records in * the file if \a idarray is NULL */ int llog_osd_get_cat_list(const struct lu_env *env, struct dt_device *d, int idx, int count, struct llog_catid *idarray, const struct lu_fid *fid) { struct llog_thread_info *lgi = llog_info(env); struct dt_object *o = NULL; struct thandle *th; int rc, size; ENTRY; LASSERT(d); size = sizeof(*idarray) * count; lgi->lgi_off = idx * sizeof(*idarray); lgi->lgi_fid = *fid; o = dt_locate(env, d, &lgi->lgi_fid); if (IS_ERR(o)) RETURN(PTR_ERR(o)); if (!dt_object_exists(o)) { th = dt_trans_create(env, d); if (IS_ERR(th)) GOTO(out, rc = PTR_ERR(th)); lgi->lgi_attr.la_valid = LA_MODE; lgi->lgi_attr.la_mode = S_IFREG | S_IRUGO | S_IWUSR; lgi->lgi_dof.dof_type = dt_mode_to_dft(S_IFREG); rc = dt_declare_create(env, o, &lgi->lgi_attr, NULL, &lgi->lgi_dof, 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)) rc = dt_create(env, o, &lgi->lgi_attr, NULL, &lgi->lgi_dof, th); dt_write_unlock(env, o); out_trans: dt_trans_stop(env, d, th); if (rc) GOTO(out, rc); } rc = dt_attr_get(env, o, &lgi->lgi_attr, BYPASS_CAPA); if (rc) GOTO(out, rc); if (!S_ISREG(lgi->lgi_attr.la_mode)) { CERROR("%s: CATALOGS is not a regular file!: mode = %o\n", o->do_lu.lo_dev->ld_obd->obd_name, lgi->lgi_attr.la_mode); GOTO(out, rc = -ENOENT); } CDEBUG(D_CONFIG, "cat list: disk size=%d, read=%d\n", (int)lgi->lgi_attr.la_size, size); /* return just number of llogs */ if (idarray == NULL) { rc = lgi->lgi_attr.la_size / sizeof(*idarray); GOTO(out, rc); } /* read for new ost index or for empty file */ memset(idarray, 0, size); if (lgi->lgi_attr.la_size <= lgi->lgi_off) GOTO(out, rc = 0); if (lgi->lgi_attr.la_size < lgi->lgi_off + size) size = lgi->lgi_attr.la_size - lgi->lgi_off; lgi->lgi_buf.lb_buf = idarray; lgi->lgi_buf.lb_len = size; rc = dt_record_read(env, o, &lgi->lgi_buf, &lgi->lgi_off); if (rc) { CERROR("%s: error reading CATALOGS: rc = %d\n", o->do_lu.lo_dev->ld_obd->obd_name, rc); GOTO(out, rc); } EXIT; out: lu_object_put(env, &o->do_lu); 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); }
/* * Update slave or global index copy. * * \param env - the environment passed by the caller * \param qqi - is the qsd_type_info structure managing the index to be * update * \param qid - is the identifier for which we need to update the quota * settings * \param global - is set to true when updating the global index copy and to * false for the slave index copy. * \param ver - is the new version of the index. If equal to 0, the version * of the index isn't changed * \param rec - is the updated record to insert in the index file */ int qsd_update_index(const struct lu_env *env, struct qsd_qtype_info *qqi, union lquota_id *qid, bool global, __u64 ver, void *rec) { struct thandle *th = NULL; struct dt_object *obj; __u64 *new_verp = NULL; int flags = 0; int rc; ENTRY; obj = global ? qqi->qqi_glb_obj : qqi->qqi_slv_obj; /* allocate transaction */ th = dt_trans_create(env, qqi->qqi_qsd->qsd_dev); if (IS_ERR(th)) RETURN(PTR_ERR(th)); /* reserve enough credits to update record in index file */ rc = lquota_disk_declare_write(env, th, obj, qid); if (rc) GOTO(out, rc); /* start local transaction */ rc = dt_trans_start_local(env, qqi->qqi_qsd->qsd_dev, th); if (rc) GOTO(out, rc); if (global) { /* Update record in global index copy */ struct lquota_glb_rec *glb_rec = (struct lquota_glb_rec *)rec; CDEBUG(D_QUOTA, "%s: updating global index hardlimit: "LPU64", " "softlimit: "LPU64" for id "LPU64"\n", qqi->qqi_qsd->qsd_svname, glb_rec->qbr_hardlimit, glb_rec->qbr_softlimit, qid->qid_uid); } else { /* Update record in slave index copy */ struct lquota_slv_rec *slv_rec = (struct lquota_slv_rec *)rec; CDEBUG(D_QUOTA, "%s: update granted to "LPU64" for id "LPU64 "\n", qqi->qqi_qsd->qsd_svname, slv_rec->qsr_granted, qid->qid_uid); } if (ver != 0) { new_verp = &ver; flags = LQUOTA_SET_VER; } /* write new record to index file */ rc = lquota_disk_write(env, th, obj, qid, (struct dt_rec *)rec, flags, new_verp); EXIT; out: dt_trans_stop(env, qqi->qqi_qsd->qsd_dev, th); if (rc) CERROR("%s: failed to update %s index copy for id "LPU64", rc:" "%d\n", qqi->qqi_qsd->qsd_svname, global ? "global" : "slave", qid->qid_uid, rc); else if (flags == LQUOTA_SET_VER) qsd_bump_version(qqi, ver, global); 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); }
/* 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); }