+ EXIT;
+error_up:
+ up(&o->mot_ioepoch_sem);
+ return rc ? : ret;
+}
+
+/**
+ * Close IOEpoch (opened file or FMODE_EPOCH state). It happens if:
+ * - a client closes the IOEpoch;
+ * - a client eviction occured.
+ * Return values:
+ * MDT_IOEPOCH_OPENED if the client does not close IOEpoch.
+ * MDT_IOEPOCH_CLOSED if the client closes IOEpoch.
+ * MDT_IOEPOCH_GETATTR if the client closes IOEpoch but another SOM attribute
+ * update is needed.
+ */
+static int mdt_ioepoch_close(struct mdt_thread_info *info, struct mdt_object *o)
+{
+ struct ptlrpc_request *req = mdt_info_req(info);
+ ENTRY;
+
+ if (!(mdt_conn_flags(info) & OBD_CONNECT_SOM) ||
+ !S_ISREG(lu_object_attr(&o->mot_obj.mo_lu)))
+ RETURN(0);
+
+ LASSERT(o->mot_ioepoch_count);
+ LASSERT(info->mti_ioepoch == NULL ||
+ info->mti_ioepoch->ioepoch == o->mot_ioepoch);
+
+ /* IOEpoch is closed only if client tells about it or eviction occures.
+ * In the replay case, always close the epoch. */
+ if (req == NULL)
+ RETURN(mdt_ioepoch_close_on_eviction(info, o));
+ if (lustre_msg_get_flags(req->rq_reqmsg) & MSG_REPLAY)
+ RETURN(mdt_ioepoch_close_on_replay(info, o));
+ if (info->mti_ioepoch->flags & MF_EPOCH_CLOSE)
+ RETURN(mdt_ioepoch_close_reg(info, o));
+ /* IO epoch is not closed. */
+ RETURN(MDT_IOEPOCH_OPENED);
+}
+
+/**
+ * Close FMODE_SOM state, when IOEpoch is already closed and we are waiting for
+ * attribute update. It happens if:
+ * - SOM Attribute Update is obtained;
+ * - the client failed to obtain it and informs MDS about it;
+ * - a client eviction occured.
+ * Apply obtained attributes for the 1st case, wipe out the on-disk SOM
+ * cache otherwise.
+ */
+int mdt_som_au_close(struct mdt_thread_info *info, struct mdt_object *o)
+{
+ struct ptlrpc_request *req = mdt_info_req(info);
+ __u64 ioepoch = 0;
+ int act = MDT_SOM_ENABLE;
+ int rc = 0;
+ ENTRY;
+
+ LASSERT(!req || info->mti_ioepoch);
+ if (!(mdt_conn_flags(info) & OBD_CONNECT_SOM) ||
+ !S_ISREG(lu_object_attr(&o->mot_obj.mo_lu)))
+ RETURN(0);
+
+ /* No size whereas MF_SOM_CHANGE is set means client failed to
+ * obtain ost attributes, drop the SOM cache on disk if so. */
+ if (!req ||
+ (info->mti_ioepoch &&
+ info->mti_ioepoch->flags & MF_SOM_CHANGE &&
+ !(info->mti_attr.ma_attr.la_valid & LA_SIZE)))
+ act = MDT_SOM_DISABLE;
+
+ down(&o->mot_ioepoch_sem);
+ /* Mark the object it is the recovery state if we failed to obtain
+ * SOM attributes. */
+ if (act == MDT_SOM_DISABLE)
+ o->mot_flags |= MOF_SOM_RECOV;
+
+ if (!mdt_ioepoch_opened(o)) {
+ ioepoch = info->mti_ioepoch ?
+ info->mti_ioepoch->ioepoch : o->mot_ioepoch;
+
+ if (!(lustre_msg_get_flags(req->rq_reqmsg) & MSG_REPLAY))
+ rc = mdt_som_attr_set(info, o, ioepoch, act);
+ mdt_object_som_enable(o, ioepoch);