+ EXIT;
+out_child:
+ if (child)
+ mdt_object_put(info->mti_env, child);
+unlock_parent:
+ if (lhp)
+ mdt_object_unlock(info, parent, lhp, 1);
+ if (rc == -ENOENT) {
+ /* return -ENOKEY instead of -ENOENT to encryption-unaware
+ * client if trying to access an encrypted file
+ */
+ int rc2 = mdt_check_enc(info, parent);
+
+ if (rc2)
+ rc = rc2;
+ }
+ return rc;
+}
+
+/* normal handler: should release the child lock */
+static int mdt_getattr_name(struct tgt_session_info *tsi)
+{
+ struct mdt_thread_info *info = tsi2mdt_info(tsi);
+ struct mdt_lock_handle *lhc = &info->mti_lh[MDT_LH_CHILD];
+ struct mdt_body *reqbody;
+ struct mdt_body *repbody;
+ int rc, rc2;
+
+ ENTRY;
+
+ reqbody = req_capsule_client_get(info->mti_pill, &RMF_MDT_BODY);
+ LASSERT(reqbody != NULL);
+ repbody = req_capsule_server_get(info->mti_pill, &RMF_MDT_BODY);
+ LASSERT(repbody != NULL);
+
+ info->mti_cross_ref = !!(reqbody->mbo_valid & OBD_MD_FLCROSSREF);
+ repbody->mbo_eadatasize = 0;
+ repbody->mbo_aclsize = 0;
+
+ rc = mdt_init_ucred(info, reqbody);
+ if (unlikely(rc))
+ GOTO(out_shrink, rc);
+
+ rc = mdt_getattr_name_lock(info, lhc, MDS_INODELOCK_UPDATE, NULL);
+ if (lustre_handle_is_used(&lhc->mlh_reg_lh)) {
+ ldlm_lock_decref(&lhc->mlh_reg_lh, lhc->mlh_reg_mode);
+ lhc->mlh_reg_lh.cookie = 0;
+ }
+ mdt_exit_ucred(info);
+ EXIT;
+out_shrink:
+ mdt_client_compatibility(info);
+ rc2 = mdt_fix_reply(info);
+ if (rc == 0)
+ rc = rc2;
+ mdt_thread_info_fini(info);
+ return rc;
+}
+
+static int mdt_rmfid_unlink(struct mdt_thread_info *info,
+ const struct lu_fid *pfid,
+ const struct lu_name *name,
+ struct mdt_object *obj, s64 ctime)
+{
+ struct lu_fid *child_fid = &info->mti_tmp_fid1;
+ struct ldlm_enqueue_info *einfo = &info->mti_einfo[0];
+ struct mdt_device *mdt = info->mti_mdt;
+ struct md_attr *ma = &info->mti_attr;
+ struct mdt_lock_handle *parent_lh;
+ struct mdt_lock_handle *child_lh;
+ struct mdt_object *pobj;
+ bool cos_incompat = false;
+ int rc;
+ ENTRY;
+
+ pobj = mdt_object_find(info->mti_env, mdt, pfid);
+ if (IS_ERR(pobj))
+ GOTO(out, rc = PTR_ERR(pobj));
+
+ parent_lh = &info->mti_lh[MDT_LH_PARENT];
+ mdt_lock_pdo_init(parent_lh, LCK_PW, name);
+ rc = mdt_object_lock(info, pobj, parent_lh, MDS_INODELOCK_UPDATE);
+ if (rc != 0)
+ GOTO(put_parent, rc);
+
+ if (mdt_object_remote(pobj))
+ cos_incompat = true;
+
+ rc = mdo_lookup(info->mti_env, mdt_object_child(pobj),
+ name, child_fid, &info->mti_spec);
+ if (rc != 0)
+ GOTO(unlock_parent, rc);
+
+ if (!lu_fid_eq(child_fid, mdt_object_fid(obj)))
+ GOTO(unlock_parent, rc = -EREMCHG);
+
+ child_lh = &info->mti_lh[MDT_LH_CHILD];
+ mdt_lock_reg_init(child_lh, LCK_EX);
+ rc = mdt_reint_striped_lock(info, obj, child_lh,
+ MDS_INODELOCK_LOOKUP | MDS_INODELOCK_UPDATE,
+ einfo, cos_incompat);
+ if (rc != 0)
+ GOTO(unlock_parent, rc);
+
+ if (atomic_read(&obj->mot_open_count)) {
+ CDEBUG(D_OTHER, "object "DFID" open, skip\n",
+ PFID(mdt_object_fid(obj)));
+ GOTO(unlock_child, rc = -EBUSY);
+ }
+
+ ma->ma_need = 0;
+ ma->ma_valid = MA_INODE;
+ ma->ma_attr.la_valid = LA_CTIME;
+ ma->ma_attr.la_ctime = ctime;
+
+ mutex_lock(&obj->mot_lov_mutex);
+
+ rc = mdo_unlink(info->mti_env, mdt_object_child(pobj),
+ mdt_object_child(obj), name, ma, 0);
+
+ mutex_unlock(&obj->mot_lov_mutex);
+
+unlock_child:
+ mdt_reint_striped_unlock(info, obj, child_lh, einfo, 1);
+unlock_parent:
+ mdt_object_unlock(info, pobj, parent_lh, 1);
+put_parent:
+ mdt_object_put(info->mti_env, pobj);
+out:
+ RETURN(rc);
+}
+
+static int mdt_rmfid_check_permission(struct mdt_thread_info *info,
+ struct mdt_object *obj)
+{
+ struct lu_ucred *uc = lu_ucred(info->mti_env);
+ struct md_attr *ma = &info->mti_attr;
+ struct lu_attr *la = &ma->ma_attr;
+ int rc = 0;
+ ENTRY;
+
+ ma->ma_need = MA_INODE;
+ rc = mo_attr_get(info->mti_env, mdt_object_child(obj), ma);
+ if (rc)
+ GOTO(out, rc);
+
+ if (la->la_flags & LUSTRE_IMMUTABLE_FL)
+ rc = -EACCES;
+
+ if (cap_raised(uc->uc_cap, CAP_DAC_OVERRIDE))
+ RETURN(0);
+ if (uc->uc_fsuid == la->la_uid) {
+ if ((la->la_mode & S_IWUSR) == 0)
+ rc = -EACCES;
+ } else if (uc->uc_fsgid == la->la_gid) {
+ if ((la->la_mode & S_IWGRP) == 0)
+ rc = -EACCES;
+ } else if ((la->la_mode & S_IWOTH) == 0) {
+ rc = -EACCES;
+ }
+
+out:
+ RETURN(rc);
+}
+
+static int mdt_rmfid_one(struct mdt_thread_info *info, struct lu_fid *fid,
+ s64 ctime)
+{
+ struct mdt_device *mdt = info->mti_mdt;
+ struct mdt_object *obj = NULL;
+ struct linkea_data ldata = { NULL };
+ struct lu_buf *buf = &info->mti_big_buf;
+ struct lu_name *name = &info->mti_name;
+ struct lu_fid *pfid = &info->mti_tmp_fid1;
+ struct link_ea_header *leh;
+ struct link_ea_entry *lee;
+ int reclen, count, rc = 0;
+ ENTRY;
+
+ if (!fid_is_sane(fid))
+ GOTO(out, rc = -EINVAL);
+
+ if (!fid_is_namespace_visible(fid))
+ GOTO(out, rc = -EINVAL);
+
+ obj = mdt_object_find(info->mti_env, mdt, fid);
+ if (IS_ERR(obj))
+ GOTO(out, rc = PTR_ERR(obj));
+
+ if (mdt_object_remote(obj))
+ GOTO(out, rc = -EREMOTE);
+ if (!mdt_object_exists(obj) || lu_object_is_dying(&obj->mot_header))
+ GOTO(out, rc = -ENOENT);
+
+ rc = mdt_rmfid_check_permission(info, obj);
+ if (rc)
+ GOTO(out, rc);
+
+ /* take LinkEA */
+ buf = lu_buf_check_and_alloc(buf, PATH_MAX);
+ if (!buf->lb_buf)
+ GOTO(out, rc = -ENOMEM);
+
+ ldata.ld_buf = buf;
+ rc = mdt_links_read(info, obj, &ldata);
+ if (rc)
+ GOTO(out, rc);
+
+ leh = buf->lb_buf;
+ lee = (struct link_ea_entry *)(leh + 1);
+ for (count = 0; count < leh->leh_reccount; count++) {
+ /* remove every hardlink */
+ linkea_entry_unpack(lee, &reclen, name, pfid);
+ lee = (struct link_ea_entry *) ((char *)lee + reclen);
+ rc = mdt_rmfid_unlink(info, pfid, name, obj, ctime);
+ if (rc)
+ break;
+ }
+
+out:
+ if (obj && !IS_ERR(obj))
+ mdt_object_put(info->mti_env, obj);
+ if (info->mti_big_buf.lb_buf)
+ lu_buf_free(&info->mti_big_buf);
+
+ RETURN(rc);
+}
+
+static int mdt_rmfid(struct tgt_session_info *tsi)
+{
+ struct mdt_thread_info *mti = tsi2mdt_info(tsi);
+ struct mdt_body *reqbody;
+ struct lu_fid *fids, *rfids;
+ int bufsize, rc;
+ __u32 *rcs;
+ int i, nr;
+ ENTRY;
+
+ reqbody = req_capsule_client_get(tsi->tsi_pill, &RMF_MDT_BODY);
+ if (reqbody == NULL)
+ RETURN(-EPROTO);
+ bufsize = req_capsule_get_size(tsi->tsi_pill, &RMF_FID_ARRAY,
+ RCL_CLIENT);
+ nr = bufsize / sizeof(struct lu_fid);
+ if (nr * sizeof(struct lu_fid) != bufsize)
+ RETURN(-EINVAL);
+ req_capsule_set_size(tsi->tsi_pill, &RMF_RCS,
+ RCL_SERVER, nr * sizeof(__u32));
+ req_capsule_set_size(tsi->tsi_pill, &RMF_FID_ARRAY,
+ RCL_SERVER, nr * sizeof(struct lu_fid));
+ rc = req_capsule_server_pack(tsi->tsi_pill);
+ if (rc)
+ GOTO(out, rc = err_serious(rc));
+ fids = req_capsule_client_get(tsi->tsi_pill, &RMF_FID_ARRAY);
+ if (fids == NULL)
+ RETURN(-EPROTO);
+ rcs = req_capsule_server_get(tsi->tsi_pill, &RMF_RCS);
+ LASSERT(rcs);
+ rfids = req_capsule_server_get(tsi->tsi_pill, &RMF_FID_ARRAY);
+ LASSERT(rfids);
+
+ mdt_init_ucred(mti, reqbody);
+ for (i = 0; i < nr; i++) {
+ rfids[i] = fids[i];
+ rcs[i] = mdt_rmfid_one(mti, fids + i, reqbody->mbo_ctime);
+ }
+ mdt_exit_ucred(mti);
+
+out:
+ RETURN(rc);
+}
+
+static int mdt_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
+ void *karg, void __user *uarg);
+
+int mdt_io_set_info(struct tgt_session_info *tsi)
+{
+ struct ptlrpc_request *req = tgt_ses_req(tsi);
+ struct ost_body *body = NULL, *repbody;
+ void *key, *val = NULL;
+ int keylen, vallen, rc = 0;
+ bool is_grant_shrink;
+
+ ENTRY;
+
+ key = req_capsule_client_get(tsi->tsi_pill, &RMF_SETINFO_KEY);
+ if (key == NULL) {
+ DEBUG_REQ(D_HA, req, "no set_info key");
+ RETURN(err_serious(-EFAULT));
+ }
+ keylen = req_capsule_get_size(tsi->tsi_pill, &RMF_SETINFO_KEY,
+ RCL_CLIENT);
+
+ val = req_capsule_client_get(tsi->tsi_pill, &RMF_SETINFO_VAL);
+ if (val == NULL) {
+ DEBUG_REQ(D_HA, req, "no set_info val");
+ RETURN(err_serious(-EFAULT));
+ }
+ vallen = req_capsule_get_size(tsi->tsi_pill, &RMF_SETINFO_VAL,
+ RCL_CLIENT);