Example #1
0
static int out_tx_index_insert_exec(struct mdt_thread_info *info,
				    struct thandle *th, struct tx_arg *arg)
{
	struct dt_object *dt_obj = arg->object;
	int rc;

	LASSERT(dt_obj != NULL && !IS_ERR(dt_obj));

	CDEBUG(D_OTHER, "index insert "DFID" name: %s fid "DFID"\n",
	       PFID(lu_object_fid(&arg->object->do_lu)),
	       (char *)arg->u.insert.key,
	       PFID((struct lu_fid *)arg->u.insert.rec));

	if (dt_try_as_dir(info->mti_env, dt_obj) == 0)
		return -ENOTDIR;

	dt_write_lock(info->mti_env, dt_obj, MOR_TGT_CHILD);
	rc = dt_insert(info->mti_env, dt_obj, arg->u.insert.rec,
		       arg->u.insert.key, th, NULL, 0);
	dt_write_unlock(info->mti_env, dt_obj);

	update_insert_reply(arg->reply, NULL, 0, arg->index, rc);

	return rc;
}
Example #2
0
static int out_tx_index_insert_undo(struct mdt_thread_info *info,
				    struct thandle *th, struct tx_arg *arg)
{
	struct dt_object *dt_obj = arg->object;
	int rc;

	LASSERT(dt_obj != NULL && !IS_ERR(dt_obj));

	CDEBUG(D_OTHER, "index delete "DFID" name: %s\n",
	       PFID(lu_object_fid(&arg->object->do_lu)),
	       (char *)arg->u.insert.key);

	if (dt_try_as_dir(info->mti_env, dt_obj) == 0) {
		CERROR("%s: "DFID" is not directory: rc = %d\n",
		       mdt_obd_name(info->mti_mdt),
		       PFID(lu_object_fid(&dt_obj->do_lu)), -ENOTDIR);
		return -ENOTDIR;
	}

	dt_write_lock(info->mti_env, dt_obj, MOR_TGT_CHILD);
	rc = dt_delete(info->mti_env, dt_obj, arg->u.insert.key, th, NULL);
	dt_write_unlock(info->mti_env, dt_obj);

	update_insert_reply(arg->reply, NULL, 0, arg->index, rc);

	return rc;
}
Example #3
0
int out_tx_create_exec(struct mdt_thread_info *info, struct thandle *th,
		       struct tx_arg *arg)
{
	struct dt_object *dt_obj = arg->object;
	int rc;

	LASSERT(dt_obj != NULL && !IS_ERR(dt_obj));

	CDEBUG(D_OTHER, "create "DFID": dof %u, mode %o\n",
	       PFID(lu_object_fid(&arg->object->do_lu)),
	       arg->u.create.dof.dof_type,
	       arg->u.create.attr.la_mode & S_IFMT);

	dt_write_lock(info->mti_env, dt_obj, MOR_TGT_CHILD);
	rc = dt_create(info->mti_env, dt_obj, &arg->u.create.attr,
		       &arg->u.create.hint, &arg->u.create.dof, th);

	dt_write_unlock(info->mti_env, dt_obj);
	CDEBUG(D_INFO, "insert create reply mode %o index %d\n",
	       arg->u.create.attr.la_mode, arg->index);

	update_insert_reply(arg->reply, NULL, 0, arg->index, rc);

	return rc;
}
Example #4
0
static int llog_osd_pad(const struct lu_env *env, struct dt_object *o,
			loff_t *off, int len, int index, struct thandle *th)
{
	struct llog_thread_info	*lgi = llog_info(env);
	int			 rc;

	LASSERT(th);
	LASSERT(off);
	LASSERT(len >= LLOG_MIN_REC_SIZE && (len & 0x7) == 0);

	lgi->lgi_tail.lrt_len = lgi->lgi_lrh.lrh_len = len;
	lgi->lgi_tail.lrt_index = lgi->lgi_lrh.lrh_index = index;
	lgi->lgi_lrh.lrh_type = LLOG_PAD_MAGIC;

	lgi->lgi_buf.lb_buf = &lgi->lgi_lrh;
	lgi->lgi_buf.lb_len = sizeof(lgi->lgi_lrh);
	dt_write_lock(env, o, 0);
	rc = dt_record_write(env, o, &lgi->lgi_buf, off, th);
	if (rc) {
		CERROR("%s: error writing padding record: rc = %d\n",
		       o->do_lu.lo_dev->ld_obd->obd_name, rc);
		GOTO(out, rc);
	}

	lgi->lgi_buf.lb_buf = &lgi->lgi_tail;
	lgi->lgi_buf.lb_len = sizeof(lgi->lgi_tail);
	*off += len - sizeof(lgi->lgi_lrh) - sizeof(lgi->lgi_tail);
	rc = dt_record_write(env, o, &lgi->lgi_buf, off, th);
	if (rc)
		CERROR("%s: error writing padding record: rc = %d\n",
		       o->do_lu.lo_dev->ld_obd->obd_name, rc);
out:
	dt_write_unlock(env, o);
	return rc;
}
Example #5
0
int out_tx_create_exec(const struct lu_env *env, struct thandle *th,
		       struct tx_arg *arg)
{
	struct dt_object	*dt_obj = arg->object;
	int			 rc;

	CDEBUG(D_OTHER, "%s: create "DFID": dof %u, mode %o\n",
	       dt_obd_name(th->th_dev),
	       PFID(lu_object_fid(&arg->object->do_lu)),
	       arg->u.create.dof.dof_type,
	       arg->u.create.attr.la_mode & S_IFMT);

	dt_write_lock(env, dt_obj, MOR_TGT_CHILD);
	rc = dt_create(env, dt_obj, &arg->u.create.attr,
		       &arg->u.create.hint, &arg->u.create.dof, th);

	dt_write_unlock(env, dt_obj);

	CDEBUG(D_INFO, "%s: insert create reply %p index %d: rc = %d\n",
	       dt_obd_name(th->th_dev), arg->reply, arg->index, rc);

	update_insert_reply(arg->reply, NULL, 0, arg->index, rc);

	return rc;
}
Example #6
0
static int out_tx_xattr_set_exec(const struct lu_env *env,
				 struct thandle *th,
				 struct tx_arg *arg)
{
	struct dt_object *dt_obj = arg->object;
	int rc;

	CDEBUG(D_INFO, "%s: set xattr buf %p name %s flag %d\n",
	       dt_obd_name(th->th_dev), arg->u.xattr_set.buf.lb_buf,
	       arg->u.xattr_set.name, arg->u.xattr_set.flags);

	dt_write_lock(env, dt_obj, MOR_TGT_CHILD);
	rc = dt_xattr_set(env, dt_obj, &arg->u.xattr_set.buf,
			  arg->u.xattr_set.name, arg->u.xattr_set.flags,
			  th, NULL);
	dt_write_unlock(env, dt_obj);
	/**
	 * Ignore errors if this is LINK EA
	 **/
	if (unlikely(rc && !strncmp(arg->u.xattr_set.name, XATTR_NAME_LINK,
				    strlen(XATTR_NAME_LINK))))
		rc = 0;

	CDEBUG(D_INFO, "%s: insert xattr set reply %p index %d: rc = %d\n",
	       dt_obd_name(th->th_dev), arg->reply, arg->index, rc);

	update_insert_reply(arg->reply, NULL, 0, arg->index, rc);

	return rc;
}
Example #7
0
static int out_tx_xattr_set_exec(struct mdt_thread_info *info,
				 struct thandle *th,
				 struct tx_arg *arg)
{
	struct dt_object *dt_obj = arg->object;
	int rc;

	LASSERT(dt_obj != NULL && !IS_ERR(dt_obj));

	CDEBUG(D_OTHER, "attr set "DFID"\n",
	       PFID(lu_object_fid(&arg->object->do_lu)));

	dt_write_lock(info->mti_env, dt_obj, MOR_TGT_CHILD);
	rc = dt_xattr_set(info->mti_env, dt_obj, &arg->u.xattr_set.buf,
			  arg->u.xattr_set.name, arg->u.xattr_set.flags,
			  th, NULL);
	dt_write_unlock(info->mti_env, dt_obj);
	/**
	 * Ignore errors if this is LINK EA
	 **/
	if (unlikely(rc && !strncmp(arg->u.xattr_set.name, XATTR_NAME_LINK,
				    strlen(XATTR_NAME_LINK))))
		rc = 0;

	update_insert_reply(arg->reply, NULL, 0, arg->index, rc);

	CDEBUG(D_INFO, "set xattr buf %p name %s flag %d\n",
	       arg->u.xattr_set.buf.lb_buf, arg->u.xattr_set.name,
	       arg->u.xattr_set.flags);

	return rc;
}
Example #8
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);
}
Example #9
0
/**
 * Implementation of the llog_operations::lop_create
 *
 * This function creates the llog according with llog_handle::lgh_obj
 * and llog_handle::lgh_name.
 *
 * \param[in] env	execution environment
 * \param[in] res	llog handle of the current llog
 * \param[in] th	current transaction handle
 *
 * \retval		0 on successful create
 * \retval		negative value on error
 */
static int llog_osd_create(const struct lu_env *env, struct llog_handle *res,
			   struct thandle *th)
{
	struct llog_thread_info *lgi = llog_info(env);
	struct dt_insert_rec	*rec = &lgi->lgi_dt_rec;
	struct local_oid_storage *los;
	struct dt_object        *o;
	int                      rc = 0;

	ENTRY;

	LASSERT(env);
	o = res->lgh_obj;
	LASSERT(o);

	/* llog can be already created */
	if (dt_object_exists(o))
		RETURN(-EEXIST);

	los = res->private_data;
	LASSERT(los);

	dt_write_lock(env, o, 0);
	if (!dt_object_exists(o))
		rc = llog_osd_create_new_object(env, los, o, th);
	else
		rc = -EEXIST;

	dt_write_unlock(env, o);
	if (rc)
		RETURN(rc);

	if (res->lgh_name) {
		struct dt_object *llog_dir;

		llog_dir = llog_osd_dir_get(env, res->lgh_ctxt);
		if (IS_ERR(llog_dir))
			RETURN(PTR_ERR(llog_dir));

		logid_to_fid(&res->lgh_id, &lgi->lgi_fid);
		rec->rec_fid = &lgi->lgi_fid;
		rec->rec_type = S_IFREG;
		dt_read_lock(env, llog_dir, 0);
		rc = dt_insert(env, llog_dir, (struct dt_rec *)rec,
			       (struct dt_key *)res->lgh_name,
			       th, BYPASS_CAPA, 1);
		dt_read_unlock(env, llog_dir);
		lu_object_put(env, &llog_dir->do_lu);
		if (rc)
			CERROR("%s: can't create named llog %s: rc = %d\n",
			       o->do_lu.lo_dev->ld_obd->obd_name,
			       res->lgh_name, rc);
	}
	RETURN(rc);
}
Example #10
0
static int out_obj_ref_del(const struct lu_env *env,
			   struct dt_object *dt_obj,
			   struct thandle *th)
{
	int rc;

	dt_write_lock(env, dt_obj, MOR_TGT_CHILD);
	rc = dt_ref_del(env, dt_obj, th);
	dt_write_unlock(env, dt_obj);

	return rc;
}
Example #11
0
static int out_obj_destroy(const struct lu_env *env, struct dt_object *dt_obj,
			   struct thandle *th)
{
	int rc;

	CDEBUG(D_INFO, "%s: destroy "DFID"\n", dt_obd_name(th->th_dev),
	       PFID(lu_object_fid(&dt_obj->do_lu)));

	dt_write_lock(env, dt_obj, MOR_TGT_CHILD);
	rc = dt_destroy(env, dt_obj, th);
	dt_write_unlock(env, dt_obj);

	return rc;
}
Example #12
0
static int out_tx_ref_add_undo(struct mdt_thread_info *info, struct thandle *th,
			       struct tx_arg *arg)
{
	struct dt_object *dt_obj = arg->object;

	LASSERT(dt_obj != NULL && !IS_ERR(dt_obj));

	CDEBUG(D_OTHER, "ref del "DFID"\n",
	       PFID(lu_object_fid(&arg->object->do_lu)));

	dt_write_lock(info->mti_env, dt_obj, MOR_TGT_CHILD);
	dt_ref_del(info->mti_env, dt_obj, th);
	dt_write_unlock(info->mti_env, dt_obj);

	return 0;
}
Example #13
0
static int out_tx_ref_add_exec(struct mdt_thread_info *info, struct thandle *th,
			       struct tx_arg *arg)
{
	struct dt_object *dt_obj = arg->object;

	LASSERT(dt_obj != NULL && !IS_ERR(dt_obj));

	CDEBUG(D_OTHER, "ref add "DFID"\n",
	       PFID(lu_object_fid(&arg->object->do_lu)));

	dt_write_lock(info->mti_env, dt_obj, MOR_TGT_CHILD);
	dt_ref_add(info->mti_env, dt_obj, th);
	dt_write_unlock(info->mti_env, dt_obj);

	update_insert_reply(arg->reply, NULL, 0, arg->index, 0);
	return 0;
}
Example #14
0
/**
 *  add an orphan \a obj to the orphan index.
 *  \param obj file or directory.
 *  \param th  transaction for index insert.
 *
 *  \pre obj nlink == 0 && obj->mod_count != 0
 *
 *  \retval 0  success
 *  \retval  -ve index operation error.
 */
int mdd_orphan_insert(const struct lu_env *env, struct mdd_object *obj,
		      struct thandle *th)
{
	struct mdd_device *mdd = mdo2mdd(&obj->mod_obj);
	struct dt_object *dor = mdd->mdd_orphans;
	const struct lu_fid *lf_dor = lu_object_fid(&dor->do_lu);
	struct dt_object *next = mdd_object_child(obj);
	struct dt_insert_rec *rec = &mdd_env_info(env)->mti_dt_rec;
	int rc;
	ENTRY;

	LASSERT(mdd_write_locked(env, obj) != 0);
	LASSERT(!(obj->mod_flags & ORPHAN_OBJ));

	dt_write_lock(env, mdd->mdd_orphans, MOR_TGT_ORPHAN);

	rc = mdd_orphan_insert_obj(env, mdd, obj, th);
	if (rc)
		GOTO(out, rc);

	mdo_ref_add(env, obj, th);
	if (!S_ISDIR(mdd_object_type(obj)))
		GOTO(out, rc = 0);

	mdo_ref_add(env, obj, th);
	dt_ref_add(env, mdd->mdd_orphans, th);

	/* try best to fixup directory, do not return errors from here */
	if (!dt_try_as_dir(env, next))
		GOTO(out, rc = 0);

	dt_delete(env, next, (const struct dt_key *)dotdot, th);

	rec->rec_fid = lf_dor;
	rec->rec_type = S_IFDIR;
	dt_insert(env, next, (const struct dt_rec *)rec,
		  (const struct dt_key *)dotdot, th);

out:
	if (rc == 0)
		obj->mod_flags |= ORPHAN_OBJ;

	dt_write_unlock(env, mdd->mdd_orphans);

	RETURN(rc);
}
Example #15
0
/**
 *  delete an orphan \a obj from orphan index.
 *  \param obj file or directory.
 *  \param th  transaction for index deletion and object destruction.
 *
 *  \pre obj->mod_count == 0 && ORPHAN_OBJ is set for obj.
 *
 *  \retval 0  success
 *  \retval  -ve index operation error.
 */
int mdd_orphan_delete(const struct lu_env *env, struct mdd_object *obj,
		      struct thandle *th)
{
	struct mdd_device *mdd = mdo2mdd(&obj->mod_obj);
	struct dt_object *dor = mdd->mdd_orphans;
	struct dt_key *key;
	int rc = 0;

	ENTRY;

	LASSERT(mdd_write_locked(env, obj) != 0);
	LASSERT(obj->mod_flags & ORPHAN_OBJ);
	LASSERT(obj->mod_count == 0);

	LASSERT(dor);

	key = mdd_orphan_key_fill(env, mdo2fid(obj));
	dt_write_lock(env, mdd->mdd_orphans, MOR_TGT_ORPHAN);

	if (OBD_FAIL_CHECK(OBD_FAIL_MDS_ORPHAN_DELETE))
		goto ref_del;

	rc = dt_delete(env, mdd->mdd_orphans, key, th);
	if (rc == -ENOENT) {
		key = mdd_orphan_key_fill_20(env, mdo2fid(obj));
		rc = dt_delete(env, mdd->mdd_orphans, key, th);
	}

ref_del:
	if (!rc) {
		/* lov objects will be destroyed by caller */
		mdo_ref_del(env, obj, th);
		if (S_ISDIR(mdd_object_type(obj))) {
			mdo_ref_del(env, obj, th);
			dt_ref_del(env, mdd->mdd_orphans, th);
		}
		obj->mod_flags &= ~ORPHAN_OBJ;
	} else {
		CERROR("%s: could not delete orphan object "DFID": rc = %d\n",
		       mdd2obd_dev(mdd)->obd_name, PFID(mdo2fid(obj)), rc);
	}

	dt_write_unlock(env, mdd->mdd_orphans);
	RETURN(rc);
}
Example #16
0
/**
 * All of the xxx_undo will be used once execution failed,
 * But because all of the required resource has been reserved in
 * declare phase, i.e. if declare succeed, it should make sure
 * the following executing phase succeed in anyway, so these undo
 * should be useless for most of the time in Phase I
 **/
int out_tx_create_undo(struct mdt_thread_info *info, struct thandle *th,
		       struct tx_arg *arg)
{
	struct dt_object *dt_obj = arg->object;
	int rc;

	LASSERT(dt_obj != NULL && !IS_ERR(dt_obj));

	dt_write_lock(info->mti_env, dt_obj, MOR_TGT_CHILD);
	rc = dt_destroy(info->mti_env, dt_obj, th);
	dt_write_unlock(info->mti_env, dt_obj);

	/* we don't like double failures */
	if (rc != 0)
		CERROR("%s: undo failure, we are doomed!: rc = %d\n",
		       mdt_obd_name(info->mti_mdt), rc);
	return rc;
}
Example #17
0
static int out_tx_write_exec(const struct lu_env *env, struct thandle *th,
			     struct tx_arg *arg)
{
	struct dt_object *dt_obj = arg->object;
	int rc;

	dt_write_lock(env, dt_obj, MOR_TGT_CHILD);
	rc = dt_record_write(env, dt_obj, &arg->u.write.buf,
			     &arg->u.write.pos, th);
	dt_write_unlock(env, dt_obj);

	if (rc == 0)
		rc = arg->u.write.buf.lb_len;

	object_update_result_insert(arg->reply, NULL, 0, arg->index, rc);

	return rc > 0 ? 0 : rc;
}
Example #18
0
static int out_obj_index_delete(const struct lu_env *env,
				struct dt_object *dt_obj,
				const struct dt_key *key,
				struct thandle *th)
{
	int rc;

	CDEBUG(D_INFO, "%s: index delete "DFID" name: %s\n",
	       dt_obd_name(th->th_dev), PFID(lu_object_fid(&dt_obj->do_lu)),
	       (char *)key);

	if (dt_try_as_dir(env, dt_obj) == 0)
		return -ENOTDIR;

	dt_write_lock(env, dt_obj, MOR_TGT_CHILD);
	rc = dt_delete(env, dt_obj, key, th, NULL);
	dt_write_unlock(env, dt_obj);

	return rc;
}
Example #19
0
static int out_tx_attr_set_exec(struct mdt_thread_info *info,
				struct thandle *th, struct tx_arg *arg)
{
	struct dt_object	*dt_obj = arg->object;
	int			rc;

	LASSERT(dt_obj != NULL && !IS_ERR(dt_obj));

	CDEBUG(D_OTHER, "attr set "DFID"\n",
	       PFID(lu_object_fid(&arg->object->do_lu)));

	dt_write_lock(info->mti_env, dt_obj, MOR_TGT_CHILD);
	rc = dt_attr_set(info->mti_env, dt_obj, &arg->u.attr_set.attr,
			 th, NULL);
	dt_write_unlock(info->mti_env, dt_obj);

	update_insert_reply(arg->reply, NULL, 0, arg->index, rc);

	return rc;
}
Example #20
0
static int out_tx_attr_set_exec(const struct lu_env *env, struct thandle *th,
				struct tx_arg *arg)
{
	struct dt_object	*dt_obj = arg->object;
	int			rc;

	CDEBUG(D_OTHER, "%s: attr set "DFID"\n", dt_obd_name(th->th_dev),
	       PFID(lu_object_fid(&dt_obj->do_lu)));

	dt_write_lock(env, dt_obj, MOR_TGT_CHILD);
	rc = dt_attr_set(env, dt_obj, &arg->u.attr_set.attr, th, NULL);
	dt_write_unlock(env, dt_obj);

	CDEBUG(D_INFO, "%s: insert attr_set reply %p index %d: rc = %d\n",
	       dt_obd_name(th->th_dev), arg->reply, arg->index, rc);

	update_insert_reply(arg->reply, NULL, 0, arg->index, rc);

	return rc;
}
Example #21
0
static int out_obj_index_insert(const struct lu_env *env,
				struct dt_object *dt_obj,
				const struct dt_rec *rec,
				const struct dt_key *key,
				struct thandle *th)
{
	int rc;

	CDEBUG(D_INFO, "%s: index insert "DFID" name: %s fid "DFID"\n",
	       dt_obd_name(th->th_dev), PFID(lu_object_fid(&dt_obj->do_lu)),
	       (char *)key, PFID((struct lu_fid *)rec));

	if (dt_try_as_dir(env, dt_obj) == 0)
		return -ENOTDIR;

	dt_write_lock(env, dt_obj, MOR_TGT_CHILD);
	rc = dt_insert(env, dt_obj, rec, key, th, NULL, 0);
	dt_write_unlock(env, dt_obj);

	return rc;
}
Example #22
0
/*
 * Update a record in a quota index file.
 *
 * \param env - is the environment passed by the caller
 * \param th  - is the transaction to use for disk writes
 * \param obj - is the on-disk index to be updated.
 * \param id  - is the key to be updated
 * \param rec - is the input record containing the new quota settings.
 * \param flags - can be LQUOTA_BUMP_VER or LQUOTA_SET_VER.
 * \param ver   - is the new version of the index if LQUOTA_SET_VER is set or is
 *                used to return the new version of the index when
 *                LQUOTA_BUMP_VER is set.
 *
 * \retval    - 0 on success, appropriate error on failure
 */
int lquota_disk_write(const struct lu_env *env, struct thandle *th,
		      struct dt_object *obj, union lquota_id *id,
		      struct dt_rec *rec, __u32 flags, __u64 *ver)
{
	struct lquota_thread_info	*qti = lquota_info(env);
	struct dt_key			*key = (struct dt_key *)&id->qid_uid;
	int				 rc;
	ENTRY;

	LASSERT(dt_object_exists(obj));
	LASSERT(obj->do_index_ops != NULL);

	/* lock index */
	dt_write_lock(env, obj, 0);

	/* check whether there is already an existing record for this ID */
	rc = dt_lookup(env, obj, (struct dt_rec *)&qti->qti_rec, key,
		       BYPASS_CAPA);
	if (rc == 0) {
		/* delete existing record in order to replace it */
		rc = dt_delete(env, obj, key, th, BYPASS_CAPA);
		if (rc)
			GOTO(out, rc);
	} else if (rc == -ENOENT) {
		/* probably first insert */
		rc = 0;
	} else {
		GOTO(out, rc);
	}

	if (rec != NULL) {
		/* insert record with updated quota settings */
		rc = dt_insert(env, obj, rec, key, th, BYPASS_CAPA, 1);
		if (rc) {
			/* try to insert the old one */
			rc = dt_insert(env, obj, (struct dt_rec *)&qti->qti_rec,
				       key, th, BYPASS_CAPA, 1);
			LASSERTF(rc == 0, "failed to insert record in quota "
			         "index "DFID,
				 PFID(lu_object_fid(&obj->do_lu)));
			GOTO(out, rc);
		}
	}

	if (flags != 0) {
		LASSERT(ver);
		if (flags & LQUOTA_BUMP_VER) {
			/* caller wants to bump the version, let's first read
			 * it */
			*ver = dt_version_get(env, obj);
			(*ver)++;
		} else {
			LASSERT(flags & LQUOTA_SET_VER);
		}
		dt_version_set(env, obj, *ver, th);
	}

	EXIT;
out:
	dt_write_unlock(env, obj);
	return rc;
}
Example #23
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);
}
Example #24
0
static int llog_osd_write_blob(const struct lu_env *env, struct dt_object *o,
			       struct llog_rec_hdr *rec, void *buf,
			       loff_t *off, struct thandle *th)
{
	struct llog_thread_info	*lgi = llog_info(env);
	int			 buflen = rec->lrh_len;
	int			 rc;

	ENTRY;

	LASSERT(env);
	LASSERT(o);

	if (buflen == 0)
		CWARN("0-length record\n");

	CDEBUG(D_OTHER, "write blob with type %x, buf %p/%u at off %llu\n",
	       rec->lrh_type, buf, buflen, *off);

	if (!buf) {
		lgi->lgi_buf.lb_len = buflen;
		lgi->lgi_buf.lb_buf = rec;
		rc = dt_record_write(env, o, &lgi->lgi_buf, off, th);
		if (rc)
			CERROR("%s: error writing log record: rc = %d\n",
			       o->do_lu.lo_dev->ld_obd->obd_name, rc);
		RETURN(rc);
	}

	/* the buf case */
	/* protect the following 3 writes from concurrent read */
	dt_write_lock(env, o, 0);
	rec->lrh_len = sizeof(*rec) + buflen + sizeof(lgi->lgi_tail);
	lgi->lgi_buf.lb_len = sizeof(*rec);
	lgi->lgi_buf.lb_buf = rec;
	rc = dt_record_write(env, o, &lgi->lgi_buf, off, th);
	if (rc) {
		CERROR("%s: error writing log hdr: rc = %d\n",
		       o->do_lu.lo_dev->ld_obd->obd_name, rc);
		GOTO(out, rc);
	}

	lgi->lgi_buf.lb_len = buflen;
	lgi->lgi_buf.lb_buf = buf;
	rc = dt_record_write(env, o, &lgi->lgi_buf, off, th);
	if (rc) {
		CERROR("%s: error writing log buffer: rc = %d\n",
		       o->do_lu.lo_dev->ld_obd->obd_name,  rc);
		GOTO(out, rc);
	}

	lgi->lgi_tail.lrt_len = rec->lrh_len;
	lgi->lgi_tail.lrt_index = rec->lrh_index;
	lgi->lgi_buf.lb_len = sizeof(lgi->lgi_tail);
	lgi->lgi_buf.lb_buf = &lgi->lgi_tail;
	rc = dt_record_write(env, o, &lgi->lgi_buf, off, th);
	if (rc)
		CERROR("%s: error writing log tail: rc = %d\n",
		       o->do_lu.lo_dev->ld_obd->obd_name, rc);
out:
	dt_write_unlock(env, o);
	RETURN(rc);
}
Example #25
0
static inline void mdd_orphan_write_unlock(const struct lu_env *env,
					   struct mdd_device *mdd)
{
	struct dt_object *dor = mdd->mdd_orphans;
	dt_write_unlock(env, dor);
}
Example #26
0
int ofd_precreate_objects(const struct lu_env *env, struct ofd_device *ofd,
			  obd_id id, struct ofd_seq *oseq, int nr, int sync)
{
	struct ofd_thread_info	*info = ofd_info(env);
	struct ofd_object	*fo = NULL;
	struct dt_object	*next;
	struct thandle		*th;
	struct ofd_object	**batch;
	struct lu_fid		*fid = &info->fti_fid;
	obd_id			 tmp;
	int			 rc;
	int			 i;
	int			 objects = 0;
	int			 nr_saved = nr;

	ENTRY;

	/* Don't create objects beyond the valid range for this SEQ */
	if (unlikely(fid_seq_is_mdt0(ostid_seq(&oseq->os_oi)) &&
		     (id + nr) >= IDIF_MAX_OID)) {
		CERROR("%s:"DOSTID" hit the IDIF_MAX_OID (1<<48)!\n",
		       ofd_name(ofd), id, ostid_seq(&oseq->os_oi));
		RETURN(rc = -ENOSPC);
	} else if (unlikely(!fid_seq_is_mdt0(ostid_seq(&oseq->os_oi)) &&
			    (id + nr) >= OBIF_MAX_OID)) {
		CERROR("%s:"DOSTID" hit the OBIF_MAX_OID (1<<32)!\n",
		       ofd_name(ofd), id, ostid_seq(&oseq->os_oi));
		RETURN(rc = -ENOSPC);
	}

	OBD_ALLOC(batch, nr_saved * sizeof(struct ofd_object *));
	if (batch == NULL)
		RETURN(-ENOMEM);

	info->fti_attr.la_valid = LA_TYPE | LA_MODE;
	/*
	 * We mark object SUID+SGID to flag it for accepting UID+GID from
	 * client on first write.  Currently the permission bits on the OST are
	 * never used, so this is OK.
	 */
	info->fti_attr.la_mode = S_IFREG | S_ISUID | S_ISGID | 0666;
	info->fti_dof.dof_type = dt_mode_to_dft(S_IFREG);

	/* Initialize a/c/m time so any client timestamp will always
	 * be newer and update the inode. ctime = 0 is also handled
	 * specially in osd_inode_setattr(). See LU-221, LU-1042 */
	info->fti_attr.la_valid |= LA_ATIME | LA_MTIME | LA_CTIME;
	info->fti_attr.la_atime = 0;
	info->fti_attr.la_mtime = 0;
	info->fti_attr.la_ctime = 0;

	LASSERT(id != 0);

	/* prepare objects */
	*fid = *lu_object_fid(&oseq->os_lastid_obj->do_lu);
	for (i = 0; i < nr; i++) {
		rc = fid_set_id(fid, id + i);
		if (rc != 0) {
			if (i == 0)
				GOTO(out, rc);

			nr = i;
			break;
		}

		fo = ofd_object_find(env, ofd, fid);
		if (IS_ERR(fo)) {
			if (i == 0)
				GOTO(out, rc = PTR_ERR(fo));

			nr = i;
			break;
		}

		ofd_write_lock(env, fo);
		batch[i] = fo;
	}
	info->fti_buf.lb_buf = &tmp;
	info->fti_buf.lb_len = sizeof(tmp);
	info->fti_off = 0;

	th = ofd_trans_create(env, ofd);
	if (IS_ERR(th))
		GOTO(out, rc = PTR_ERR(th));

	th->th_sync |= sync;

	rc = dt_declare_record_write(env, oseq->os_lastid_obj, &info->fti_buf,
				     info->fti_off, th);
	if (rc)
		GOTO(trans_stop, rc);

	for (i = 0; i < nr; i++) {
		fo = batch[i];
		LASSERT(fo);

		if (unlikely(ofd_object_exists(fo))) {
			/* object may exist being re-created by write replay */
			CDEBUG(D_INODE, "object "LPX64"/"LPX64" exists: "
			       DFID"\n", ostid_seq(&oseq->os_oi), id,
			       PFID(lu_object_fid(&fo->ofo_obj.do_lu)));
			continue;
		}

		next = ofd_object_child(fo);
		LASSERT(next != NULL);

		rc = dt_declare_create(env, next, &info->fti_attr, NULL,
				       &info->fti_dof, th);
		if (rc) {
			nr = i;
			break;
		}
	}

	rc = dt_trans_start_local(env, ofd->ofd_osd, th);
	if (rc)
		GOTO(trans_stop, rc);

	CDEBUG(D_OTHER, "%s: create new object "DFID" nr %d\n",
	       ofd_name(ofd), PFID(fid), nr);

	LASSERT(nr > 0);

	 /* When the LFSCK scanning the whole device to verify the LAST_ID file
	  * consistency, it will load the last_id into RAM firstly, and compare
	  * the last_id with each OST-object's ID. If the later one is larger,
	  * then it will regard the LAST_ID file crashed. But during the LFSCK
	  * scanning, the OFD may continue to create new OST-objects. Those new
	  * created OST-objects will have larger IDs than the LFSCK known ones.
	  * So from the LFSCK view, it needs to re-load the last_id from disk
	  * file, and if the latest last_id is still smaller than the object's
	  * ID, then the LAST_ID file is real crashed.
	  *
	  * To make above mechanism to work, before OFD pre-create OST-objects,
	  * it needs to update the LAST_ID file firstly, otherwise, the LFSCK
	  * may cannot get latest last_id although new OST-object created. */
	if (!OBD_FAIL_CHECK(OBD_FAIL_LFSCK_SKIP_LASTID)) {
		tmp = cpu_to_le64(id + nr - 1);
		dt_write_lock(env, oseq->os_lastid_obj, 0);
		rc = dt_record_write(env, oseq->os_lastid_obj,
				     &info->fti_buf, &info->fti_off, th);
		dt_write_unlock(env, oseq->os_lastid_obj);
		if (rc != 0)
			GOTO(trans_stop, rc);
	}

	for (i = 0; i < nr; i++) {
		fo = batch[i];
		LASSERT(fo);

		/* Only the new created objects need to be recorded. */
		if (ofd->ofd_osd->dd_record_fid_accessed) {
			lfsck_pack_rfa(&ofd_info(env)->fti_lr,
				       lu_object_fid(&fo->ofo_obj.do_lu));
			lfsck_in_notify(env, ofd->ofd_osd,
					&ofd_info(env)->fti_lr);
		}

		if (likely(!ofd_object_exists(fo) &&
			   !OBD_FAIL_CHECK(OBD_FAIL_LFSCK_DANGLING))) {
			next = ofd_object_child(fo);
			LASSERT(next != NULL);

			rc = dt_create(env, next, &info->fti_attr, NULL,
				       &info->fti_dof, th);
			if (rc)
				break;
			LASSERT(ofd_object_exists(fo));
		}
		ofd_seq_last_oid_set(oseq, id + i);
	}

	objects = i;
	/* NOT all the wanted objects have been created,
	 * set the LAST_ID as the real created. */
	if (unlikely(objects < nr)) {
		int rc1;

		info->fti_off = 0;
		tmp = cpu_to_le64(ofd_seq_last_oid(oseq));
		dt_write_lock(env, oseq->os_lastid_obj, 0);
		rc1 = dt_record_write(env, oseq->os_lastid_obj,
				      &info->fti_buf, &info->fti_off, th);
		dt_write_unlock(env, oseq->os_lastid_obj);
		if (rc1 != 0)
			CERROR("%s: fail to reset the LAST_ID for seq ("LPX64
			       ") from "LPU64" to "LPU64"\n", ofd_name(ofd),
			       ostid_seq(&oseq->os_oi), id + nr - 1,
			       ofd_seq_last_oid(oseq));
	}

trans_stop:
	ofd_trans_stop(env, ofd, th, rc);
out:
	for (i = 0; i < nr_saved; i++) {
		fo = batch[i];
		if (fo) {
			ofd_write_unlock(env, fo);
			ofd_object_put(env, fo);
		}
	}
	OBD_FREE(batch, nr_saved * sizeof(struct ofd_object *));

	CDEBUG((objects == 0 && rc == 0) ? D_ERROR : D_OTHER,
	       "created %d/%d objects: %d\n", objects, nr_saved, rc);

	LASSERT(ergo(objects == 0, rc < 0));
	RETURN(objects > 0 ? objects : rc);
}
Example #27
0
static int mdd_orphan_destroy(const struct lu_env *env, struct mdd_object *obj,
			      struct dt_key *key)
{
	struct thandle *th = NULL;
	struct mdd_device *mdd = mdo2mdd(&obj->mod_obj);
	bool orphan_exists = true;
	int rc = 0;
	ENTRY;

	th = mdd_trans_create(env, mdd);
	if (IS_ERR(th)) {
		rc = PTR_ERR(th);
		if (rc != -EINPROGRESS)
			CERROR("%s: cannot get orphan thandle: rc = %d\n",
			       mdd2obd_dev(mdd)->obd_name, rc);
		RETURN(rc);
	}

	mdd_write_lock(env, obj, MOR_TGT_CHILD);
	rc = mdd_orphan_declare_delete(env, obj, th);
	if (rc == -ENOENT)
		orphan_exists = false;
	else if (rc)
		GOTO(unlock, rc);

	if (orphan_exists) {
		rc = mdo_declare_destroy(env, obj, th);
		if (rc)
			GOTO(unlock, rc);
	}

	rc = mdd_trans_start(env, mdd, th);
	if (rc)
		GOTO(unlock, rc);

	if (likely(obj->mod_count == 0)) {
		dt_write_lock(env, mdd->mdd_orphans, MOR_TGT_ORPHAN);
		rc = dt_delete(env, mdd->mdd_orphans, key, th);
		if (rc) {
			CERROR("%s: could not delete orphan "DFID": rc = %d\n",
			       mdd2obd_dev(mdd)->obd_name, PFID(mdo2fid(obj)),
			       rc);
		} else if (orphan_exists) {
			mdo_ref_del(env, obj, th);
			if (S_ISDIR(mdd_object_type(obj))) {
				mdo_ref_del(env, obj, th);
				dt_ref_del(env, mdd->mdd_orphans, th);
			}
			rc = mdo_destroy(env, obj, th);
		} else {
			CWARN("%s: orphan %s "DFID" doesn't exist\n",
			      mdd2obd_dev(mdd)->obd_name, (char *)key,
			      PFID(mdo2fid(obj)));
		}
		dt_write_unlock(env, mdd->mdd_orphans);
	}
unlock:
	mdd_write_unlock(env, obj);

	rc = mdd_trans_stop(env, mdd, 0, th);

	RETURN(rc);
}
Example #28
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);
}
Example #29
0
/**
 * 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);
}
Example #30
0
static int llog_osd_write_blob(const struct lu_env *env, struct dt_object *o,
			       struct llog_rec_hdr *rec, void *buf,
			       loff_t *off, struct thandle *th)
{
	struct llog_thread_info	*lgi = llog_info(env);
	int			 buflen = rec->lrh_len;
	int			 rc;

	LASSERT(env);
	LASSERT(o);

	if (buflen == 0)
		CWARN("0-length record\n");

	CDEBUG(D_OTHER, "write blob with type %x, buf %p/%u at off %llu\n",
	       rec->lrh_type, buf, buflen, *off);

	lgi->lgi_attr.la_valid = LA_SIZE;
	lgi->lgi_attr.la_size = *off;

	if (!buf) {
		lgi->lgi_buf.lb_len = buflen;
		lgi->lgi_buf.lb_buf = rec;
		rc = dt_record_write(env, o, &lgi->lgi_buf, off, th);
		if (rc)
			CERROR("%s: error writing log record: rc = %d\n",
			       o->do_lu.lo_dev->ld_obd->obd_name, rc);
		GOTO(out, rc);
	}

	/* the buf case */
	/* protect the following 3 writes from concurrent read */
	dt_write_lock(env, o, 0);
	rec->lrh_len = sizeof(*rec) + buflen + sizeof(lgi->lgi_tail);
	lgi->lgi_buf.lb_len = sizeof(*rec);
	lgi->lgi_buf.lb_buf = rec;
	rc = dt_record_write(env, o, &lgi->lgi_buf, off, th);
	if (rc) {
		CERROR("%s: error writing log hdr: rc = %d\n",
		       o->do_lu.lo_dev->ld_obd->obd_name, rc);
		GOTO(out_unlock, rc);
	}

	lgi->lgi_buf.lb_len = buflen;
	lgi->lgi_buf.lb_buf = buf;
	rc = dt_record_write(env, o, &lgi->lgi_buf, off, th);
	if (rc) {
		CERROR("%s: error writing log buffer: rc = %d\n",
		       o->do_lu.lo_dev->ld_obd->obd_name,  rc);
		GOTO(out_unlock, rc);
	}

	lgi->lgi_tail.lrt_len = rec->lrh_len;
	lgi->lgi_tail.lrt_index = rec->lrh_index;
	lgi->lgi_buf.lb_len = sizeof(lgi->lgi_tail);
	lgi->lgi_buf.lb_buf = &lgi->lgi_tail;
	rc = dt_record_write(env, o, &lgi->lgi_buf, off, th);
	if (rc)
		CERROR("%s: error writing log tail: rc = %d\n",
		       o->do_lu.lo_dev->ld_obd->obd_name, rc);

out_unlock:
	dt_write_unlock(env, o);

out:
	/* cleanup the content written above */
	if (rc) {
		dt_punch(env, o, lgi->lgi_attr.la_size, OBD_OBJECT_EOF, th,
			 BYPASS_CAPA);
		dt_attr_set(env, o, &lgi->lgi_attr, th, BYPASS_CAPA);
	}

	return rc;
}