Esempio n. 1
0
/**
 * Compute file level page index by stripe level page offset
 */
pgoff_t lov_stripe_pgoff(struct lov_stripe_md *lsm, pgoff_t stripe_index,
			 int stripe)
{
	obd_off offset;

	offset = lov_stripe_size(lsm, stripe_index << PAGE_CACHE_SHIFT,
				 stripe);
	return offset >> PAGE_CACHE_SHIFT;
}
Esempio n. 2
0
void lov_merge_attrs(struct obdo *tgt, struct obdo *src, u64 valid,
		     struct lov_stripe_md *lsm, int stripeno, int *set)
{
	valid &= src->o_valid;

	if (*set) {
		if (valid & OBD_MD_FLSIZE) {
			/* this handles sparse files properly */
			u64 lov_size;

			lov_size = lov_stripe_size(lsm, src->o_size, stripeno);
			if (lov_size > tgt->o_size)
				tgt->o_size = lov_size;
		}
		if (valid & OBD_MD_FLBLOCKS)
			tgt->o_blocks += src->o_blocks;
		if (valid & OBD_MD_FLBLKSZ)
			tgt->o_blksize += src->o_blksize;
		if (valid & OBD_MD_FLCTIME && tgt->o_ctime < src->o_ctime)
			tgt->o_ctime = src->o_ctime;
		if (valid & OBD_MD_FLMTIME && tgt->o_mtime < src->o_mtime)
			tgt->o_mtime = src->o_mtime;
		if (valid & OBD_MD_FLDATAVERSION)
			tgt->o_data_version += src->o_data_version;
	} else {
		memcpy(tgt, src, sizeof(*tgt));
		tgt->o_oi = lsm->lsm_oi;
		if (valid & OBD_MD_FLSIZE)
			tgt->o_size = lov_stripe_size(lsm, src->o_size,
						      stripeno);
	}

	/* data_version needs to be valid on all stripes to be correct! */
	if (!(valid & OBD_MD_FLDATAVERSION))
		tgt->o_valid &= ~OBD_MD_FLDATAVERSION;

	*set += 1;
}
Esempio n. 3
0
/** Merge the lock value block(&lvb) attributes and KMS from each of the
 * stripes in a file into a single lvb. It is expected that the caller
 * initializes the current atime, mtime, ctime to avoid regressing a more
 * uptodate time on the local client.
 */
int lov_merge_lvb_kms(struct lov_stripe_md *lsm,
		      struct ost_lvb *lvb, __u64 *kms_place)
{
	__u64 size = 0;
	__u64 kms = 0;
	__u64 blocks = 0;
	s64 current_mtime = lvb->lvb_mtime;
	s64 current_atime = lvb->lvb_atime;
	s64 current_ctime = lvb->lvb_ctime;
	int i;
	int rc = 0;

	assert_spin_locked(&lsm->lsm_lock);
	LASSERT(lsm->lsm_lock_owner == current_pid());

	CDEBUG(D_INODE, "MDT ID "DOSTID" initial value: s=%llu m=%llu a=%llu c=%llu b=%llu\n",
	       POSTID(&lsm->lsm_oi), lvb->lvb_size, lvb->lvb_mtime,
	       lvb->lvb_atime, lvb->lvb_ctime, lvb->lvb_blocks);
	for (i = 0; i < lsm->lsm_stripe_count; i++) {
		struct lov_oinfo *loi = lsm->lsm_oinfo[i];
		u64 lov_size, tmpsize;

		if (OST_LVB_IS_ERR(loi->loi_lvb.lvb_blocks)) {
			rc = OST_LVB_GET_ERR(loi->loi_lvb.lvb_blocks);
			continue;
		}

		tmpsize = loi->loi_kms;
		lov_size = lov_stripe_size(lsm, tmpsize, i);
		if (lov_size > kms)
			kms = lov_size;

		if (loi->loi_lvb.lvb_size > tmpsize)
			tmpsize = loi->loi_lvb.lvb_size;

		lov_size = lov_stripe_size(lsm, tmpsize, i);
		if (lov_size > size)
			size = lov_size;
		/* merge blocks, mtime, atime */
		blocks += loi->loi_lvb.lvb_blocks;
		if (loi->loi_lvb.lvb_mtime > current_mtime)
			current_mtime = loi->loi_lvb.lvb_mtime;
		if (loi->loi_lvb.lvb_atime > current_atime)
			current_atime = loi->loi_lvb.lvb_atime;
		if (loi->loi_lvb.lvb_ctime > current_ctime)
			current_ctime = loi->loi_lvb.lvb_ctime;

		CDEBUG(D_INODE, "MDT ID "DOSTID" on OST[%u]: s=%llu m=%llu a=%llu c=%llu b=%llu\n",
		       POSTID(&lsm->lsm_oi), loi->loi_ost_idx,
		       loi->loi_lvb.lvb_size, loi->loi_lvb.lvb_mtime,
		       loi->loi_lvb.lvb_atime, loi->loi_lvb.lvb_ctime,
		       loi->loi_lvb.lvb_blocks);
	}

	*kms_place = kms;
	lvb->lvb_size = size;
	lvb->lvb_blocks = blocks;
	lvb->lvb_mtime = current_mtime;
	lvb->lvb_atime = current_atime;
	lvb->lvb_ctime = current_ctime;
	return rc;
}
Esempio n. 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;
}
Esempio n. 5
0
/** Merge the lock value block(&lvb) attributes and KMS from each of the
 * stripes in a file into a single lvb. It is expected that the caller
 * initializes the current atime, mtime, ctime to avoid regressing a more
 * uptodate time on the local client.
 */
int lov_merge_lvb_kms(struct lov_stripe_md *lsm,
                      struct ost_lvb *lvb, __u64 *kms_place)
{
    __u64 size = 0;
    __u64 kms = 0;
    __u64 blocks = 0;
    obd_time current_mtime = lvb->lvb_mtime;
    obd_time current_atime = lvb->lvb_atime;
    obd_time current_ctime = lvb->lvb_ctime;
    int i;
    int rc = 0;

    LASSERT_SPIN_LOCKED(&lsm->lsm_lock);
#ifdef __KERNEL__
    LASSERT(lsm->lsm_lock_owner == cfs_curproc_pid());
#endif

    CDEBUG(D_INODE, "MDT FID "DFID" initial value: s="LPU64" m="LPU64
           " a="LPU64" c="LPU64" b="LPU64"\n",
           lsm->lsm_object_seq, (__u32)lsm->lsm_object_id,
           (__u32)(lsm->lsm_object_id >> 32), lvb->lvb_size,
           lvb->lvb_mtime, lvb->lvb_atime, lvb->lvb_ctime, lvb->lvb_blocks);
    for (i = 0; i < lsm->lsm_stripe_count; i++) {
        struct lov_oinfo *loi = lsm->lsm_oinfo[i];
        obd_size lov_size, tmpsize;

        if (OST_LVB_IS_ERR(loi->loi_lvb.lvb_blocks)) {
            rc = OST_LVB_GET_ERR(loi->loi_lvb.lvb_blocks);
            continue;
        }

        tmpsize = loi->loi_kms;
        lov_size = lov_stripe_size(lsm, tmpsize, i);
        if (lov_size > kms)
            kms = lov_size;

        if (loi->loi_lvb.lvb_size > tmpsize)
            tmpsize = loi->loi_lvb.lvb_size;

        lov_size = lov_stripe_size(lsm, tmpsize, i);
        if (lov_size > size)
            size = lov_size;
        /* merge blocks, mtime, atime */
        blocks += loi->loi_lvb.lvb_blocks;
        if (loi->loi_lvb.lvb_mtime > current_mtime)
            current_mtime = loi->loi_lvb.lvb_mtime;
        if (loi->loi_lvb.lvb_atime > current_atime)
            current_atime = loi->loi_lvb.lvb_atime;
        if (loi->loi_lvb.lvb_ctime > current_ctime)
            current_ctime = loi->loi_lvb.lvb_ctime;
        CDEBUG(D_INODE, "MDT FID "DFID" on OST[%u]: s="LPU64" m="LPU64
               " a="LPU64" c="LPU64" b="LPU64"\n",
               lsm->lsm_object_seq, (__u32)lsm->lsm_object_id,
               (__u32)(lsm->lsm_object_id >> 32), loi->loi_ost_idx,
               loi->loi_lvb.lvb_size, loi->loi_lvb.lvb_mtime,
               loi->loi_lvb.lvb_atime, loi->loi_lvb.lvb_ctime,
               loi->loi_lvb.lvb_blocks);
    }

    *kms_place = kms;
    lvb->lvb_size = size;
    lvb->lvb_blocks = blocks;
    lvb->lvb_mtime = current_mtime;
    lvb->lvb_atime = current_atime;
    lvb->lvb_ctime = current_ctime;
    RETURN(rc);
}