+}
+
+static int llu_lov_dir_setstripe(struct inode *ino, unsigned long arg)
+{
+ struct llu_sb_info *sbi = llu_i2sbi(ino);
+ struct ptlrpc_request *request = NULL;
+ struct md_op_data op_data = {{ 0 }};
+ struct lov_user_md lum, *lump = (struct lov_user_md *)arg;
+ int rc = 0;
+
+ llu_prep_md_op_data(&op_data, ino, NULL, NULL, 0, 0,
+ LUSTRE_OPC_ANY);
+
+ LASSERT(sizeof(lum) == sizeof(*lump));
+ LASSERT(sizeof(lum.lmm_objects[0]) ==
+ sizeof(lump->lmm_objects[0]));
+ if (copy_from_user(&lum, lump, sizeof(lum)))
+ return(-EFAULT);
+
+ switch (lum.lmm_magic) {
+ case LOV_USER_MAGIC_V1: {
+ if (lum.lmm_magic != cpu_to_le32(LOV_USER_MAGIC_V1))
+ lustre_swab_lov_user_md_v1(&lum);
+ break;
+ }
+ case LOV_USER_MAGIC_V3: {
+ if (lum.lmm_magic != cpu_to_le32(LOV_USER_MAGIC_V3))
+ lustre_swab_lov_user_md_v3((struct lov_user_md_v3 *)&lum);
+ break;
+ }
+ default: {
+ CDEBUG(D_IOCTL, "bad userland LOV MAGIC:"
+ " %#08x != %#08x nor %#08x\n",
+ lum.lmm_magic, LOV_USER_MAGIC_V1,
+ LOV_USER_MAGIC_V3);
+ RETURN(-EINVAL);
+ }
+ }
+
+ /* swabbing is done in lov_setstripe() on server side */
+ rc = md_setattr(sbi->ll_md_exp, &op_data, &lum,
+ sizeof(lum), NULL, 0, &request, NULL);
+ if (rc) {
+ ptlrpc_req_finished(request);
+ if (rc != -EPERM && rc != -EACCES)
+ CERROR("md_setattr fails: rc = %d\n", rc);
+ return rc;
+ }
+ ptlrpc_req_finished(request);
+
+ return rc;
+}
+
+static int llu_lov_setstripe_ea_info(struct inode *ino, int flags,
+ struct lov_user_md *lum, int lum_size)
+{
+ struct llu_sb_info *sbi = llu_i2sbi(ino);
+ struct llu_inode_info *lli = llu_i2info(ino);
+ struct lookup_intent oit = {.it_op = IT_OPEN, .it_flags = flags};
+ struct ldlm_enqueue_info einfo = {
+ .ei_type = LDLM_IBITS,
+ .ei_mode = LCK_CR,
+ .ei_cb_bl = llu_md_blocking_ast,
+ .ei_cb_cp = ldlm_completion_ast,
+ };
+ struct ptlrpc_request *req = NULL;
+ struct lustre_md md;
+ struct md_op_data data = {{ 0 }};
+ struct lustre_handle lockh;
+ int rc = 0;
+ ENTRY;
+
+ if (lli->lli_has_smd) {
+ CDEBUG(D_IOCTL, "stripe already exists for ino "DFID"\n",
+ PFID(&lli->lli_fid));
+ return -EEXIST;
+ }
+
+ llu_prep_md_op_data(&data, NULL, ino, NULL, 0, O_RDWR,
+ LUSTRE_OPC_ANY);
+ rc = md_enqueue(sbi->ll_md_exp, &einfo, &oit, &data,
+ &lockh, lum, lum_size, NULL, LDLM_FL_INTENT_ONLY);
+ if (rc)
+ GOTO(out, rc);
+
+ req = oit.d.lustre.it_data;
+ rc = it_open_error(DISP_IT_EXECD, &oit);
+ if (rc) {
+ req->rq_replay = 0;
+ GOTO(out, rc);
+ }
+
+ rc = it_open_error(DISP_OPEN_OPEN, &oit);
+ if (rc) {
+ req->rq_replay = 0;
+ GOTO(out, rc);
+ }
+
+ rc = md_get_lustre_md(sbi->ll_md_exp, req,
+ sbi->ll_dt_exp, sbi->ll_md_exp, &md);
+ if (rc)
+ GOTO(out, rc);
+
+ llu_update_inode(ino, &md);
+ llu_local_open(lli, &oit);
+ /* release intent */
+ if (lustre_handle_is_used(&lockh))
+ ldlm_lock_decref(&lockh, LCK_CR);
+ ptlrpc_req_finished(req);
+ req = NULL;
+ rc = llu_file_release(ino);
+ EXIT;
+
+out:
+ if (req != NULL)
+ ptlrpc_req_finished(req);
+ return rc;
+}
+
+static int llu_lov_file_setstripe(struct inode *ino, unsigned long arg)
+{
+ struct lov_user_md lum, *lump = (struct lov_user_md *)arg;
+ int rc;
+ int flags = FMODE_WRITE;
+ ENTRY;
+
+ LASSERT(sizeof(lum) == sizeof(*lump));
+ LASSERT(sizeof(lum.lmm_objects[0]) == sizeof(lump->lmm_objects[0]));
+ if (copy_from_user(&lum, lump, sizeof(lum)))
+ RETURN(-EFAULT);
+
+ rc = llu_lov_setstripe_ea_info(ino, flags, &lum, sizeof(lum));
+ RETURN(rc);
+}
+
+static int llu_lov_setstripe(struct inode *ino, unsigned long arg)
+{
+ struct intnl_stat *st = llu_i2stat(ino);
+ if (S_ISREG(st->st_mode))
+ return llu_lov_file_setstripe(ino, arg);
+ if (S_ISDIR(st->st_mode))
+ return llu_lov_dir_setstripe(ino, arg);
+
+ return -EINVAL;
+}
+
+static int llu_lov_getstripe(struct inode *ino, unsigned long arg)
+{
+ struct lov_stripe_md *lsm = NULL;
+ int rc = -ENODATA;
+
+ lsm = ccc_inode_lsm_get(ino);
+ if (lsm != NULL)
+ rc = obd_iocontrol(LL_IOC_LOV_GETSTRIPE, llu_i2obdexp(ino), 0, lsm,
+ (void *)arg);
+ ccc_inode_lsm_put(ino, lsm);
+ return rc;
+}