return rc;
/* Only record user xattr changes */
- if ((strncmp("user.", name, 5) == 0))
+ if ((strncmp("user.", name, 5) == 0)) {
+ rc = mdd_declare_changelog_store(env, mdd, NULL, handle);
+ if (rc)
+ return rc;
+ }
+
+ /* If HSM data is modified, this could add a changelog */
+ if (strncmp(XATTR_NAME_HSM, name, sizeof(XATTR_NAME_HSM) - 1) == 0)
rc = mdd_declare_changelog_store(env, mdd, NULL, handle);
rc = mdd_declare_changelog_store(env, mdd, NULL, handle);
return rc;
}
+/*
+ * 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);
+}
+
+
/**
* The caller should guarantee to update the object ctime
* after xattr_set if needed.
handle->th_sync |= !!mdd->mdd_sync_permission;
mdd_write_lock(env, mdd_obj, MOR_TGT_CHILD);
+
+ if (strncmp(XATTR_NAME_HSM, name, sizeof(XATTR_NAME_HSM) - 1) == 0) {
+ rc = mdd_hsm_update_locked(env, obj, buf, handle);
+ if (rc) {
+ mdd_write_unlock(env, mdd_obj);
+ GOTO(stop, rc);
+ }
+ }
+
rc = mdo_xattr_set(env, mdd_obj, buf, name, fl, handle,
mdd_object_capa(env, mdd_obj));
mdd_write_unlock(env, mdd_obj);
ENTRY;
if (ma->ma_valid & MA_FLAGS && ma->ma_attr_flags & MDS_KEEP_ORPHAN) {
- mdd_obj->mod_count--;
+ mdd_write_lock(env, mdd_obj, MOR_TGT_CHILD);
+ mdd_obj->mod_count--;
+ mdd_write_unlock(env, mdd_obj);
if (mdd_obj->mod_flags & ORPHAN_OBJ && !mdd_obj->mod_count)
CDEBUG(D_HA, "Object "DFID" is retained in orphan "
RETURN(0);
}
- /* check without any lock */
- if (mdd_obj->mod_count == 1 &&
- (mdd_obj->mod_flags & (ORPHAN_OBJ | DEAD_OBJ)) != 0) {
- again:
+ /* mdd_finish_unlink() will always set orphan object as DEAD_OBJ, but
+ * it might fail to add the object to orphan list (w/o ORPHAN_OBJ). */
+ /* check without any lock */
+ is_orphan = mdd_obj->mod_count == 1 &&
+ (mdd_obj->mod_flags & (ORPHAN_OBJ | DEAD_OBJ)) != 0;
+
+again:
+ if (is_orphan) {
handle = mdd_trans_create(env, mdo2mdd(obj));
if (IS_ERR(handle))
RETURN(PTR_ERR(handle));
}
mdd_write_lock(env, mdd_obj, MOR_TGT_CHILD);
- if (handle == NULL && mdd_obj->mod_count == 1 &&
- (mdd_obj->mod_flags & ORPHAN_OBJ) != 0) {
- mdd_write_unlock(env, mdd_obj);
- goto again;
- }
-
- /* release open count */
- mdd_obj->mod_count --;
-
- if (mdd_obj->mod_count == 0 && mdd_obj->mod_flags & ORPHAN_OBJ) {
- /* remove link to object from orphan index */
- LASSERT(handle != NULL);
- rc = __mdd_orphan_del(env, mdd_obj, handle);
- if (rc == 0) {
- CDEBUG(D_HA, "Object "DFID" is deleted from orphan "
- "list, OSS objects to be destroyed.\n",
- PFID(mdd_object_fid(mdd_obj)));
- is_orphan = 1;
- } else {
- CERROR("Object "DFID" can not be deleted from orphan "
- "list, maybe cause OST objects can not be "
- "destroyed (err: %d).\n",
- PFID(mdd_object_fid(mdd_obj)), rc);
- /* If object was not deleted from orphan list, do not
- * destroy OSS objects, which will be done when next
- * recovery. */
- GOTO(out, rc);
- }
- }
-
rc = mdd_la_get(env, mdd_obj, &ma->ma_attr,
mdd_object_capa(env, mdd_obj));
- /* Object maybe not in orphan list originally, it is rare case for
- * mdd_finish_unlink() failure. */
- if (rc == 0 && (ma->ma_attr.la_nlink == 0 || is_orphan)) {
- if (handle == NULL) {
- handle = mdd_trans_create(env, mdo2mdd(obj));
- if (IS_ERR(handle))
- GOTO(out, rc = PTR_ERR(handle));
-
- rc = mdo_declare_destroy(env, mdd_obj, handle);
- if (rc)
- GOTO(out, rc);
+ if (rc != 0) {
+ CERROR("Failed to get lu_attr of "DFID": %d\n",
+ PFID(mdd_object_fid(mdd_obj)), rc);
+ GOTO(out, rc);
+ }
- rc = mdd_declare_changelog_store(env, mdd,
- NULL, handle);
- if (rc)
- GOTO(stop, rc);
+ /* check again with lock */
+ is_orphan = (mdd_obj->mod_count == 1) &&
+ ((mdd_obj->mod_flags & (ORPHAN_OBJ | DEAD_OBJ)) != 0 ||
+ ma->ma_attr.la_nlink == 0);
- rc = mdd_trans_start(env, mdo2mdd(obj), handle);
- if (rc)
- GOTO(out, rc);
+ if (is_orphan && handle == NULL) {
+ mdd_write_unlock(env, mdd_obj);
+ goto again;
+ }
+
+ mdd_obj->mod_count--; /*release open count */
+
+ if (!is_orphan)
+ GOTO(out, rc = 0);
+
+ /* Orphan object */
+ /* NB: Object maybe not in orphan list originally, it is rare case for
+ * mdd_finish_unlink() failure, in that case, the object doesn't have
+ * ORPHAN_OBJ flag */
+ if ((mdd_obj->mod_flags & ORPHAN_OBJ) != 0) {
+ /* remove link to object from orphan index */
+ LASSERT(handle != NULL);
+ rc = __mdd_orphan_del(env, mdd_obj, handle);
+ if (rc != 0) {
+ CERROR("%s: unable to delete "DFID" from orphan list: "
+ "rc = %d\n", lu_dev_name(mdd2lu_dev(mdd)),
+ PFID(mdd_object_fid(mdd_obj)), rc);
+ /* If object was not deleted from orphan list, do not
+ * destroy OSS objects, which will be done when next
+ * recovery. */
+ GOTO(out, rc);
}
- rc = mdo_destroy(env, mdd_obj, handle);
+ CDEBUG(D_HA, "Object "DFID" is deleted from orphan "
+ "list, OSS objects to be destroyed.\n",
+ PFID(mdd_object_fid(mdd_obj)));
+ }
+
+ rc = mdo_destroy(env, mdd_obj, handle);
- if (rc != 0)
- CERROR("Error when prepare to delete Object "DFID" , "
- "which will cause OST objects can not be "
- "destroyed.\n", PFID(mdd_object_fid(mdd_obj)));
- }
- EXIT;
+ if (rc != 0) {
+ CERROR("%s: unable to delete "DFID" from orphan list: "
+ "rc = %d\n", lu_dev_name(mdd2lu_dev(mdd)),
+ PFID(mdd_object_fid(mdd_obj)), rc);
+ }
+ EXIT;
out:
-
mdd_write_unlock(env, mdd_obj);
if (rc == 0 &&
if (result > 0)
/* end of directory */
dp->ldp_hash_end = cpu_to_le64(MDS_DIR_END_OFF);
- if (result < 0)
+ else if (result < 0)
CWARN("build page failed: %d!\n", result);
return result;
}