/***************************************************************************** * * Lov object operations. * */ 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); const struct cl_object_conf *cconf = lu2cl_conf(conf); union lov_layout_state *set = &lov->u; const struct lov_layout_operations *ops; int result; ENTRY; init_rwsem(&lov->lo_type_guard); cfs_atomic_set(&lov->lo_active_ios, 0); init_waitqueue_head(&lov->lo_waitq); cl_object_page_init(lu2cl(obj), sizeof(struct lov_page)); /* no locking is necessary, as object is being created */ lov->lo_type = lov_type(cconf->u.coc_md->lsm); ops = &lov_dispatch[lov->lo_type]; result = ops->llo_init(env, dev, lov, cconf, set); if (result == 0) ops->llo_install(env, lov, set); RETURN(result); }
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; int ost_idx; int rc; struct cl_object *result; if (lov->lo_type != LLT_RAID0) GOTO(out, result = NULL); ost_idx = oinfo->loi_ost_idx; rc = ostid_to_fid(ofid, &oinfo->loi_oi, ost_idx); if (rc != 0) GOTO(out, result = NULL); subdev = lovsub2cl_dev(dev->ld_target[ost_idx]); result = lov_sub_find(env, subdev, ofid, NULL); out: if (result == NULL) result = ERR_PTR(-EINVAL); return result; }
static int lov_layout_change(const struct lu_env *unused, struct lov_object *lov, const struct cl_object_conf *conf) { int result; enum lov_layout_type llt = LLT_EMPTY; union lov_layout_state *state = &lov->u; const struct lov_layout_operations *old_ops; const struct lov_layout_operations *new_ops; struct cl_object_header *hdr = cl_object_header(&lov->lo_cl); void *cookie; struct lu_env *env; int refcheck; ENTRY; LASSERT(0 <= lov->lo_type && lov->lo_type < ARRAY_SIZE(lov_dispatch)); if (conf->u.coc_md != NULL) 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); RETURN(PTR_ERR(env)); } old_ops = &lov_dispatch[lov->lo_type]; new_ops = &lov_dispatch[llt]; result = old_ops->llo_delete(env, lov, &lov->u); if (result == 0) { old_ops->llo_fini(env, lov, &lov->u); LASSERT(cfs_atomic_read(&lov->lo_active_ios) == 0); LASSERT(hdr->coh_tree.rnode == NULL); LASSERT(hdr->coh_pages == 0); lov->lo_type = LLT_EMPTY; 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. */ } } cl_env_put(env, &refcheck); cl_env_reexit(cookie); RETURN(result); }
static void lov_cl_del_target(const struct lu_env *env, struct lu_device *dev, __u32 index) { struct lov_device *ld = lu2lov_dev(dev); if (ld->ld_target[index] != NULL) { cl_stack_fini(env, lovsub2cl_dev(ld->ld_target[index])); ld->ld_target[index] = NULL; } }
static struct lu_device *lov_device_free(const struct lu_env *env, struct lu_device *d) { struct lov_device *ld = lu2lov_dev(d); const int nr = ld->ld_target_nr; cl_device_fini(lu2cl_dev(d)); kfree(ld->ld_target); if (ld->ld_emrg != NULL) lov_emerg_free(ld->ld_emrg, nr); kfree(ld); return NULL; }
static struct lu_device *lov_device_free(const struct lu_env *env, struct lu_device *d) { struct lov_device *ld = lu2lov_dev(d); const int nr = ld->ld_target_nr; cl_device_fini(lu2cl_dev(d)); if (ld->ld_target != NULL) OBD_FREE(ld->ld_target, nr * sizeof(ld->ld_target[0])); if (ld->ld_emrg != NULL) lov_emerg_free(ld->ld_emrg, nr); OBD_FREE_PTR(ld); return NULL; }
static int lov_cl_add_target(const struct lu_env *env, struct lu_device *dev, __u32 index) { struct obd_device *obd = dev->ld_obd; struct lov_device *ld = lu2lov_dev(dev); struct lov_tgt_desc *tgt; struct lovsub_device *lsd; struct cl_device *cl; int rc; obd_getref(obd); tgt = obd->u.lov.lov_tgts[index]; LASSERT(tgt != NULL); LASSERT(tgt->ltd_obd != NULL); if (!tgt->ltd_obd->obd_set_up) { CERROR("Target %s not set up\n", obd_uuid2str(&tgt->ltd_uuid)); return -EINVAL; } rc = lov_expand_targets(env, ld); if (rc == 0 && ld->ld_flags & LOV_DEV_INITIALIZED) { LASSERT(dev->ld_site != NULL); cl = cl_type_setup(env, dev->ld_site, &lovsub_device_type, tgt->ltd_obd->obd_lu_dev); if (!IS_ERR(cl)) { lsd = cl2lovsub_dev(cl); lsd->acid_idx = index; lsd->acid_super = ld; ld->ld_target[index] = lsd; } else { CERROR("add failed (%d), deleting %s\n", rc, obd_uuid2str(&tgt->ltd_uuid)); lov_cl_del_target(env, dev, index); rc = PTR_ERR(cl); } } obd_putref(obd); return rc; }
static struct lu_device *lov_device_fini(const struct lu_env *env, struct lu_device *d) { int i; struct lov_device *ld = lu2lov_dev(d); LASSERT(ld->ld_lov != NULL); if (ld->ld_target == NULL) return NULL; lov_foreach_target(ld, i) { struct lovsub_device *lsd; lsd = ld->ld_target[i]; if (lsd != NULL) { cl_stack_fini(env, lovsub2cl_dev(lsd)); ld->ld_target[i] = NULL; } } return NULL; }
static int lov_device_init(const struct lu_env *env, struct lu_device *d, const char *name, struct lu_device *next) { struct lov_device *ld = lu2lov_dev(d); int i; int rc = 0; LASSERT(d->ld_site != NULL); if (ld->ld_target == NULL) return rc; lov_foreach_target(ld, i) { struct lovsub_device *lsd; struct cl_device *cl; struct lov_tgt_desc *desc; desc = ld->ld_lov->lov_tgts[i]; if (desc == NULL) continue; cl = cl_type_setup(env, d->ld_site, &lovsub_device_type, desc->ltd_obd->obd_lu_dev); if (IS_ERR(cl)) { rc = PTR_ERR(cl); break; } lsd = cl2lovsub_dev(cl); lsd->acid_idx = i; lsd->acid_super = ld; ld->ld_target[i] = lsd; } if (rc) lov_device_fini(env, d); else ld->ld_flags |= LOV_DEV_INITIALIZED; return rc; }
static int lov_layout_change(const struct lu_env *unused, struct lov_object *lov, const struct cl_object_conf *conf) { int result; enum lov_layout_type llt = LLT_EMPTY; 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; 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); return PTR_ERR(env); } CDEBUG(D_INODE, DFID" from %s to %s\n", PFID(lu_object_fid(lov2lu(lov))), llt2str(lov->lo_type), llt2str(llt)); old_ops = &lov_dispatch[lov->lo_type]; new_ops = &lov_dispatch[llt]; result = cl_object_prune(env, &lov->lo_cl); if (result != 0) goto out; result = old_ops->llo_delete(env, lov, &lov->u); if (result == 0) { old_ops->llo_fini(env, lov, &lov->u); LASSERT(atomic_read(&lov->lo_active_ios) == 0); lov->lo_type = LLT_EMPTY; 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. */ } } out: cl_env_put(env, &refcheck); cl_env_reexit(cookie); return result; }
static inline struct lov_device *lov_object_dev(struct lov_object *obj) { return lu2lov_dev(obj->lo_cl.co_lu.lo_dev); }
/** * 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; }
/* Retrieve object striping information. * * @lump is a pointer to an in-core struct with lmm_ost_count indicating * the maximum number of OST indices which will fit in the user buffer. * lmm_magic must be LOV_USER_MAGIC. */ int lov_getstripe(struct lov_object *obj, struct lov_stripe_md *lsm, struct lov_user_md __user *lump) { /* * XXX huge struct allocated on stack. */ /* we use lov_user_md_v3 because it is larger than lov_user_md_v1 */ struct lov_obd *lov; struct lov_user_md_v3 lum; struct lov_mds_md *lmmk = NULL; int rc, lmmk_size, lmm_size; int lum_size; mm_segment_t seg; if (!lsm) return -ENODATA; /* * "Switch to kernel segment" to allow copying from kernel space by * copy_{to,from}_user(). */ seg = get_fs(); set_fs(KERNEL_DS); /* we only need the header part from user space to get lmm_magic and * lmm_stripe_count, (the header part is common to v1 and v3) */ lum_size = sizeof(struct lov_user_md_v1); if (copy_from_user(&lum, lump, lum_size)) { rc = -EFAULT; goto out; } if (lum.lmm_magic != LOV_USER_MAGIC_V1 && lum.lmm_magic != LOV_USER_MAGIC_V3 && lum.lmm_magic != LOV_USER_MAGIC_SPECIFIC) { rc = -EINVAL; goto out; } if (lum.lmm_stripe_count && (lum.lmm_stripe_count < lsm->lsm_stripe_count)) { /* Return right size of stripe to user */ lum.lmm_stripe_count = lsm->lsm_stripe_count; rc = copy_to_user(lump, &lum, lum_size); rc = -EOVERFLOW; goto out; } lov = lu2lov_dev(obj->lo_cl.co_lu.lo_dev)->ld_lov; rc = lov_obd_packmd(lov, &lmmk, lsm); if (rc < 0) goto out; lmmk_size = rc; lmm_size = rc; rc = 0; /* FIXME: Bug 1185 - copy fields properly when structs change */ /* struct lov_user_md_v3 and struct lov_mds_md_v3 must be the same */ CLASSERT(sizeof(lum) == sizeof(struct lov_mds_md_v3)); CLASSERT(sizeof(lum.lmm_objects[0]) == sizeof(lmmk->lmm_objects[0])); if ((cpu_to_le32(LOV_MAGIC) != LOV_MAGIC) && ((lmmk->lmm_magic == cpu_to_le32(LOV_MAGIC_V1)) || (lmmk->lmm_magic == cpu_to_le32(LOV_MAGIC_V3)))) { lustre_swab_lov_mds_md(lmmk); lustre_swab_lov_user_md_objects( (struct lov_user_ost_data *)lmmk->lmm_objects, lmmk->lmm_stripe_count); } if (lum.lmm_magic == LOV_USER_MAGIC) { /* User request for v1, we need skip lmm_pool_name */ if (lmmk->lmm_magic == LOV_MAGIC_V3) { memmove(((struct lov_mds_md_v1 *)lmmk)->lmm_objects, ((struct lov_mds_md_v3 *)lmmk)->lmm_objects, lmmk->lmm_stripe_count * sizeof(struct lov_ost_data_v1)); lmm_size -= LOV_MAXPOOLNAME; } } else { /* if v3 we just have to update the lum_size */ lum_size = sizeof(struct lov_user_md_v3); } /* User wasn't expecting this many OST entries */ if (lum.lmm_stripe_count == 0) { lmm_size = lum_size; } else if (lum.lmm_stripe_count < lmmk->lmm_stripe_count) { rc = -EOVERFLOW; goto out_free; } /* * Have a difference between lov_mds_md & lov_user_md. * So we have to re-order the data before copy to user. */ lum.lmm_stripe_count = lmmk->lmm_stripe_count; lum.lmm_layout_gen = lmmk->lmm_layout_gen; ((struct lov_user_md *)lmmk)->lmm_layout_gen = lum.lmm_layout_gen; ((struct lov_user_md *)lmmk)->lmm_stripe_count = lum.lmm_stripe_count; if (copy_to_user(lump, lmmk, lmm_size)) rc = -EFAULT; out_free: kfree(lmmk); out: set_fs(seg); return rc; }