diff options
Diffstat (limited to 'drivers/staging/lustre/lustre/lov/lov_object.c')
-rw-r--r-- | drivers/staging/lustre/lustre/lov/lov_object.c | 698 |
1 files changed, 621 insertions, 77 deletions
diff --git a/drivers/staging/lustre/lustre/lov/lov_object.c b/drivers/staging/lustre/lustre/lov/lov_object.c index 52f7363..76d4256 100644 --- a/drivers/staging/lustre/lustre/lov/lov_object.c +++ b/drivers/staging/lustre/lustre/lov/lov_object.c @@ -39,6 +39,11 @@ #include "lov_cl_internal.h" +static inline struct lov_device *lov_object_dev(struct lov_object *obj) +{ + return lu2lov_dev(obj->lo_cl.co_lu.lo_dev); +} + /** \addtogroup lov * @{ */ @@ -51,7 +56,7 @@ struct lov_layout_operations { int (*llo_init)(const struct lu_env *env, struct lov_device *dev, - struct lov_object *lov, + struct lov_object *lov, struct lov_stripe_md *lsm, const struct cl_object_conf *conf, union lov_layout_state *state); int (*llo_delete)(const struct lu_env *env, struct lov_object *lov, @@ -75,12 +80,11 @@ struct lov_layout_operations { static int lov_layout_wait(const struct lu_env *env, struct lov_object *lov); -void lov_lsm_put(struct cl_object *unused, struct lov_stripe_md *lsm) +static void lov_lsm_put(struct lov_stripe_md *lsm) { if (lsm) lov_free_memmd(&lsm); } -EXPORT_SYMBOL(lov_lsm_put); /***************************************************************************** * @@ -97,17 +101,17 @@ static void lov_install_empty(const struct lu_env *env, */ } -static int lov_init_empty(const struct lu_env *env, - struct lov_device *dev, struct lov_object *lov, +static int lov_init_empty(const struct lu_env *env, struct lov_device *dev, + struct lov_object *lov, struct lov_stripe_md *lsm, const struct cl_object_conf *conf, - union lov_layout_state *state) + union lov_layout_state *state) { return 0; } static void lov_install_raid0(const struct lu_env *env, struct lov_object *lov, - union lov_layout_state *state) + union lov_layout_state *state) { } @@ -212,8 +216,8 @@ static int lov_page_slice_fixup(struct lov_object *lov, return cl_object_header(stripe)->coh_page_bufsize; } -static int lov_init_raid0(const struct lu_env *env, - struct lov_device *dev, struct lov_object *lov, +static int lov_init_raid0(const struct lu_env *env, struct lov_device *dev, + struct lov_object *lov, struct lov_stripe_md *lsm, const struct cl_object_conf *conf, union lov_layout_state *state) { @@ -223,7 +227,6 @@ static int lov_init_raid0(const struct lu_env *env, struct cl_object *stripe; struct lov_thread_info *lti = lov_env_info(env); struct cl_object_conf *subconf = <i->lti_stripe_conf; - struct lov_stripe_md *lsm = conf->u.coc_md->lsm; struct lu_fid *ofid = <i->lti_fid; struct lov_layout_raid0 *r0 = &state->raid0; @@ -298,13 +301,11 @@ out: return result; } -static int lov_init_released(const struct lu_env *env, - struct lov_device *dev, struct lov_object *lov, +static int lov_init_released(const struct lu_env *env, struct lov_device *dev, + struct lov_object *lov, struct lov_stripe_md *lsm, const struct cl_object_conf *conf, union lov_layout_state *state) { - struct lov_stripe_md *lsm = conf->u.coc_md->lsm; - LASSERT(lsm); LASSERT(lsm_is_released(lsm)); LASSERT(!lov->lo_lsm); @@ -313,6 +314,40 @@ static int lov_init_released(const struct lu_env *env, return 0; } +static struct cl_object *lov_find_subobj(const struct lu_env *env, + struct lov_object *lov, + struct lov_stripe_md *lsm, + int stripe_idx) +{ + struct lov_device *dev = lu2lov_dev(lov2lu(lov)->lo_dev); + struct lov_oinfo *oinfo = lsm->lsm_oinfo[stripe_idx]; + struct lov_thread_info *lti = lov_env_info(env); + struct lu_fid *ofid = <i->lti_fid; + struct cl_device *subdev; + struct cl_object *result; + int ost_idx; + int rc; + + if (lov->lo_type != LLT_RAID0) { + result = NULL; + goto out; + } + + ost_idx = oinfo->loi_ost_idx; + rc = ostid_to_fid(ofid, &oinfo->loi_oi, ost_idx); + if (rc) { + result = NULL; + goto out; + } + + subdev = lovsub2cl_dev(dev->ld_target[ost_idx]); + result = lov_sub_find(env, subdev, ofid, NULL); +out: + if (!result) + result = ERR_PTR(-EINVAL); + return result; +} + static int lov_delete_empty(const struct lu_env *env, struct lov_object *lov, union lov_layout_state *state) { @@ -687,31 +722,24 @@ static int lov_layout_wait(const struct lu_env *env, struct lov_object *lov) } static int lov_layout_change(const struct lu_env *unused, - struct lov_object *lov, + struct lov_object *lov, struct lov_stripe_md *lsm, const struct cl_object_conf *conf) { - int result; - enum lov_layout_type llt = LLT_EMPTY; + enum lov_layout_type llt = lov_type(lsm); union lov_layout_state *state = &lov->u; const struct lov_layout_operations *old_ops; const struct lov_layout_operations *new_ops; - - void *cookie; struct lu_env *env; int refcheck; + int rc; LASSERT(0 <= lov->lo_type && lov->lo_type < ARRAY_SIZE(lov_dispatch)); - if (conf->u.coc_md) - llt = lov_type(conf->u.coc_md->lsm); - LASSERT(0 <= llt && llt < ARRAY_SIZE(lov_dispatch)); - - cookie = cl_env_reenter(); env = cl_env_get(&refcheck); - if (IS_ERR(env)) { - cl_env_reexit(cookie); + if (IS_ERR(env)) return PTR_ERR(env); - } + + LASSERT(0 <= llt && llt < ARRAY_SIZE(lov_dispatch)); CDEBUG(D_INODE, DFID" from %s to %s\n", PFID(lu_object_fid(lov2lu(lov))), @@ -720,38 +748,37 @@ static int lov_layout_change(const struct lu_env *unused, old_ops = &lov_dispatch[lov->lo_type]; new_ops = &lov_dispatch[llt]; - result = cl_object_prune(env, &lov->lo_cl); - if (result != 0) + rc = cl_object_prune(env, &lov->lo_cl); + if (rc) + goto out; + + rc = old_ops->llo_delete(env, lov, &lov->u); + if (rc) goto out; - result = old_ops->llo_delete(env, lov, &lov->u); - if (result == 0) { - old_ops->llo_fini(env, lov, &lov->u); + old_ops->llo_fini(env, lov, &lov->u); - LASSERT(atomic_read(&lov->lo_active_ios) == 0); + LASSERT(!atomic_read(&lov->lo_active_ios)); - lov->lo_type = LLT_EMPTY; - /* page bufsize fixup */ - cl_object_header(&lov->lo_cl)->coh_page_bufsize -= + lov->lo_type = LLT_EMPTY; + + /* page bufsize fixup */ + cl_object_header(&lov->lo_cl)->coh_page_bufsize -= lov_page_slice_fixup(lov, NULL); - result = new_ops->llo_init(env, - lu2lov_dev(lov->lo_cl.co_lu.lo_dev), - lov, conf, state); - if (result == 0) { - new_ops->llo_install(env, lov, state); - lov->lo_type = llt; - } else { - new_ops->llo_delete(env, lov, state); - new_ops->llo_fini(env, lov, state); - /* this file becomes an EMPTY file. */ - } + rc = new_ops->llo_init(env, lov_object_dev(lov), lov, lsm, conf, state); + if (rc) { + new_ops->llo_delete(env, lov, state); + new_ops->llo_fini(env, lov, state); + /* this file becomes an EMPTY file. */ + goto out; } + new_ops->llo_install(env, lov, state); + lov->lo_type = llt; out: cl_env_put(env, &refcheck); - cl_env_reexit(cookie); - return result; + return rc; } /***************************************************************************** @@ -762,26 +789,38 @@ out: int lov_object_init(const struct lu_env *env, struct lu_object *obj, const struct lu_object_conf *conf) { - struct lov_device *dev = lu2lov_dev(obj->lo_dev); struct lov_object *lov = lu2lov(obj); + struct lov_device *dev = lov_object_dev(lov); const struct cl_object_conf *cconf = lu2cl_conf(conf); union lov_layout_state *set = &lov->u; const struct lov_layout_operations *ops; - int result; + struct lov_stripe_md *lsm = NULL; + int rc; init_rwsem(&lov->lo_type_guard); atomic_set(&lov->lo_active_ios, 0); init_waitqueue_head(&lov->lo_waitq); - cl_object_page_init(lu2cl(obj), sizeof(struct lov_page)); + lov->lo_type = LLT_EMPTY; + if (cconf->u.coc_layout.lb_buf) { + lsm = lov_unpackmd(dev->ld_lov, + cconf->u.coc_layout.lb_buf, + cconf->u.coc_layout.lb_len); + if (IS_ERR(lsm)) + return PTR_ERR(lsm); + } + /* no locking is necessary, as object is being created */ - lov->lo_type = lov_type(cconf->u.coc_md->lsm); + lov->lo_type = lov_type(lsm); ops = &lov_dispatch[lov->lo_type]; - result = ops->llo_init(env, dev, lov, cconf, set); - if (result == 0) + rc = ops->llo_init(env, dev, lov, lsm, cconf, set); + if (!rc) ops->llo_install(env, lov, set); - return result; + + lov_lsm_put(lsm); + + return rc; } static int lov_conf_set(const struct lu_env *env, struct cl_object *obj, @@ -791,6 +830,15 @@ static int lov_conf_set(const struct lu_env *env, struct cl_object *obj, struct lov_object *lov = cl2lov(obj); int result = 0; + if (conf->coc_opc == OBJECT_CONF_SET && + conf->u.coc_layout.lb_buf) { + lsm = lov_unpackmd(lov_object_dev(lov)->ld_lov, + conf->u.coc_layout.lb_buf, + conf->u.coc_layout.lb_len); + if (IS_ERR(lsm)) + return PTR_ERR(lsm); + } + lov_conf_lock(lov); if (conf->coc_opc == OBJECT_CONF_INVALIDATE) { lov->lo_layout_invalid = true; @@ -810,8 +858,6 @@ static int lov_conf_set(const struct lu_env *env, struct cl_object *obj, LASSERT(conf->coc_opc == OBJECT_CONF_SET); - if (conf->u.coc_md) - lsm = conf->u.coc_md->lsm; if ((!lsm && !lov->lo_lsm) || ((lsm && lov->lo_lsm) && (lov->lo_lsm->lsm_layout_gen == lsm->lsm_layout_gen) && @@ -829,11 +875,12 @@ static int lov_conf_set(const struct lu_env *env, struct cl_object *obj, goto out; } - result = lov_layout_change(env, lov, conf); + result = lov_layout_change(env, lov, lsm, conf); lov->lo_layout_invalid = result != 0; out: lov_conf_unlock(lov); + lov_lsm_put(lsm); CDEBUG(D_INODE, DFID" lo_layout_invalid=%d\n", PFID(lu_object_fid(lov2lu(lov))), lov->lo_layout_invalid); return result; @@ -911,6 +958,473 @@ int lov_lock_init(const struct lu_env *env, struct cl_object *obj, io); } +/** + * 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))) + break; + } + *stripe_count = j; + last_stripe = (start_stripe + j - 1) % lsm->lsm_stripe_count; + } + + return last_stripe; +} + +/** + * Set fe_device and copy extents from local buffer into main return buffer. + * + * \param fiemap [out] fiemap to hold all extents + * \param lcl_fm_ext [in] array of fiemap extents get from OSC layer + * \param ost_index [in] OST index to be written into the fm_device + * field for each extent + * \param ext_count [in] number of extents to be copied + * \param current_extent [in] where to start copying in the extent array + */ +static void fiemap_prepare_and_copy_exts(struct fiemap *fiemap, + struct fiemap_extent *lcl_fm_ext, + int ost_index, unsigned int ext_count, + int current_extent) +{ + unsigned int ext; + char *to; + + for (ext = 0; ext < ext_count; ext++) { + lcl_fm_ext[ext].fe_device = ost_index; + lcl_fm_ext[ext].fe_flags |= FIEMAP_EXTENT_NET; + } + + /* Copy fm_extent's from fm_local to return buffer */ + to = (char *)fiemap + fiemap_count_to_size(current_extent); + memcpy(to, lcl_fm_ext, ext_count * sizeof(struct fiemap_extent)); +} + +#define FIEMAP_BUFFER_SIZE 4096 + +/** + * 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, lun_end; + loff_t fm_end_offset; + int stripe_no = -1; + int i; + + if (!fiemap->fm_extent_count || !fiemap->fm_extents[0].fe_logical) + 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) && + 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; +} + +/** + * 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_obd *lov = lu2lov_dev(obj->co_lu.lo_dev)->ld_lov; + unsigned int buffer_size = FIEMAP_BUFFER_SIZE; + struct fiemap_extent *lcl_fm_ext; + struct cl_object *subobj = NULL; + struct fiemap *fm_local = NULL; + struct lov_stripe_md *lsm; + 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; + /* 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; + + lsm = lov_lsm_addref(cl2lov(obj)); + if (!lsm) + 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)) { + rc = -ENOTSUPP; + goto out; + } + + 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; + } + rc = 0; + goto out; + } + + if (fiemap_count_to_size(fiemap->fm_extent_count) < buffer_size) + buffer_size = fiemap_count_to_size(fiemap->fm_extent_count); + + fm_local = libcfs_kvzalloc(buffer_size, GFP_NOFS); + if (!fm_local) { + rc = -ENOMEM; + goto out; + } + 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) { + rc = -EINVAL; + goto out; + } + + /** + * 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) + 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))) + continue; + + if (lov_oinfo_is_dummy(lsm->lsm_oinfo[cur_stripe])) { + rc = -EIO; + goto out; + } + + /* + * 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 && 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)) { + rc = PTR_ERR(subobj); + goto out; + } + /* + * 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) { + rc = -EINVAL; + goto obj_put; + } + /* + * 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) + goto obj_put; +inactive_tgt: + ext_count = fm_local->fm_mapped_extents; + if (!ext_count) { + 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) { + 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) + 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) + cl_object_put(env, subobj); +out: + kvfree(fm_local); + lov_lsm_put(lsm); + return rc; +} + static int lov_object_getstripe(const struct lu_env *env, struct cl_object *obj, struct lov_user_md __user *lum) { @@ -923,10 +1437,53 @@ static int lov_object_getstripe(const struct lu_env *env, struct cl_object *obj, return -ENODATA; rc = lov_getstripe(cl2lov(obj), lsm, lum); - lov_lsm_put(obj, lsm); + lov_lsm_put(lsm); return rc; } +static int lov_object_layout_get(const struct lu_env *env, + struct cl_object *obj, + struct cl_layout *cl) +{ + struct lov_object *lov = cl2lov(obj); + struct lov_stripe_md *lsm = lov_lsm_addref(lov); + struct lu_buf *buf = &cl->cl_buf; + ssize_t rc; + + if (!lsm) { + cl->cl_size = 0; + cl->cl_layout_gen = CL_LAYOUT_GEN_EMPTY; + cl->cl_is_released = false; + + return 0; + } + + cl->cl_size = lov_mds_md_size(lsm->lsm_stripe_count, lsm->lsm_magic); + cl->cl_layout_gen = lsm->lsm_layout_gen; + cl->cl_is_released = lsm_is_released(lsm); + + rc = lov_lsm_pack(lsm, buf->lb_buf, buf->lb_len); + lov_lsm_put(lsm); + + return rc < 0 ? rc : 0; +} + +static loff_t lov_object_maxbytes(struct cl_object *obj) +{ + struct lov_object *lov = cl2lov(obj); + struct lov_stripe_md *lsm = lov_lsm_addref(lov); + loff_t maxbytes; + + if (!lsm) + return LLONG_MAX; + + maxbytes = lsm->lsm_maxbytes; + + lov_lsm_put(lsm); + + return maxbytes; +} + static const struct cl_object_operations lov_ops = { .coo_page_init = lov_page_init, .coo_lock_init = lov_lock_init, @@ -934,7 +1491,10 @@ static const struct cl_object_operations lov_ops = { .coo_attr_get = lov_attr_get, .coo_attr_update = lov_attr_update, .coo_conf_set = lov_conf_set, - .coo_getstripe = lov_object_getstripe + .coo_getstripe = lov_object_getstripe, + .coo_layout_get = lov_object_layout_get, + .coo_maxbytes = lov_object_maxbytes, + .coo_fiemap = lov_object_fiemap, }; static const struct lu_object_operations lov_lu_obj_ops = { @@ -986,22 +1546,6 @@ struct lov_stripe_md *lov_lsm_addref(struct lov_object *lov) return lsm; } -struct lov_stripe_md *lov_lsm_get(struct cl_object *clobj) -{ - struct lu_object *luobj; - struct lov_stripe_md *lsm = NULL; - - if (!clobj) - return NULL; - - luobj = lu_object_locate(&cl_object_header(clobj)->coh_lu, - &lov_device_type); - if (luobj) - lsm = lov_lsm_addref(lu2lov(luobj)); - return lsm; -} -EXPORT_SYMBOL(lov_lsm_get); - int lov_read_and_clear_async_rc(struct cl_object *clob) { struct lu_object *luobj; |