// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2015, 2017, Intel Corporation. */ /* * This file is part of Lustre, http://www.lustre.org/ * * LOD sub object methods * * This file implements sub-object methods for LOD. * * LOD is Logic volume layer in the MDS stack, which will handle striping * and distribute the update to different OSP/OSD. After directing the updates * to one specific OSD/OSP, it also needs to do some thing before calling * OSD/OSP API, for example recording updates for cross-MDT operation, get * the next level transaction etc. * * Author: Di Wang */ #define DEBUG_SUBSYSTEM S_MDS #include #include #include #include #include #include #include #include #include #include #include "lod_internal.h" struct thandle *lod_sub_get_thandle(const struct lu_env *env, struct thandle *th, const struct dt_object *sub_obj, bool *record_update) { struct lod_device *lod = dt2lod_dev(th->th_dev); struct top_thandle *tth; struct thandle *sub_th; int type = LU_SEQ_RANGE_ANY; __u32 mdt_index; int rc; ENTRY; if (record_update != NULL) *record_update = false; if (th->th_top == NULL) RETURN(th); tth = container_of(th, struct top_thandle, tt_super); tth->tt_master_sub_thandle->th_ignore_quota = th->th_ignore_quota; tth->tt_master_sub_thandle->th_ignore_root_proj_quota = th->th_ignore_root_proj_quota; /* local object must be mdt object, Note: during ost object * creation, FID is not assigned until osp_create(), * so if the FID of sub_obj is zero, it means OST object. */ if (!dt_object_remote(sub_obj) || fid_is_zero(lu_object_fid(&sub_obj->do_lu))) { /* local MDT object */ if (fid_is_sane(lu_object_fid(&sub_obj->do_lu)) && tth->tt_multiple_thandle != NULL && record_update != NULL && th->th_result == 0) *record_update = true; RETURN(tth->tt_master_sub_thandle); } rc = lod_fld_lookup(env, lod, lu_object_fid(&sub_obj->do_lu), &mdt_index, &type); if (rc < 0) RETURN(ERR_PTR(rc)); /* th_complex means we need track all of updates for this * transaction, include changes on OST */ if (type == LU_SEQ_RANGE_OST && !th->th_complex) RETURN(tth->tt_master_sub_thandle); sub_th = thandle_get_sub(env, th, sub_obj); if (IS_ERR(sub_th)) RETURN(sub_th); sub_th->th_ignore_quota = th->th_ignore_quota; sub_th->th_ignore_root_proj_quota = th->th_ignore_root_proj_quota; if (tth->tt_multiple_thandle != NULL && record_update != NULL && th->th_result == 0) *record_update = true; RETURN(sub_th); } /** * lod_sub_declare_create() - Declare sub-object creation. * @env: execution environment * @dt: the object being created * @attr: the attributes of the object being created * @hint: the hint of the creation * @dof: the object format of the creation * @th: the transaction handle * * Get transaction of next layer and declare the creation of the object. * * Return: * * %0 if the declaration succeeds. * * %negative errno if the declaration fails. */ int lod_sub_declare_create(const struct lu_env *env, struct dt_object *dt, struct lu_attr *attr, struct dt_allocation_hint *hint, struct dt_object_format *dof, struct thandle *th) { struct thandle *sub_th; bool record_update; sub_th = lod_sub_get_thandle(env, th, dt, &record_update); if (IS_ERR(sub_th)) return PTR_ERR(sub_th); if (record_update) update_record_size(env, create, th, lu_object_fid(&dt->do_lu), attr, hint, dof); return dt_declare_create(env, dt, attr, hint, dof, sub_th); } /** * lod_sub_create() - Create sub-object. * @env: execution environment * @dt: the object being created * @attr: the attributes of the object being created * @hint: the hint of the creation * @dof: the object format of the creation * @th: the transaction handle * * Get transaction of next layer, record updates if it belongs to cross-MDT * operation, and create the object. * * Return: * * %0 if the creation succeeds. * * %negative errno if the creation fails. */ int lod_sub_create(const struct lu_env *env, struct dt_object *dt, struct lu_attr *attr, struct dt_allocation_hint *hint, struct dt_object_format *dof, struct thandle *th) { struct thandle *sub_th; bool record_update; int rc; ENTRY; sub_th = lod_sub_get_thandle(env, th, dt, &record_update); if (IS_ERR(sub_th)) RETURN(PTR_ERR(sub_th)); if (record_update) { rc = update_record_pack(create, th, lu_object_fid(&dt->do_lu), attr, hint, dof); if (rc < 0) RETURN(rc); } rc = dt_create(env, dt, attr, hint, dof, sub_th); RETURN(rc); } /** * lod_sub_declare_ref_add() - Declare adding reference for the sub-object * @env: execution environment * @dt: dt object to add reference * @th: transaction handle * * Get transaction of next layer and declare the reference adding. * * Return: * * %0 if the declaration succeeds. * * %negative errno if the declaration fails. */ int lod_sub_declare_ref_add(const struct lu_env *env, struct dt_object *dt, struct thandle *th) { struct thandle *sub_th; bool record_update; int rc; ENTRY; sub_th = lod_sub_get_thandle(env, th, dt, &record_update); if (IS_ERR(sub_th)) RETURN(PTR_ERR(sub_th)); if (record_update) update_record_size(env, ref_add, th, lu_object_fid(&dt->do_lu)); rc = dt_declare_ref_add(env, dt, sub_th); RETURN(rc); } /** * lod_sub_ref_add() - Add reference for the sub-object * @env: execution environment * @dt: dt object to add reference * @th: transaction handle * * Get transaction of next layer, record updates if it belongs to cross-MDT * operation and add reference of the object. * * Return: * * %0 if it succeeds. * * %negative errno if the addition fails. */ int lod_sub_ref_add(const struct lu_env *env, struct dt_object *dt, struct thandle *th) { struct thandle *sub_th; bool record_update; int rc; ENTRY; sub_th = lod_sub_get_thandle(env, th, dt, &record_update); if (IS_ERR(sub_th)) RETURN(PTR_ERR(sub_th)); if (record_update) { rc = update_record_pack(ref_add, th, lu_object_fid(&dt->do_lu)); if (rc < 0) RETURN(rc); } rc = dt_ref_add(env, dt, sub_th); RETURN(rc); } /** * lod_sub_declare_ref_del() - Declare deleting reference for the sub-object * @env: execution environment * @dt: dt object to delete reference * @th: transaction handle * * Get transaction of next layer and declare the reference deleting. * * Return: * * %0 if the declaration succeeds. * * %negative errno if the declaration fails. */ int lod_sub_declare_ref_del(const struct lu_env *env, struct dt_object *dt, struct thandle *th) { struct thandle *sub_th; bool record_update; int rc; ENTRY; sub_th = lod_sub_get_thandle(env, th, dt, &record_update); if (IS_ERR(sub_th)) RETURN(PTR_ERR(sub_th)); if (record_update) update_record_size(env, ref_del, th, lu_object_fid(&dt->do_lu)); rc = dt_declare_ref_del(env, dt, sub_th); RETURN(rc); } /** * lod_sub_ref_del() - Delete reference for the sub-object * @env: execution environment * @dt: dt object to delete reference * @th: transaction handle * * Get transaction of next layer, record updates if it belongs to cross-MDT * operation and delete reference of the object. * * Return: * * %0 0 if it succeeds. * * %negative errno if it fails. */ int lod_sub_ref_del(const struct lu_env *env, struct dt_object *dt, struct thandle *th) { struct thandle *sub_th; bool record_update; int rc; ENTRY; sub_th = lod_sub_get_thandle(env, th, dt, &record_update); if (IS_ERR(sub_th)) RETURN(PTR_ERR(sub_th)); if (record_update) { rc = update_record_pack(ref_del, th, lu_object_fid(&dt->do_lu)); if (rc < 0) RETURN(rc); } rc = dt_ref_del(env, dt, sub_th); RETURN(rc); } /** * lod_sub_declare_destroy() - Declare destroying sub-object * @env: execution environment * @dt: dt object to be destroyed * @th: transaction handle * * Get transaction of next layer and declare the sub-object destroy. * * Return: * * %0 if the declaration succeeds. * * %negative errno if the declaration fails. */ int lod_sub_declare_destroy(const struct lu_env *env, struct dt_object *dt, struct thandle *th) { struct thandle *sub_th; bool record_update; int rc; ENTRY; sub_th = lod_sub_get_thandle(env, th, dt, &record_update); if (IS_ERR(sub_th)) RETURN(PTR_ERR(sub_th)); if (record_update) update_record_size(env, destroy, th, lu_object_fid(&dt->do_lu)); rc = dt_declare_destroy(env, dt, sub_th); RETURN(rc); } /** * lod_sub_destroy() - Destroy sub-object * @env: execution environment * @dt: dt object to be destroyed * @th: transaction handle * * Get transaction of next layer, record updates if it belongs to cross-MDT * operation and destroy the object. * * Return: * * %0 if the destroy succeeds. * * %negative errno if the destroy fails. */ int lod_sub_destroy(const struct lu_env *env, struct dt_object *dt, struct thandle *th) { struct thandle *sub_th; bool record_update; int rc; ENTRY; sub_th = lod_sub_get_thandle(env, th, dt, &record_update); if (IS_ERR(sub_th)) RETURN(PTR_ERR(sub_th)); if (record_update) { rc = update_record_pack(destroy, th, lu_object_fid(&dt->do_lu)); if (rc < 0) RETURN(rc); } rc = dt_destroy(env, dt, sub_th); RETURN(rc); } /** * lod_sub_declare_insert() - Declare sub-object index insert * @env: execution environment * @dt: object for which to insert index * @rec: record of the index which will be inserted * @key: key of the index which will be inserted * @th: the transaction handle * * Get transaction of next layer and declare index insert. * * Return: * * %0 if the declaration succeeds. * * %negative errno if the declaration fails. */ int lod_sub_declare_insert(const struct lu_env *env, struct dt_object *dt, const struct dt_rec *rec, const struct dt_key *key, struct thandle *th) { struct thandle *sub_th; bool record_update; sub_th = lod_sub_get_thandle(env, th, dt, &record_update); if (IS_ERR(sub_th)) return PTR_ERR(sub_th); if (record_update) update_record_size(env, index_insert, th, lu_object_fid(&dt->do_lu), rec, key); return dt_declare_insert(env, dt, rec, key, sub_th); } /** * lod_sub_insert() - Insert index of sub object * @env: execution environment * @dt: object for which to insert index * @rec: record of the index to be inserted * @key: key of the index to be inserted * @th: the transaction handle * * Get transaction of next layer, record updates if it belongs to cross-MDT * operation, and insert the index. * * Return: * * %0 if the insertion succeeds. * * %negative errno if the insertion fails. */ int lod_sub_insert(const struct lu_env *env, struct dt_object *dt, const struct dt_rec *rec, const struct dt_key *key, struct thandle *th) { struct thandle *sub_th; int rc; bool record_update; sub_th = lod_sub_get_thandle(env, th, dt, &record_update); if (IS_ERR(sub_th)) return PTR_ERR(sub_th); if (record_update) { rc = update_record_pack(index_insert, th, lu_object_fid(&dt->do_lu), rec, key); if (rc < 0) return rc; } return dt_insert(env, dt, rec, key, sub_th); } /** * lod_sub_declare_delete() - Declare sub-object index delete * @env: execution environment * @dt: object for which to delete index * @key: key of the index which will be deleted * @th: the transaction handle * * Get transaction of next layer and declare index deletion. * * Return: * * %0 if the declaration succeeds. * * %negative errno if the declaration fails. */ int lod_sub_declare_delete(const struct lu_env *env, struct dt_object *dt, const struct dt_key *key, struct thandle *th) { struct thandle *sub_th; bool record_update; sub_th = lod_sub_get_thandle(env, th, dt, &record_update); if (IS_ERR(sub_th)) return PTR_ERR(sub_th); if (record_update) update_record_size(env, index_delete, th, lu_object_fid(&dt->do_lu), key); return dt_declare_delete(env, dt, key, sub_th); } /** * lod_sub_delete() - Delete index of sub object * @env: execution environment * @dt: object for which to delete index * @name: key name of the sub-object to be deleted * @th: the transaction handle * * Get transaction of next layer, record updates if it belongs to cross-MDT * operation, and delete the index. * * Return: * * %0 if the deletion succeeds. * * %negative errno if the deletion fails. */ int lod_sub_delete(const struct lu_env *env, struct dt_object *dt, const struct dt_key *name, struct thandle *th) { struct thandle *sub_th; bool record_update; int rc; ENTRY; sub_th = lod_sub_get_thandle(env, th, dt, &record_update); if (IS_ERR(sub_th)) RETURN(PTR_ERR(sub_th)); if (record_update) { rc = update_record_pack(index_delete, th, lu_object_fid(&dt->do_lu), name); if (rc < 0) RETURN(rc); } rc = dt_delete(env, dt, name, sub_th); RETURN(rc); } /** * lod_sub_declare_xattr_set() - Declare xattr_set * @env: execution environment * @dt: object on which to set xattr * @buf: xattr to be set * @name: name of the xattr * @fl: flag for setting xattr * @th: transaction handle * * Get transaction of next layer, and declare xattr set. * * Return: * * %0 if the declaration succeeds. * * %negative errno if the declaration fails. */ int lod_sub_declare_xattr_set(const struct lu_env *env, struct dt_object *dt, const struct lu_buf *buf, const char *name, int fl, struct thandle *th) { struct thandle *sub_th; bool record_update; int rc; ENTRY; sub_th = lod_sub_get_thandle(env, th, dt, &record_update); if (IS_ERR(sub_th)) RETURN(PTR_ERR(sub_th)); if (record_update) update_record_size(env, xattr_set, th, lu_object_fid(&dt->do_lu), buf, name, fl); rc = dt_declare_xattr_set(env, dt, buf, name, fl, sub_th); RETURN(rc); } /** * lod_sub_xattr_set() - Set xattr * @env: execution environment * @dt: object on which to set xattr * @buf: xattr to be set * @name: name of the xattr * @fl: flag for setting xattr * @th: transaction handle * * Get transaction of next layer, record updates if it belongs to cross-MDT * operation, and set xattr to the object. * * Return: * * %0 if the xattr setting succeeds. * * %negative errno if xattr setting fails. */ int lod_sub_xattr_set(const struct lu_env *env, struct dt_object *dt, const struct lu_buf *buf, const char *name, int fl, struct thandle *th) { struct thandle *sub_th; bool record_update; int rc; ENTRY; sub_th = lod_sub_get_thandle(env, th, dt, &record_update); if (IS_ERR(sub_th)) RETURN(PTR_ERR(sub_th)); if (record_update) { rc = update_record_pack(xattr_set, th, lu_object_fid(&dt->do_lu), buf, name, fl); if (rc < 0) RETURN(rc); } rc = dt_xattr_set(env, dt, buf, name, fl, sub_th); RETURN(rc); } /** * lod_sub_declare_attr_set() - Declare attr_set * @env: execution environment * @dt: object on which to set attr * @attr: attributes to be set * @th: transaction handle * * Get transaction of next layer, and declare attr set. * * Return: * * %0 if the declaration succeeds. * * %negative errno if the declaration fails. */ int lod_sub_declare_attr_set(const struct lu_env *env, struct dt_object *dt, const struct lu_attr *attr, struct thandle *th) { struct thandle *sub_th; bool record_update; int rc; ENTRY; sub_th = lod_sub_get_thandle(env, th, dt, &record_update); if (IS_ERR(sub_th)) RETURN(PTR_ERR(sub_th)); if (record_update) update_record_size(env, attr_set, th, lu_object_fid(&dt->do_lu), attr); rc = dt_declare_attr_set(env, dt, attr, sub_th); RETURN(rc); } /** * lod_sub_attr_set() - attributes set * @env: execution environment * @dt: object on which to set attr * @attr: attrbutes to be set * @th: transaction handle * * Get transaction of next layer, record updates if it belongs to cross-MDT * operation, and set attributes to the object. * * Return: * * %0 if attributes setting succeeds. * * %negative errno if the attributes setting fails. */ int lod_sub_attr_set(const struct lu_env *env, struct dt_object *dt, const struct lu_attr *attr, struct thandle *th) { bool record_update; struct thandle *sub_th; int rc; ENTRY; sub_th = lod_sub_get_thandle(env, th, dt, &record_update); if (IS_ERR(sub_th)) RETURN(PTR_ERR(sub_th)); if (record_update) { rc = update_record_pack(attr_set, th, lu_object_fid(&dt->do_lu), attr); if (rc < 0) RETURN(rc); } rc = dt_attr_set(env, dt, attr, sub_th); RETURN(rc); } /** * lod_sub_declare_xattr_del() - Declare xattr_del * @env: execution environment * @dt: object on which to delete xattr * @name: name of the xattr to be deleted * @th: transaction handle * * Get transaction of next layer, and declare xattr deletion. * * Return: * * %0 if the declaration succeeds. * * %negative errno if the declaration fails. */ int lod_sub_declare_xattr_del(const struct lu_env *env, struct dt_object *dt, const char *name, struct thandle *th) { struct thandle *sub_th; bool record_update; int rc; ENTRY; sub_th = lod_sub_get_thandle(env, th, dt, &record_update); if (IS_ERR(sub_th)) RETURN(PTR_ERR(sub_th)); if (record_update) update_record_size(env, xattr_del, th, lu_object_fid(&dt->do_lu), name); rc = dt_declare_xattr_del(env, dt, name, sub_th); RETURN(rc); } /** * lod_sub_xattr_del() - xattribute deletion * @env: execution environment * @dt: object on which to delete xattr * @name: name of the xattr to be deleted * @th: transaction handle * * Get transaction of next layer, record update if it belongs to cross-MDT * operation and delete xattr. * * Return: * * %0 if the deletion succeeds. * * %negative errno if the deletion fails. */ int lod_sub_xattr_del(const struct lu_env *env, struct dt_object *dt, const char *name, struct thandle *th) { struct thandle *sub_th; bool record_update; int rc; ENTRY; sub_th = lod_sub_get_thandle(env, th, dt, &record_update); if (IS_ERR(sub_th)) RETURN(PTR_ERR(sub_th)); if (record_update) { rc = update_record_pack(xattr_del, th, lu_object_fid(&dt->do_lu), name); if (rc < 0) RETURN(rc); } rc = dt_xattr_del(env, dt, name, sub_th); RETURN(rc); } /** * lod_sub_declare_write() - Declare buffer write * @env: execution environment * @dt: object to be written * @buf: buffer to write which includes an embedded size field * @pos: offet in the object to start writing at * @th: transaction handle * * Get transaction of next layer and declare buffer write. * * Return: * * %0 if the insertion succeeds. * * %negative errno if the insertion fails. */ int lod_sub_declare_write(const struct lu_env *env, struct dt_object *dt, const struct lu_buf *buf, loff_t pos, struct thandle *th) { struct thandle *sub_th; bool record_update; int rc; ENTRY; sub_th = lod_sub_get_thandle(env, th, dt, &record_update); if (IS_ERR(sub_th)) RETURN(PTR_ERR(sub_th)); if (record_update) update_record_size(env, write, th, lu_object_fid(&dt->do_lu), buf, pos); rc = dt_declare_write(env, dt, buf, pos, sub_th); RETURN(rc); } /** * lod_sub_write() - Write buffer to sub object * @env: execution environment * @dt: object to be written * @buf: buffer to write which includes an embedded size field * @pos: offet in the object to start writing at * @th: transaction handle * * Get transaction of next layer, records buffer write if it belongs to * Cross-MDT operation, and write buffer. * * Return: * * %size in bytes(buffer) if it succeeds. * * %negative errno if the insertion fails. */ ssize_t lod_sub_write(const struct lu_env *env, struct dt_object *dt, const struct lu_buf *buf, loff_t *pos, struct thandle *th) { struct thandle *sub_th; bool record_update; ssize_t rc; ENTRY; sub_th = lod_sub_get_thandle(env, th, dt, &record_update); if (IS_ERR(sub_th)) RETURN(PTR_ERR(sub_th)); if (record_update) { rc = update_record_pack(write, th, lu_object_fid(&dt->do_lu), buf, *pos); if (rc < 0) RETURN(rc); } rc = dt_write(env, dt, buf, pos, sub_th); RETURN(rc); } /** * lod_sub_declare_punch() - Declare punch * @env: execution environment * @dt: object to be written * @start: start offset of punch * @end: end offet of punch * @th: transaction handle * * Get transaction of next layer and declare punch. * * Return: * * %0 if the insertion succeeds. * * %negative errno if the insertion fails. */ int lod_sub_declare_punch(const struct lu_env *env, struct dt_object *dt, __u64 start, __u64 end, struct thandle *th) { struct thandle *sub_th; bool record_update; int rc; ENTRY; sub_th = lod_sub_get_thandle(env, th, dt, &record_update); if (IS_ERR(sub_th)) RETURN(PTR_ERR(sub_th)); if (record_update) update_record_size(env, punch, th, lu_object_fid(&dt->do_lu), start, end); rc = dt_declare_punch(env, dt, start, end, sub_th); RETURN(rc); } /** * lod_sub_punch() - Punch to sub object * @env: execution environment * @dt: object to be written * @start: start offset of punch * @end: end offset of punch * @th: transaction handle * * Get transaction of next layer, records buffer write if it belongs to * Cross-MDT operation, and punch object. * * Return: * * %size in bytes(buffer) if it succeeds. * * %negative errno if it fails. */ int lod_sub_punch(const struct lu_env *env, struct dt_object *dt, __u64 start, __u64 end, struct thandle *th) { struct thandle *sub_th; bool record_update; int rc; ENTRY; sub_th = lod_sub_get_thandle(env, th, dt, &record_update); if (IS_ERR(sub_th)) RETURN(PTR_ERR(sub_th)); if (record_update) { rc = update_record_pack(punch, th, lu_object_fid(&dt->do_lu), start, end); if (rc < 0) RETURN(rc); } rc = dt_punch(env, dt, start, end, sub_th); RETURN(rc); } int lod_sub_prep_llog(const struct lu_env *env, struct lod_device *lod, struct dt_device *dt, int index) { struct lod_thread_info *lti = lod_env_info(env); struct llog_ctxt *ctxt; struct llog_handle *lgh; struct llog_catid *cid = <i->lti_cid; struct lu_fid *fid = <i->lti_fid; struct obd_device *obd; int rc; bool need_put = false; ENTRY; lu_update_log_fid(fid, index); rc = lodname2mdt_index(lod2obd(lod)->obd_name, (__u32 *)&index); if (rc < 0) RETURN(rc); rc = llog_osd_get_cat_list(env, dt, index, 1, cid, fid); if (rc != 0) { CERROR("%s: can't get id from catalogs: rc = %d\n", lod2obd(lod)->obd_name, rc); RETURN(rc); } obd = dt->dd_lu_dev.ld_obd; ctxt = llog_get_context(obd, LLOG_UPDATELOG_ORIG_CTXT); LASSERT(ctxt != NULL); /* concurrent config processing (e.g. setting MDT active) * can try to initialize llog again before causing double * initialization. check for this */ if (ctxt->loc_handle) GOTO(out_put, rc = 0); ctxt->loc_flags |= LLOG_CTXT_FLAG_NORMAL_FID; ctxt->loc_chunk_size = LLOG_MIN_CHUNK_SIZE * 4; if (likely(logid_id(&cid->lci_logid) != 0)) { rc = llog_open(env, ctxt, &lgh, &cid->lci_logid, NULL, LLOG_OPEN_EXISTS); /* re-create llog if it is missing */ if (rc == -ENOENT || rc == -EREMCHG) { logid_set_id(&cid->lci_logid, 0); } else if (rc < 0) { CWARN("%s: can't open llog "DFID": rc = %d\n", lod2obd(lod)->obd_name, PLOGID(&cid->lci_logid), rc); GOTO(out_put, rc); } } if (unlikely(logid_id(&cid->lci_logid) == 0)) { renew: rc = llog_open_create(env, ctxt, &lgh, NULL, NULL); if (rc < 0) { CWARN("%s: can't create new llog: rc = %d\n", lod2obd(lod)->obd_name, rc); GOTO(out_put, rc); } cid->lci_logid = lgh->lgh_id; need_put = true; } LASSERT(lgh != NULL); rc = llog_init_handle(env, lgh, LLOG_F_IS_CAT, NULL); if (rc) { /* Update llog is incorrect, renew it */ if (rc == -EINVAL && need_put == false) { CWARN("%s: renew invalid update log "DFID": rc = %d\n", lod2obd(lod)->obd_name, PLOGID(&cid->lci_logid), rc); llog_cat_close(env, lgh); GOTO(renew, 0); } GOTO(out_close, rc); } if (need_put) { rc = llog_osd_put_cat_list(env, dt, index, 1, cid, fid); if (rc) { CERROR("%s: can't update id in catalogs: rc = %d\n", lod2obd(lod)->obd_name, rc); GOTO(out_close, rc); } } LASSERT(!ctxt->loc_handle); ctxt->loc_handle = lgh; CDEBUG(D_INFO, "%s: init llog for index %d - catid "DFID"\n", obd->obd_name, index, PLOGID(&cid->lci_logid)); out_close: if (rc != 0) llog_cat_close(env, lgh); out_put: llog_ctxt_put(ctxt); RETURN(rc); }