Exemple #1
0
/**
 * We calculate on which OST the mapping will end. If the length of mapping
 * is greater than (stripe_size * stripe_count) then the last_stripe will
 * will be one just before start_stripe. Else we check if the mapping
 * intersects each OST and find last_stripe.
 * This function returns the last_stripe and also sets the stripe_count
 * over which the mapping is spread
 *
 * \param lsm [in]		striping information for the file
 * \param fm_start [in]		logical start of mapping
 * \param fm_end [in]		logical end of mapping
 * \param start_stripe [in]	starting stripe of the mapping
 * \param stripe_count [out]	the number of stripes across which to map is
 *				returned
 *
 * \retval last_stripe		return the last stripe of the mapping
 */
static int fiemap_calc_last_stripe(struct lov_stripe_md *lsm,
				   loff_t fm_start, loff_t fm_end,
				   int start_stripe, int *stripe_count)
{
	int last_stripe;
	loff_t obd_start;
	loff_t obd_end;
	int i, j;

	if (fm_end - fm_start > lsm->lsm_stripe_size * lsm->lsm_stripe_count) {
		last_stripe = (start_stripe < 1 ? lsm->lsm_stripe_count - 1 :
							      start_stripe - 1);
		*stripe_count = lsm->lsm_stripe_count;
	} else {
		for (j = 0, i = start_stripe; j < lsm->lsm_stripe_count;
		     i = (i + 1) % lsm->lsm_stripe_count, j++) {
			if ((lov_stripe_intersects(lsm, i, fm_start, fm_end,
						   &obd_start, &obd_end)) == 0)
				break;
		}
		*stripe_count = j;
		last_stripe = (start_stripe + j - 1) % lsm->lsm_stripe_count;
	}

	return last_stripe;
}
Exemple #2
0
/**
 * Non-zero fe_logical indicates that this is a continuation FIEMAP
 * call. The local end offset and the device are sent in the first
 * fm_extent. This function calculates the stripe number from the index.
 * This function returns a stripe_no on which mapping is to be restarted.
 *
 * This function returns fm_end_offset which is the in-OST offset at which
 * mapping should be restarted. If fm_end_offset=0 is returned then caller
 * will re-calculate proper offset in next stripe.
 * Note that the first extent is passed to lov_get_info via the value field.
 *
 * \param fiemap [in]		fiemap request header
 * \param lsm [in]		striping information for the file
 * \param fm_start [in]		logical start of mapping
 * \param fm_end [in]		logical end of mapping
 * \param start_stripe [out]	starting stripe will be returned in this
 */
static loff_t fiemap_calc_fm_end_offset(struct fiemap *fiemap,
					struct lov_stripe_md *lsm,
					loff_t fm_start, loff_t fm_end,
					int *start_stripe)
{
	loff_t local_end = fiemap->fm_extents[0].fe_logical;
	loff_t lun_start;
	loff_t lun_end;
	loff_t fm_end_offset;
	int stripe_no = -1;
	int i;

	if (fiemap->fm_extent_count == 0 ||
	    fiemap->fm_extents[0].fe_logical == 0)
		return 0;

	/* Find out stripe_no from ost_index saved in the fe_device */
	for (i = 0; i < lsm->lsm_stripe_count; i++) {
		struct lov_oinfo *oinfo = lsm->lsm_oinfo[i];

		if (lov_oinfo_is_dummy(oinfo))
			continue;

		if (oinfo->loi_ost_idx == fiemap->fm_extents[0].fe_device) {
			stripe_no = i;
			break;
		}
	}

	if (stripe_no == -1)
		return -EINVAL;

	/* If we have finished mapping on previous device, shift logical
	 * offset to start of next device */
	if (lov_stripe_intersects(lsm, stripe_no, fm_start, fm_end,
				  &lun_start, &lun_end) != 0 &&
	    local_end < lun_end) {
		fm_end_offset = local_end;
		*start_stripe = stripe_no;
	} else {
		/* This is a special value to indicate that caller should
		 * calculate offset in next stripe. */
		fm_end_offset = 0;
		*start_stripe = (stripe_no + 1) % lsm->lsm_stripe_count;
	}

	return fm_end_offset;
}
Exemple #3
0
/**
 * Creates sub-locks for a given lov_lock for the first time.
 *
 * Goes through all sub-objects of top-object, and creates sub-locks on every
 * sub-object intersecting with top-lock extent. This is complicated by the
 * fact that top-lock (that is being created) can be accessed concurrently
 * through already created sub-locks (possibly shared with other top-locks).
 */
static struct lov_lock *lov_lock_sub_init(const struct lu_env *env,
					  const struct cl_object *obj,
					  struct cl_lock *lock)
{
	int result = 0;
	int i;
	int nr;
	u64 start;
	u64 end;
	u64 file_start;
	u64 file_end;

	struct lov_object       *loo    = cl2lov(obj);
	struct lov_layout_raid0 *r0     = lov_r0(loo);
	struct lov_lock		*lovlck;

	file_start = cl_offset(lov2cl(loo), lock->cll_descr.cld_start);
	file_end   = cl_offset(lov2cl(loo), lock->cll_descr.cld_end + 1) - 1;

	for (i = 0, nr = 0; i < r0->lo_nr; i++) {
		/*
		 * XXX for wide striping smarter algorithm is desirable,
		 * breaking out of the loop, early.
		 */
		if (likely(r0->lo_sub[i]) && /* spare layout */
		    lov_stripe_intersects(loo->lo_lsm, i,
					  file_start, file_end, &start, &end))
			nr++;
	}
	LASSERT(nr > 0);
	lovlck = libcfs_kvzalloc(offsetof(struct lov_lock, lls_sub[nr]),
				 GFP_NOFS);
	if (!lovlck)
		return ERR_PTR(-ENOMEM);

	lovlck->lls_nr = nr;
	for (i = 0, nr = 0; i < r0->lo_nr; ++i) {
		if (likely(r0->lo_sub[i]) &&
		    lov_stripe_intersects(loo->lo_lsm, i,
					  file_start, file_end, &start, &end)) {
			struct lov_lock_sub *lls = &lovlck->lls_sub[nr];
			struct cl_lock_descr *descr;

			descr = &lls->sub_lock.cll_descr;

			LASSERT(!descr->cld_obj);
			descr->cld_obj   = lovsub2cl(r0->lo_sub[i]);
			descr->cld_start = cl_index(descr->cld_obj, start);
			descr->cld_end   = cl_index(descr->cld_obj, end);
			descr->cld_mode  = lock->cll_descr.cld_mode;
			descr->cld_gid   = lock->cll_descr.cld_gid;
			descr->cld_enq_flags = lock->cll_descr.cld_enq_flags;
			lls->sub_stripe = i;

			/* initialize sub lock */
			result = lov_sublock_init(env, lock, lls);
			if (result < 0)
				break;

			lls->sub_initialized = 1;
			nr++;
		}
	}
	LASSERT(ergo(result == 0, nr == lovlck->lls_nr));

	if (result != 0) {
		for (i = 0; i < nr; ++i) {
			if (!lovlck->lls_sub[i].sub_initialized)
				break;

			cl_lock_fini(env, &lovlck->lls_sub[i].sub_lock);
		}
		kvfree(lovlck);
		lovlck = ERR_PTR(result);
	}

	return lovlck;
}
Exemple #4
0
/**
 * Break down the FIEMAP request and send appropriate calls to individual OSTs.
 * This also handles the restarting of FIEMAP calls in case mapping overflows
 * the available number of extents in single call.
 *
 * \param env [in]		lustre environment
 * \param obj [in]		file object
 * \param fmkey [in]		fiemap request header and other info
 * \param fiemap [out]		fiemap buffer holding retrived map extents
 * \param buflen [in/out]	max buffer length of @fiemap, when iterate
 *				each OST, it is used to limit max map needed
 * \retval 0	success
 * \retval < 0	error
 */
static int lov_object_fiemap(const struct lu_env *env, struct cl_object *obj,
			     struct ll_fiemap_info_key *fmkey,
			     struct fiemap *fiemap, size_t *buflen)
{
	struct lov_stripe_md	*lsm;
	struct cl_object	*subobj = NULL;
	struct lov_obd		*lov = lu2lov_dev(obj->co_lu.lo_dev)->ld_lov;
	struct fiemap		*fm_local = NULL;
	struct fiemap_extent	*lcl_fm_ext;
	loff_t			fm_start;
	loff_t			fm_end;
	loff_t			fm_length;
	loff_t			fm_end_offset;
	int			count_local;
	int			ost_index = 0;
	int			start_stripe;
	int			current_extent = 0;
	int			rc = 0;
	int			last_stripe;
	int			cur_stripe = 0;
	int			cur_stripe_wrap = 0;
	int			stripe_count;
	unsigned int		buffer_size = FIEMAP_BUFFER_SIZE;
	/* Whether have we collected enough extents */
	bool			enough = false;
	/* EOF for object */
	bool			ost_eof = false;
	/* done with required mapping for this OST? */
	bool			ost_done = false;
	ENTRY;

	lsm = lov_lsm_addref(cl2lov(obj));
	if (lsm == NULL)
		RETURN(-ENODATA);

	/**
	 * If the stripe_count > 1 and the application does not understand
	 * DEVICE_ORDER flag, it cannot interpret the extents correctly.
	 */
	if (lsm->lsm_stripe_count > 1 && !(fiemap->fm_flags &
					   FIEMAP_FLAG_DEVICE_ORDER))
		GOTO(out_lsm, rc = -ENOTSUPP);

	if (lsm_is_released(lsm)) {
		if (fiemap->fm_start < fmkey->lfik_oa.o_size) {
			/**
			 * released file, return a minimal FIEMAP if
			 * request fits in file-size.
			 */
			fiemap->fm_mapped_extents = 1;
			fiemap->fm_extents[0].fe_logical = fiemap->fm_start;
			if (fiemap->fm_start + fiemap->fm_length <
			    fmkey->lfik_oa.o_size)
				fiemap->fm_extents[0].fe_length =
					fiemap->fm_length;
			else
				fiemap->fm_extents[0].fe_length =
					fmkey->lfik_oa.o_size -
					fiemap->fm_start;
			fiemap->fm_extents[0].fe_flags |=
				FIEMAP_EXTENT_UNKNOWN | FIEMAP_EXTENT_LAST;
		}
		GOTO(out_lsm, rc = 0);
	}

	if (fiemap_count_to_size(fiemap->fm_extent_count) < buffer_size)
		buffer_size = fiemap_count_to_size(fiemap->fm_extent_count);

	OBD_ALLOC_LARGE(fm_local, buffer_size);
	if (fm_local == NULL)
		GOTO(out_lsm, rc = -ENOMEM);
	lcl_fm_ext = &fm_local->fm_extents[0];
	count_local = fiemap_size_to_count(buffer_size);

	fm_start = fiemap->fm_start;
	fm_length = fiemap->fm_length;
	/* Calculate start stripe, last stripe and length of mapping */
	start_stripe = lov_stripe_number(lsm, fm_start);
	fm_end = (fm_length == ~0ULL) ? fmkey->lfik_oa.o_size :
					fm_start + fm_length - 1;
	/* If fm_length != ~0ULL but fm_start_fm_length-1 exceeds file size */
	if (fm_end > fmkey->lfik_oa.o_size)
		fm_end = fmkey->lfik_oa.o_size;

	last_stripe = fiemap_calc_last_stripe(lsm, fm_start, fm_end,
					      start_stripe, &stripe_count);
	fm_end_offset = fiemap_calc_fm_end_offset(fiemap, lsm, fm_start, fm_end,
						  &start_stripe);
	if (fm_end_offset == -EINVAL)
		GOTO(out_fm_local, rc = -EINVAL);

	/**
	 * Requested extent count exceeds the fiemap buffer size, shrink our
	 * ambition.
	 */
	if (fiemap_count_to_size(fiemap->fm_extent_count) > *buflen)
		fiemap->fm_extent_count = fiemap_size_to_count(*buflen);
	if (fiemap->fm_extent_count == 0)
		count_local = 0;

	/* Check each stripe */
	for (cur_stripe = start_stripe; stripe_count > 0;
	     --stripe_count,
	     cur_stripe = (cur_stripe + 1) % lsm->lsm_stripe_count) {
		loff_t req_fm_len; /* Stores length of required mapping */
		loff_t len_mapped_single_call;
		loff_t lun_start;
		loff_t lun_end;
		loff_t obd_object_end;
		unsigned int ext_count;

		cur_stripe_wrap = cur_stripe;

		/* Find out range of mapping on this stripe */
		if ((lov_stripe_intersects(lsm, cur_stripe, fm_start, fm_end,
					   &lun_start, &obd_object_end)) == 0)
			continue;

		if (lov_oinfo_is_dummy(lsm->lsm_oinfo[cur_stripe]))
			GOTO(out_fm_local, rc = -EIO);

		/* If this is a continuation FIEMAP call and we are on
		 * starting stripe then lun_start needs to be set to
		 * fm_end_offset */
		if (fm_end_offset != 0 && cur_stripe == start_stripe)
			lun_start = fm_end_offset;

		if (fm_length != ~0ULL) {
			/* Handle fm_start + fm_length overflow */
			if (fm_start + fm_length < fm_start)
				fm_length = ~0ULL - fm_start;
			lun_end = lov_size_to_stripe(lsm, fm_start + fm_length,
						     cur_stripe);
		} else {
			lun_end = ~0ULL;
		}

		if (lun_start == lun_end)
			continue;

		req_fm_len = obd_object_end - lun_start;
		fm_local->fm_length = 0;
		len_mapped_single_call = 0;

		/* find lobsub object */
		subobj = lov_find_subobj(env, cl2lov(obj), lsm,
					     cur_stripe);
		if (IS_ERR(subobj))
			GOTO(out_fm_local, rc = PTR_ERR(subobj));
		/* If the output buffer is very large and the objects have many
		 * extents we may need to loop on a single OST repeatedly */
		ost_eof = false;
		ost_done = false;
		do {
			if (fiemap->fm_extent_count > 0) {
				/* Don't get too many extents. */
				if (current_extent + count_local >
				    fiemap->fm_extent_count)
					count_local = fiemap->fm_extent_count -
						      current_extent;
			}

			lun_start += len_mapped_single_call;
			fm_local->fm_length = req_fm_len -
					      len_mapped_single_call;
			req_fm_len = fm_local->fm_length;
			fm_local->fm_extent_count = enough ? 1 : count_local;
			fm_local->fm_mapped_extents = 0;
			fm_local->fm_flags = fiemap->fm_flags;

			ost_index = lsm->lsm_oinfo[cur_stripe]->loi_ost_idx;

			if (ost_index < 0 ||
			    ost_index >= lov->desc.ld_tgt_count)
				GOTO(obj_put, rc = -EINVAL);
			/* If OST is inactive, return extent with UNKNOWN
			 * flag. */
			if (!lov->lov_tgts[ost_index]->ltd_active) {
				fm_local->fm_flags |= FIEMAP_EXTENT_LAST;
				fm_local->fm_mapped_extents = 1;

				lcl_fm_ext[0].fe_logical = lun_start;
				lcl_fm_ext[0].fe_length = obd_object_end -
							  lun_start;
				lcl_fm_ext[0].fe_flags |= FIEMAP_EXTENT_UNKNOWN;

				goto inactive_tgt;
			}

			fm_local->fm_start = lun_start;
			fm_local->fm_flags &= ~FIEMAP_FLAG_DEVICE_ORDER;
			memcpy(&fmkey->lfik_fiemap, fm_local,
			       sizeof(*fm_local));
			*buflen = fiemap_count_to_size(
						fm_local->fm_extent_count);

			rc = cl_object_fiemap(env, subobj, fmkey, fm_local,
					      buflen);
			if (rc != 0)
				GOTO(obj_put, rc);
inactive_tgt:
			ext_count = fm_local->fm_mapped_extents;
			if (ext_count == 0) {
				ost_done = true;
				/* If last stripe has hold at the end,
				 * we need to return */
				if (cur_stripe_wrap == last_stripe) {
					fiemap->fm_mapped_extents = 0;
					goto finish;
				}
				break;
			} else if (enough) {
				/*
				 * We've collected enough extents and there are
				 * more extents after it.
				 */
				goto finish;
			}

			/* If we just need num of extents, got to next device */
			if (fiemap->fm_extent_count == 0) {
				current_extent += ext_count;
				break;
			}

			/* prepare to copy retrived map extents */
			len_mapped_single_call =
				lcl_fm_ext[ext_count - 1].fe_logical -
				lun_start + lcl_fm_ext[ext_count - 1].fe_length;

			/* Have we finished mapping on this device? */
			if (req_fm_len <= len_mapped_single_call)
				ost_done = true;

			/* Clear the EXTENT_LAST flag which can be present on
			 * the last extent */
			if (lcl_fm_ext[ext_count - 1].fe_flags &
			    FIEMAP_EXTENT_LAST)
				lcl_fm_ext[ext_count - 1].fe_flags &=
							~FIEMAP_EXTENT_LAST;
			if (lov_stripe_size(lsm,
					lcl_fm_ext[ext_count - 1].fe_logical +
					lcl_fm_ext[ext_count - 1].fe_length,
					cur_stripe) >= fmkey->lfik_oa.o_size)
				ost_eof = true;

			fiemap_prepare_and_copy_exts(fiemap, lcl_fm_ext,
						     ost_index, ext_count,
						     current_extent);
			current_extent += ext_count;

			/* Ran out of available extents? */
			if (current_extent >= fiemap->fm_extent_count)
				enough = true;
		} while (!ost_done && !ost_eof);

		cl_object_put(env, subobj);
		subobj = NULL;

		if (cur_stripe_wrap == last_stripe)
			goto finish;
	} /* for each stripe */
finish:
	/* Indicate that we are returning device offsets unless file just has
	 * single stripe */
	if (lsm->lsm_stripe_count > 1)
		fiemap->fm_flags |= FIEMAP_FLAG_DEVICE_ORDER;

	if (fiemap->fm_extent_count == 0)
		goto skip_last_device_calc;

	/* Check if we have reached the last stripe and whether mapping for that
	 * stripe is done. */
	if ((cur_stripe_wrap == last_stripe) && (ost_done || ost_eof))
		fiemap->fm_extents[current_extent - 1].fe_flags |=
							     FIEMAP_EXTENT_LAST;
skip_last_device_calc:
	fiemap->fm_mapped_extents = current_extent;
obj_put:
	if (subobj != NULL)
		cl_object_put(env, subobj);
out_fm_local:
	OBD_FREE_LARGE(fm_local, buffer_size);

out_lsm:
	lov_lsm_put(lsm);

	return rc;
}