/* 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 obd_export *exp, struct lov_stripe_md *lsm, struct lov_user_md *lump) { /* * XXX huge struct allocated on stack. */ /* we use lov_user_md_v3 because it is larger than lov_user_md_v1 */ struct lov_user_md_v3 lum; struct lov_mds_md *lmmk = NULL; int rc, 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)) GOTO(out_set, rc = -EFAULT); else if ((lum.lmm_magic != LOV_USER_MAGIC) && (lum.lmm_magic != LOV_USER_MAGIC_V3)) GOTO(out_set, rc = -EINVAL); 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); GOTO(out_set, rc = -EOVERFLOW); } rc = lov_packmd(exp, &lmmk, lsm); if (rc < 0) GOTO(out_set, 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((char *)(&lmmk->lmm_stripe_count) + sizeof(lmmk->lmm_stripe_count), ((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) GOTO(out_set, rc = -EOVERFLOW); /* * 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; obd_free_diskmd(exp, &lmmk); out_set: set_fs(seg); 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. * * If @size > 0, User specified limited buffer size, usually the buffer is from * ll_lov_setstripe(), and the buffer can only hold basic layout template info. */ int lov_getstripe(const struct lu_env *env, struct lov_object *obj, struct lov_stripe_md *lsm, struct lov_user_md __user *lump, size_t size) { /* we use lov_user_md_v3 because it is larger than lov_user_md_v1 */ struct lov_mds_md *lmmk, *lmm; struct lov_user_md_v1 lum; size_t lmmk_size; ssize_t lmm_size, lum_size = 0; static bool printed; int rc = 0; ENTRY; if (lsm->lsm_magic != LOV_MAGIC_V1 && lsm->lsm_magic != LOV_MAGIC_V3 && lsm->lsm_magic != LOV_MAGIC_COMP_V1) { CERROR("bad LSM MAGIC: 0x%08X != 0x%08X nor 0x%08X\n", lsm->lsm_magic, LOV_MAGIC_V1, LOV_MAGIC_V3); GOTO(out, rc = -EIO); } if (!printed) { LCONSOLE_WARN("%s: using old ioctl(LL_IOC_LOV_GETSTRIPE) on " DFID", use llapi_layout_get_by_path()\n", current->comm, PFID(&obj->lo_cl.co_lu.lo_header->loh_fid)); printed = true; } lmmk_size = lov_comp_md_size(lsm); OBD_ALLOC_LARGE(lmmk, lmmk_size); if (lmmk == NULL) GOTO(out, rc = -ENOMEM); lmm_size = lov_lsm_pack(lsm, lmmk, lmmk_size); if (lmm_size < 0) GOTO(out_free, rc = lmm_size); if (cpu_to_le32(LOV_MAGIC) != LOV_MAGIC) { if (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); } else if (lmmk->lmm_magic == cpu_to_le32(LOV_MAGIC_COMP_V1)) { lustre_swab_lov_comp_md_v1( (struct lov_comp_md_v1 *)lmmk); } } /* Legacy appication passes limited buffer, we need to figure out * the user buffer size by the passed in lmm_stripe_count. */ if (copy_from_user(&lum, lump, sizeof(struct lov_user_md_v1))) GOTO(out_free, rc = -EFAULT); if (lum.lmm_magic == LOV_USER_MAGIC_V1 || lum.lmm_magic == LOV_USER_MAGIC_V3) lum_size = lov_user_md_size(lum.lmm_stripe_count, lum.lmm_magic); if (lum_size != 0) { struct lov_mds_md *comp_md = lmmk; /* Legacy app (ADIO for instance) treats the layout as V1/V3 * blindly, we'd return a reasonable V1/V3 for them. */ if (lmmk->lmm_magic == LOV_MAGIC_COMP_V1) { struct lov_comp_md_v1 *comp_v1; struct cl_object *cl_obj; struct cl_attr attr; int i; attr.cat_size = 0; cl_obj = cl_object_top(&obj->lo_cl); cl_object_attr_get(env, cl_obj, &attr); /* return the last instantiated component if file size * is non-zero, otherwise, return the last component.*/ comp_v1 = (struct lov_comp_md_v1 *)lmmk; i = attr.cat_size == 0 ? comp_v1->lcm_entry_count : 0; for (; i < comp_v1->lcm_entry_count; i++) { if (!(comp_v1->lcm_entries[i].lcme_flags & LCME_FL_INIT)) break; } if (i > 0) i--; comp_md = (struct lov_mds_md *)((char *)comp_v1 + comp_v1->lcm_entries[i].lcme_offset); } lmm = comp_md; lmm_size = lum_size; } else { lmm = lmmk; lmm_size = lmmk_size; } /** * User specified limited buffer size, usually the buffer is * from ll_lov_setstripe(), and the buffer can only hold basic * layout template info. */ if (size == 0 || size > lmm_size) size = lmm_size; if (copy_to_user(lump, lmm, size)) GOTO(out_free, rc = -EFAULT); out_free: OBD_FREE_LARGE(lmmk, lmmk_size); out: 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) { /* we use lov_user_md_v3 because it is larger than lov_user_md_v1 */ struct lov_user_md_v3 lum; struct lov_mds_md *lmmk; u32 stripe_count; ssize_t lmm_size; size_t lmmk_size; size_t lum_size; int rc; if (!lsm) return -ENODATA; if (lsm->lsm_magic != LOV_MAGIC_V1 && lsm->lsm_magic != LOV_MAGIC_V3) { CERROR("bad LSM MAGIC: 0x%08X != 0x%08X nor 0x%08X\n", lsm->lsm_magic, LOV_MAGIC_V1, LOV_MAGIC_V3); rc = -EIO; goto out; } if (!lsm_is_released(lsm)) stripe_count = lsm->lsm_stripe_count; else stripe_count = 0; /* 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 = stripe_count; rc = copy_to_user(lump, &lum, lum_size); rc = -EOVERFLOW; goto out; } lmmk_size = lov_mds_md_size(stripe_count, lsm->lsm_magic); lmmk = kvzalloc(lmmk_size, GFP_NOFS); if (!lmmk) { rc = -ENOMEM; goto out; } lmm_size = lov_lsm_pack(lsm, lmmk, lmmk_size); if (lmm_size < 0) { rc = lmm_size; goto out_free; } /* FIXME: Bug 1185 - copy fields properly when structs change */ /* struct lov_user_md_v3 and struct lov_mds_md_v3 must be the same */ BUILD_BUG_ON(sizeof(lum) != sizeof(struct lov_mds_md_v3)); BUILD_BUG_ON(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; else rc = 0; out_free: kvfree(lmmk); out: return rc; }