示例#1
0
文件: fld_index.c 项目: hfeeki/lustre
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);
}
示例#2
0
文件: fid_store.c 项目: DCteam/lustre
/* 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);
}
示例#3
0
/*
 * 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);
}
示例#4
0
文件: fld_index.c 项目: DCteam/lustre
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);
}
示例#5
0
文件: llog.c 项目: 7799/linux
/**
 * 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;
}
示例#6
0
文件: llog.c 项目: 7799/linux
/*
 * 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;
}
示例#7
0
文件: fld_index.c 项目: hpc/lustre
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);
}
示例#8
0
文件: fld_index.c 项目: hpc/lustre
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);
}
示例#9
0
/*
 * Write a global record
 *
 * \param env - is the environment passed by the caller
 * \param obj - is the on-disk global index to be updated
 * \param id  - index to be updated
 * \param rec - record to be written
 */
int lquota_disk_write_glb(const struct lu_env *env, struct dt_object *obj,
			  __u64 id, struct lquota_glb_rec *rec)
{
	struct dt_device	*dev = lu2dt_dev(obj->do_lu.lo_dev);
	struct thandle		*th;
	struct dt_key		*key = (struct dt_key *)&id;
	int			 rc;
	ENTRY;

	th = dt_trans_create(env, dev);
	if (IS_ERR(th))
		RETURN(PTR_ERR(th));

	/* the entry with 0 key can always be found in IAM file. */
	if (id == 0) {
		rc = dt_declare_delete(env, obj, key, th);
		if (rc)
			GOTO(out, rc);
	}

	rc = dt_declare_insert(env, obj, (struct dt_rec *)rec, key, th);
	if (rc)
		GOTO(out, rc);

	rc = dt_trans_start_local(env, dev, th);
	if (rc)
		GOTO(out, rc);

	dt_write_lock(env, obj, 0);

	if (id == 0) {
		struct lquota_glb_rec *tmp;

		OBD_ALLOC_PTR(tmp);
		if (tmp == NULL)
			GOTO(out_lock, rc = -ENOMEM);

		rc = dt_lookup(env, obj, (struct dt_rec *)tmp, key,
			       BYPASS_CAPA);

		OBD_FREE_PTR(tmp);
		if (rc == 0) {
			rc = dt_delete(env, obj, key, th, BYPASS_CAPA);
			if (rc)
				GOTO(out_lock, rc);
		}
		rc = 0;
	}

	rc = dt_insert(env, obj, (struct dt_rec *)rec, key, th, BYPASS_CAPA, 1);
out_lock:
	dt_write_unlock(env, obj);
out:
	dt_trans_stop(env, dev, th);
	RETURN(rc);
}
示例#10
0
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);
}
示例#11
0
文件: fid_store.c 项目: DCteam/lustre
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);
}
示例#12
0
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);
}
示例#13
0
文件: fld_index.c 项目: DCteam/lustre
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);
}
示例#14
0
/**
 * 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);
}
示例#15
0
/**
 * 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;
}
示例#16
0
/*
 * 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;
}
示例#17
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);
}
示例#18
0
/**
 * 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;
}
示例#19
0
文件: fid_store.c 项目: DCteam/lustre
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;
}
示例#20
0
文件: fld_index.c 项目: DCteam/lustre
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);
}
示例#21
0
/**
 * 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;
}
示例#22
0
/**
 * 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);
}
示例#23
0
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;
}
示例#24
0
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);
}
示例#25
0
/* 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;
}
示例#26
0
/**
 * 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;
}
示例#27
0
/* 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);
}