+ MDT_HSM_FREE(hal, hal_size);
+out_ucred:
+ mdt_exit_ucred(info);
+out:
+ mdt_thread_info_fini(info);
+ return rc;
+}
+
+/* Return true if a FID is present in an action list. */
+static bool is_fid_in_hal(struct hsm_action_list *hal, const lustre_fid *fid)
+{
+ struct hsm_action_item *hai;
+ int i;
+
+ for (hai = hai_first(hal), i = 0;
+ i < hal->hal_count;
+ i++, hai = hai_next(hai)) {
+ if (lu_fid_eq(&hai->hai_fid, fid))
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Process the HSM actions described in a struct hsm_user_request.
+ *
+ * The action described in hur will be send to coordinator to be saved and
+ * processed later or either handled directly if hur.hur_action is HUA_RELEASE.
+ *
+ * This is MDS_HSM_REQUEST RPC handler.
+ */
+int mdt_hsm_request(struct tgt_session_info *tsi)
+{
+ struct mdt_thread_info *info;
+ struct req_capsule *pill = tsi->tsi_pill;
+ struct hsm_request *hr;
+ struct hsm_user_item *hui;
+ struct hsm_action_list *hal;
+ struct hsm_action_item *hai;
+ const void *data;
+ int hui_list_size;
+ int data_size;
+ enum hsm_copytool_action action = HSMA_NONE;
+ int hal_size, i, rc;
+ ENTRY;
+
+ hr = req_capsule_client_get(pill, &RMF_MDS_HSM_REQUEST);
+ hui = req_capsule_client_get(pill, &RMF_MDS_HSM_USER_ITEM);
+ data = req_capsule_client_get(pill, &RMF_GENERIC_DATA);
+
+ if (tsi->tsi_mdt_body == NULL || hr == NULL || hui == NULL || data == NULL)
+ RETURN(-EPROTO);
+
+ /* Sanity check. Nothing to do with an empty list */
+ if (hr->hr_itemcount == 0)
+ RETURN(0);
+
+ hui_list_size = req_capsule_get_size(pill, &RMF_MDS_HSM_USER_ITEM,
+ RCL_CLIENT);
+ if (hui_list_size < hr->hr_itemcount * sizeof(*hui))
+ RETURN(-EPROTO);
+
+ data_size = req_capsule_get_size(pill, &RMF_GENERIC_DATA, RCL_CLIENT);
+ if (data_size != hr->hr_data_len)
+ RETURN(-EPROTO);
+
+ info = tsi2mdt_info(tsi);
+ /* Only valid if client is remote */
+ rc = mdt_init_ucred(info, (struct mdt_body *)info->mti_body);
+ if (rc)
+ GOTO(out, rc);
+
+ switch (hr->hr_action) {
+ /* code to be removed in hsm1_merge and final patch */
+ case HUA_RELEASE:
+ CERROR("Release action is not working in hsm1_coord\n");
+ GOTO(out_ucred, rc = -EINVAL);
+ break;
+ /* end of code to be removed */
+ case HUA_ARCHIVE:
+ action = HSMA_ARCHIVE;
+ break;
+ case HUA_RESTORE:
+ action = HSMA_RESTORE;
+ break;
+ case HUA_REMOVE:
+ action = HSMA_REMOVE;
+ break;
+ case HUA_CANCEL:
+ action = HSMA_CANCEL;
+ break;
+ default:
+ CERROR("Unknown hsm action: %d\n", hr->hr_action);
+ GOTO(out_ucred, rc = -EINVAL);
+ }
+
+ hal_size = sizeof(*hal) + cfs_size_round(MTI_NAME_MAXLEN) /* fsname */ +
+ (sizeof(*hai) + cfs_size_round(hr->hr_data_len)) *
+ hr->hr_itemcount;
+
+ MDT_HSM_ALLOC(hal, hal_size);
+ if (hal == NULL)
+ GOTO(out_ucred, rc = -ENOMEM);
+
+ hal->hal_version = HAL_VERSION;
+ hal->hal_archive_id = hr->hr_archive_id;
+ hal->hal_flags = hr->hr_flags;
+ obd_uuid2fsname(hal->hal_fsname, mdt_obd_name(info->mti_mdt),
+ MTI_NAME_MAXLEN);
+
+ hal->hal_count = 0;
+ hai = hai_first(hal);
+ for (i = 0; i < hr->hr_itemcount; i++, hai = hai_next(hai)) {
+ /* Get rid of duplicate entries. Otherwise we get
+ * duplicated work in the llog. */
+ if (is_fid_in_hal(hal, &hui[i].hui_fid))
+ continue;
+
+ hai->hai_action = action;
+ hai->hai_cookie = 0;
+ hai->hai_gid = 0;
+ hai->hai_fid = hui[i].hui_fid;
+ hai->hai_extent = hui[i].hui_extent;
+ memcpy(hai->hai_data, data, hr->hr_data_len);
+ hai->hai_len = sizeof(*hai) + hr->hr_data_len;
+
+ hal->hal_count++;
+ }
+
+ rc = mdt_hsm_add_actions(info, hal);
+
+ MDT_HSM_FREE(hal, hal_size);
+
+ GOTO(out_ucred, rc);
+