+ 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, rc = -ENOTSUPP);
+
+ if (lsm_is_released(lsm)) {
+ if (fiemap->fm_start < fmkey->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->oa.o_size)
+ fiemap->fm_extents[0].fe_length =
+ fiemap->fm_length;
+ else
+ fiemap->fm_extents[0].fe_length =
+ fmkey->oa.o_size - fiemap->fm_start;
+ fiemap->fm_extents[0].fe_flags |=
+ FIEMAP_EXTENT_UNKNOWN | FIEMAP_EXTENT_LAST;
+ }
+ GOTO(out, 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, 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->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->oa.o_size)
+ fm_end = fmkey->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, 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, 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, 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->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;
+ }