Esempio n. 1
0
/**
 * Implementation of dt_object_operations::do_create
 *
 * It adds an OUT_CREATE sub-request into the OUT RPC that will be flushed
 * when the transaction stop, and sets necessary flags for created object.
 *
 * \param[in] env	execution environment
 * \param[in] dt	object to be created
 * \param[in] attr	attribute of the created object
 * \param[in] hint	creation hint
 * \param[in] dof	creation format information
 * \param[in] th	the transaction handle
 *
 * \retval		0 if packing creation succeeds.
 * \retval		negative errno if packing creation fails.
 */
int osp_md_object_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 osp_update_request	*update;
	struct osp_object		*obj = dt2osp_obj(dt);
	int				rc;

	update = thandle_to_osp_update_request(th);
	LASSERT(update != NULL);

	LASSERT(attr->la_valid & LA_TYPE);
	rc = osp_update_rpc_pack(env, create, update, OUT_CREATE,
				 lu_object_fid(&dt->do_lu), attr, hint, dof);
	if (rc != 0)
		GOTO(out, rc);

	rc = osp_insert_update_callback(env, update, dt2osp_obj(dt), NULL,
					osp_object_create_interpreter);

	if (rc < 0)
		GOTO(out, rc);

	dt->do_lu.lo_header->loh_attr |= LOHA_EXISTS | (attr->la_mode & S_IFMT);
	dt2osp_obj(dt)->opo_non_exist = 0;

	LASSERT(obj->opo_ooa != NULL);
	obj->opo_ooa->ooa_attr = *attr;
out:
	return rc;
}
Esempio n. 2
0
/**
 * Implement OSP layer dt_object_operations::do_destroy() interface.
 *
 * Pack the destroy update into the RPC buffer, which will be sent
 * to the remote MDT during transaction stop.
 *
 * It also marks the object as non-cached.
 *
 * \param[in] env	pointer to the thread context
 * \param[in] dt	pointer to the OSP layer dt_object to be destroyed
 * \param[in] th	pointer to the transaction handler
 *
 * \retval		0 for success
 * \retval		negative error number on failure
 */
int osp_md_object_destroy(const struct lu_env *env, struct dt_object *dt,
			  struct thandle *th)
{
	struct osp_object		*o = dt2osp_obj(dt);
	struct osp_device		*osp = lu2osp_dev(dt->do_lu.lo_dev);
	struct osp_update_request	*update;
	int				rc = 0;

	ENTRY;
	o->opo_non_exist = 1;

	LASSERT(osp->opd_connect_mdt);
	update = thandle_to_osp_update_request(th);
	LASSERT(update != NULL);

	rc = osp_update_rpc_pack(env, object_destroy, update, OUT_DESTROY,
				 lu_object_fid(&dt->do_lu));
	if (rc != 0)
		RETURN(rc);

	set_bit(LU_OBJECT_HEARD_BANSHEE, &dt->do_lu.lo_header->loh_flags);
	rc = osp_insert_update_callback(env, update, dt2osp_obj(dt), NULL,
					NULL);

	RETURN(rc);
}
Esempio n. 3
0
/**
 * Implementation of dt_object_operations::do_write_locked
 *
 * Test if the object is locked in write mode.
 *
 * \param[in] env	execution environment
 * \param[in] dt	object to be tested
 */
static int osp_md_object_write_locked(const struct lu_env *env,
				      struct dt_object *dt)
{
	struct osp_object *obj = dt2osp_obj(dt);

	return obj->opo_owner == env;
}
Esempio n. 4
0
/**
 * Implementation of dt_object_operations::do_read_unlock
 *
 * Unlock the read lock of remote object.
 *
 * \param[in] env	execution environment
 * \param[in] dt	object to be unlocked
 */
static void osp_md_object_read_unlock(const struct lu_env *env,
				      struct dt_object *dt)
{
	struct osp_object *obj = dt2osp_obj(dt);

	up_read(&obj->opo_sem);
}
Esempio n. 5
0
/**
 * Implementation of dt_body_operations::dbo_write
 *
 * Pack the write object update into the RPC buffer, which will be sent
 * to the remote MDT during transaction stop.
 *
 * \param[in] env	execution environment
 * \param[in] dt	object to be written
 * \param[in] buf	buffer to write which includes an embedded size field
 * \param[in] pos	offet in the object to start writing at
 * \param[in] th	transaction handle
 * \param[in] ignore_quota quota enforcement for this write
 *
 * \retval		the buffer size in bytes if packing succeeds.
 * \retval		negative errno if packing fails.
 */
static ssize_t osp_md_write(const struct lu_env *env, struct dt_object *dt,
			    const struct lu_buf *buf, loff_t *pos,
			    struct thandle *th, int ignore_quota)
{
	struct osp_object	  *obj = dt2osp_obj(dt);
	struct osp_update_request  *update;
	struct osp_thandle	  *oth = thandle_to_osp_thandle(th);
	ssize_t			  rc;
	ENTRY;

	update = thandle_to_osp_update_request(th);
	LASSERT(update != NULL);

	CDEBUG(D_INFO, "write "DFID" offset = "LPU64" length = %zu\n",
	       PFID(lu_object_fid(&dt->do_lu)), *pos, buf->lb_len);

	rc = osp_update_rpc_pack(env, write, update, OUT_WRITE,
				 lu_object_fid(&dt->do_lu), buf, *pos);
	if (rc < 0)
		RETURN(rc);

	rc = osp_check_and_set_rpc_version(oth, obj);
	if (rc < 0)
		RETURN(rc);

	/* XXX: how about the write error happened later? */
	*pos += buf->lb_len;

	if (obj->opo_ooa != NULL &&
	    obj->opo_ooa->ooa_attr.la_valid & LA_SIZE &&
	    obj->opo_ooa->ooa_attr.la_size < *pos)
		obj->opo_ooa->ooa_attr.la_size = *pos;

	RETURN(buf->lb_len);
}
Esempio n. 6
0
static int osp_attr_set(const struct lu_env *env, struct dt_object *dt,
			const struct lu_attr *attr, struct thandle *th,
			struct lustre_capa *capa)
{
	struct osp_object	*o = dt2osp_obj(dt);
	int			 rc = 0;

	ENTRY;

	/* we're interested in uid/gid changes only */
	if (!(attr->la_valid & (LA_UID | LA_GID)))
		RETURN(0);

	/* new object, the very first ->attr_set()
	 * initializing attributes needs no logging
	 * all subsequent one are subject to the
	 * logging and synchronization with OST */
	if (o->opo_new) {
		o->opo_new = 0;
		RETURN(0);
	}

	/*
	 * once transaction is committed put proper command on
	 * the queue going to our OST
	 */
	rc = osp_sync_add(env, o, MDS_SETATTR64_REC, th, attr);

	/* XXX: send new uid/gid to OST ASAP? */

	RETURN(rc);
}
Esempio n. 7
0
/**
 * Implementation of dt_object_operations::do_write_unlock
 *
 * Unlock the write lock of remote object.
 *
 * \param[in] env	execution environment
 * \param[in] dt	object to be unlocked
 */
static void osp_md_object_write_unlock(const struct lu_env *env,
				       struct dt_object *dt)
{
	struct osp_object *obj = dt2osp_obj(dt);

	LASSERT(obj->opo_owner == env);
	obj->opo_owner = NULL;
	up_write(&obj->opo_sem);
}
Esempio n. 8
0
static int osp_declare_attr_set(const struct lu_env *env, struct dt_object *dt,
				const struct lu_attr *attr, struct thandle *th)
{
	struct osp_device	*d = lu2osp_dev(dt->do_lu.lo_dev);
	struct osp_object	*o = dt2osp_obj(dt);
	int			 rc = 0;

	ENTRY;

	/*
	 * Usually we don't allow server stack to manipulate size
	 * but there is a special case when striping is created
	 * late, after stripless file got truncated to non-zero.
	 *
	 * In this case we do the following:
	 *
	 * 1) grab id in declare - this can lead to leaked OST objects
	 *    but we don't currently have proper mechanism and the only
	 *    options we have are to do truncate RPC holding transaction
	 *    open (very bad) or to grab id in declare at cost of leaked
	 *    OST object in same very rare unfortunate case (just bad)
	 *    notice 1.6-2.0 do assignment outside of running transaction
	 *    all the time, meaning many more chances for leaked objects.
	 *
	 * 2) send synchronous truncate RPC with just assigned id
	 */

	/* there are few places in MDD code still passing NULL
	 * XXX: to be fixed soon */
	if (attr == NULL)
		RETURN(0);

	if (attr->la_valid & LA_SIZE && attr->la_size > 0 &&
	    fid_is_zero(lu_object_fid(&o->opo_obj.do_lu))) {
		LASSERT(!dt_object_exists(dt));
		osp_object_assign_fid(env, d, o);
		rc = osp_object_truncate(env, dt, attr->la_size);
		if (rc)
			RETURN(rc);
	}

	if (o->opo_new) {
		/* no need in logging for new objects being created */
		RETURN(0);
	}

	if (!(attr->la_valid & (LA_UID | LA_GID)))
		RETURN(0);

	/*
	 * track all UID/GID changes via llog
	 */
	rc = osp_sync_declare_add(env, o, MDS_SETATTR64_REC, th);

	RETURN(rc);
}
Esempio n. 9
0
/**
 * Implementation of dt_object_operations::do_write_lock
 *
 * Lock the remote object in write mode.
 *
 * \param[in] env	execution environment
 * \param[in] dt	object to be locked
 * \param[in] role	lock role from MDD layer, see mdd_object_role().
 */
static void osp_md_object_write_lock(const struct lu_env *env,
				     struct dt_object *dt, unsigned role)
{
	struct osp_object *obj = dt2osp_obj(dt);

	down_write_nested(&obj->opo_sem, role);

	LASSERT(obj->opo_owner == NULL);
	obj->opo_owner = env;
}
Esempio n. 10
0
static int osp_declare_object_destroy(const struct lu_env *env,
				      struct dt_object *dt, struct thandle *th)
{
	struct osp_object	*o = dt2osp_obj(dt);
	int			 rc = 0;

	ENTRY;

	/*
	 * track objects to be destroyed via llog
	 */
	rc = osp_sync_declare_add(env, o, MDS_UNLINK64_REC, th);

	RETURN(rc);
}
Esempio n. 11
0
/**
 * Implementation of dt_object_operations::do_declare_create
 *
 * Create the osp_update_request to track the update for this OSP
 * in the transaction.
 *
 * \param[in] env	execution environment
 * \param[in] dt	remote object to be created
 * \param[in] attr	attribute of the created object
 * \param[in] hint	creation hint
 * \param[in] dof	creation format information
 * \param[in] th	the transaction handle
 *
 * \retval		0 if preparation succeeds.
 * \retval		negative errno if preparation fails.
 */
int osp_md_declare_object_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 osp_object *obj = dt2osp_obj(dt);
	int		  rc;

	if (obj->opo_ooa == NULL) {
		rc = osp_oac_init(obj);
		if (rc != 0)
			return rc;
	}

	return osp_trans_update_request_create(th);
}
Esempio n. 12
0
static int osp_object_destroy(const struct lu_env *env, struct dt_object *dt,
			      struct thandle *th)
{
	struct osp_object	*o = dt2osp_obj(dt);
	int			 rc = 0;

	ENTRY;

	/*
	 * once transaction is committed put proper command on
	 * the queue going to our OST
	 */
	rc = osp_sync_add(env, o, MDS_UNLINK64_REC, th, NULL);

	/* not needed in cache any more */
	set_bit(LU_OBJECT_HEARD_BANSHEE, &dt->do_lu.lo_header->loh_flags);

	RETURN(rc);
}
Esempio n. 13
0
/**
 * Implementation of dt_body_operations::dbo_declare_write
 *
 * Create the osp_update_request to track the update for this OSP
 * in the transaction.
  *
 * \param[in] env	execution environment
 * \param[in] dt	object to be written
 * \param[in] buf	buffer to write which includes an embedded size field
 * \param[in] pos	offet in the object to start writing at
 * \param[in] th	transaction handle
 *
 * \retval		0 if preparation succeeds.
 * \retval		negative errno if preparation fails.
 */
static ssize_t osp_md_declare_write(const struct lu_env *env,
				    struct dt_object *dt,
				    const struct lu_buf *buf,
				    loff_t pos, struct thandle *th)
{
	struct osp_device *osp = dt2osp_dev(th->th_dev);
	int rc;

	rc = osp_trans_update_request_create(th);
	if (rc != 0)
		return rc;

	if (osp->opd_update == NULL)
		return 0;

	if (dt2osp_obj(dt)->opo_stale)
		return -ESTALE;

	return 0;
}
Esempio n. 14
0
static int osp_object_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 osp_thread_info	*osi = osp_env_info(env);
	struct osp_device	*d = lu2osp_dev(dt->do_lu.lo_dev);
	struct osp_object	*o = dt2osp_obj(dt);
	int			rc = 0;
	struct lu_fid		*fid = &osi->osi_fid;
	ENTRY;

	if (o->opo_reserved) {
		/* regular case, fid is assigned holding trunsaction open */
		 osp_object_assign_fid(env, d, o);
	}

	memcpy(fid, lu_object_fid(&dt->do_lu), sizeof(*fid));

	LASSERTF(fid_is_sane(fid), "fid for osp_obj %p is insane"DFID"!\n",
		 osp_obj, PFID(fid));

	if (!o->opo_reserved) {
		/* special case, id was assigned outside of transaction
		 * see comments in osp_declare_attr_set */
		spin_lock(&d->opd_pre_lock);
		osp_update_last_fid(d, fid);
		spin_unlock(&d->opd_pre_lock);
	}

	CDEBUG(D_INODE, "fid for osp_obj %p is "DFID"!\n", osp_obj, PFID(fid));

	/* If the precreate ends, it means it will be ready to rollover to
	 * the new sequence soon, all the creation should be synchronized,
	 * otherwise during replay, the replay fid will be inconsistent with
	 * last_used/create fid */
	if (osp_precreate_end_seq(env, d) && osp_is_fid_client(d))
		th->th_sync = 1;

	/*
	 * it's OK if the import is inactive by this moment - id was created
	 * by OST earlier, we just need to maintain it consistently on the disk
	 * once import is reconnected, OSP will claim this and other objects
	 * used and OST either keep them, if they exist or recreate
	 */

	/* we might have lost precreated objects */
	if (unlikely(d->opd_gap_count) > 0) {
		spin_lock(&d->opd_pre_lock);
		if (d->opd_gap_count > 0) {
			int count = d->opd_gap_count;

			ostid_set_id(&osi->osi_oi,
				     fid_oid(&d->opd_gap_start_fid));
			d->opd_gap_count = 0;
			spin_unlock(&d->opd_pre_lock);

			CDEBUG(D_HA, "Writting gap "DFID"+%d in llog\n",
			       PFID(&d->opd_gap_start_fid), count);
			/* real gap handling is disabled intil ORI-692 will be
			 * fixed, now we only report gaps */
		} else {
			spin_unlock(&d->opd_pre_lock);
		}
	}

	/* new object, the very first ->attr_set()
	 * initializing attributes needs no logging */
	o->opo_new = 1;

	/* Only need update last_used oid file, seq file will only be update
	 * during seq rollover */
	osp_objid_buf_prep(&osi->osi_lb, &osi->osi_off,
			   &d->opd_last_used_fid.f_oid, d->opd_index);

	rc = dt_record_write(env, d->opd_last_used_oid_file, &osi->osi_lb,
			     &osi->osi_off, th);

	CDEBUG(D_HA, "%s: Wrote last used FID: "DFID", index %d: %d\n",
	       d->opd_obd->obd_name, PFID(fid), d->opd_index, rc);

	RETURN(rc);
}
Esempio n. 15
0
static int osp_declare_object_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 osp_thread_info	*osi = osp_env_info(env);
	struct osp_device	*d = lu2osp_dev(dt->do_lu.lo_dev);
	struct osp_object	*o = dt2osp_obj(dt);
	const struct lu_fid	*fid;
	int			 rc = 0;

	ENTRY;

	/* should happen to non-0 OSP only so that at least one object
	 * has been already declared in the scenario and LOD should
	 * cleanup that */
	if (OBD_FAIL_CHECK(OBD_FAIL_MDS_OSC_CREATE_FAIL) && d->opd_index == 1)
		RETURN(-ENOSPC);

	LASSERT(d->opd_last_used_oid_file);
	fid = lu_object_fid(&dt->do_lu);

	/*
	 * There can be gaps in precreated ids and record to unlink llog
	 * XXX: we do not handle gaps yet, implemented before solution
	 *	was found to be racy, so we disabled that. there is no
	 *	point in making useless but expensive llog declaration.
	 */
	/* rc = osp_sync_declare_add(env, o, MDS_UNLINK64_REC, th); */

	if (unlikely(!fid_is_zero(fid))) {
		/* replay case: caller knows fid */
		osi->osi_off = sizeof(osi->osi_id) * d->opd_index;
		rc = dt_declare_record_write(env, d->opd_last_used_oid_file,
					     sizeof(osi->osi_id), osi->osi_off,
					     th);
		RETURN(rc);
	}

	/*
	 * in declaration we need to reserve object so that we don't block
	 * awaiting precreation RPC to complete
	 */
	rc = osp_precreate_reserve(env, d);
	/*
	 * we also need to declare update to local "last used id" file for
	 * recovery if object isn't used for a reason, we need to release
	 * reservation, this can be made in osd_object_release()
	 */
	if (rc == 0) {
		/* mark id is reserved: in create we don't want to talk
		 * to OST */
		LASSERT(o->opo_reserved == 0);
		o->opo_reserved = 1;

		/* common for all OSPs file hystorically */
		osi->osi_off = sizeof(osi->osi_id) * d->opd_index;
		rc = dt_declare_record_write(env, d->opd_last_used_oid_file,
					     sizeof(osi->osi_id), osi->osi_off,
					     th);
	} else {
		/* not needed in the cache anymore */
		set_bit(LU_OBJECT_HEARD_BANSHEE,
			    &dt->do_lu.lo_header->loh_flags);
	}
	RETURN(rc);
}