+/*
+ * Compare current and future data of HSM EA and add a changelog if needed.
+ *
+ * Caller should have write-locked \param obj.
+ *
+ * \param buf - Future HSM EA content.
+ * \retval 0 if no changelog is needed or changelog was added properly.
+ * \retval -ve errno if there was a problem
+ */
+static int mdd_hsm_update_locked(const struct lu_env *env,
+ struct md_object *obj,
+ const struct lu_buf *buf,
+ struct thandle *handle)
+{
+ struct mdd_thread_info *info = mdd_env_info(env);
+ struct mdd_device *mdd = mdo2mdd(obj);
+ struct mdd_object *mdd_obj = md2mdd_obj(obj);
+ struct lu_buf *current_buf = &info->mti_buf;
+ struct md_hsm *current_mh;
+ struct md_hsm *new_mh;
+ int rc;
+ ENTRY;
+
+ OBD_ALLOC_PTR(current_mh);
+ if (current_mh == NULL)
+ RETURN(-ENOMEM);
+
+ /* Read HSM attrs from disk */
+ current_buf->lb_buf = info->mti_xattr_buf;
+ current_buf->lb_len = sizeof(info->mti_xattr_buf);
+ CLASSERT(sizeof(struct hsm_attrs) <= sizeof(info->mti_xattr_buf));
+ rc = mdo_xattr_get(env, mdd_obj, current_buf, XATTR_NAME_HSM,
+ mdd_object_capa(env, mdd_obj));
+ rc = lustre_buf2hsm(info->mti_xattr_buf, rc, current_mh);
+ if (rc < 0 && rc != -ENODATA)
+ GOTO(free, rc);
+ else if (rc == -ENODATA)
+ current_mh->mh_flags = 0;
+
+ /* Map future HSM xattr */
+ OBD_ALLOC_PTR(new_mh);
+ if (new_mh == NULL)
+ GOTO(free, rc = -ENOMEM);
+ lustre_buf2hsm(buf->lb_buf, buf->lb_len, new_mh);
+
+ /* If HSM flags are different, add a changelog */
+ rc = 0;
+ if (current_mh->mh_flags != new_mh->mh_flags) {
+ int flags = 0;
+ hsm_set_cl_event(&flags, HE_STATE);
+ if (new_mh->mh_flags & HS_DIRTY)
+ hsm_set_cl_flags(&flags, CLF_HSM_DIRTY);
+
+ rc = mdd_changelog_data_store(env, mdd, CL_HSM, flags, mdd_obj,
+ handle);
+ }
+
+ OBD_FREE_PTR(new_mh);
+free:
+ OBD_FREE_PTR(current_mh);
+ return(rc);
+}
+
+