- struct lov_user_md lum;
- struct lov_mds_md *lmmk = NULL;
- int rc, lmm_size;
- ENTRY;
-
- if (!lsm)
- RETURN(-ENODATA);
-
- rc = copy_from_user(&lum, lump, sizeof(lum));
- if (rc)
- RETURN(-EFAULT);
-
- if (lum.lmm_magic != LOV_USER_MAGIC)
- RETURN(-EINVAL);
-
- rc = lov_packmd(exp, &lmmk, lsm);
- if (rc < 0)
- RETURN(rc);
- lmm_size = rc;
- rc = 0;
-
- /* FIXME: Bug 1185 - copy fields properly when structs change */
- LASSERT(sizeof(lum) == sizeof(*lmmk));
- LASSERT(sizeof(lum.lmm_objects[0]) == sizeof(lmmk->lmm_objects[0]));
-
- /* User wasn't expecting this many OST entries */
- if (lum.lmm_stripe_count == 0) {
- if (copy_to_user(lump, lmmk, sizeof(lum)))
- rc = -EFAULT;
- } else if (lum.lmm_stripe_count < lmmk->lmm_stripe_count) {
- rc = -EOVERFLOW;
- } else if (copy_to_user(lump, lmmk, lmm_size)) {
- rc = -EFAULT;
- }
-
- obd_free_diskmd(exp, &lmmk);
-
- RETURN(rc);
+ /* 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);