+
+ RETURN(rc);
+}
+
+/**
+ * SOM state transition from STRICT to STALE,
+ */
+int mdt_lsom_downgrade(struct mdt_thread_info *info, struct mdt_object *o)
+{
+ struct md_attr *tmp_ma;
+ int rc;
+
+ ENTRY;
+
+ mutex_lock(&o->mot_som_mutex);
+ tmp_ma = &info->mti_u.som.attr;
+ tmp_ma->ma_need = MA_SOM;
+ tmp_ma->ma_valid = 0;
+
+ rc = mdt_get_som(info, o, tmp_ma);
+ if (rc < 0)
+ GOTO(out_lock, rc);
+
+ if (tmp_ma->ma_valid & MA_SOM) {
+ struct md_som *som = &tmp_ma->ma_som;
+
+ info->mti_som_valid = 0;
+ /* The size and blocks info should be still correct. */
+ if (som->ms_valid & SOM_FL_STRICT)
+ rc = mdt_set_som(info, o, SOM_FL_STALE,
+ som->ms_size, som->ms_blocks);
+ }
+out_lock:
+ mutex_unlock(&o->mot_som_mutex);
+ RETURN(rc);
+}
+
+int mdt_lsom_update(struct mdt_thread_info *info,
+ struct mdt_object *o, bool truncate)
+{
+ struct md_attr *ma, *tmp_ma;
+ struct lu_attr *la;
+ int rc = 0;
+
+ ENTRY;
+
+ ma = &info->mti_attr;
+ la = &ma->ma_attr;
+
+ mutex_lock(&o->mot_som_mutex);
+ tmp_ma = &info->mti_u.som.attr;
+ tmp_ma->ma_need = MA_INODE | MA_SOM;
+ tmp_ma->ma_valid = 0;
+
+ rc = mdt_attr_get_complex(info, o, tmp_ma);
+ if (rc)
+ GOTO(out_lock, rc);
+
+ /**
+ * If mti_big_lmm_used is set, it indicates that mti_big_lmm
+ * should contain valid LOV EA data, and can be used directly.
+ */
+ if (!info->mti_big_lmm_used) {
+ rc = mdt_big_xattr_get(info, o, XATTR_NAME_LOV);
+ if (rc < 0 && rc != -ENODATA)
+ GOTO(out_lock, rc);
+
+ /* No LOV EA */
+ if (rc == -ENODATA)
+ GOTO(out_lock, rc = 0);
+
+ rc = 0;
+ }
+
+ /**
+ * Check if a Lazy Size-on-MDS update is needed. Skip the
+ * file with no LOV EA, unlink files or DoM-only file.
+ * MDS only updates LSOM of the file if the size or block
+ * size is being increased or the file is being truncated.
+ */
+ if (mdt_lmm_dom_entry(info->mti_big_lmm) != LMM_DOM_ONLY &&
+ !(tmp_ma->ma_valid & MA_INODE && tmp_ma->ma_attr.la_nlink == 0)) {
+ __u64 size;
+ __u64 blocks;
+ bool changed = false;
+ struct md_som *som = &tmp_ma->ma_som;
+
+ if (truncate) {
+ size = la->la_size;
+ if (size == 0) {
+ blocks = 0;
+ } else if (!(tmp_ma->ma_valid & MA_SOM) ||
+ size < som->ms_size) {
+ /* We cannot rely to blocks after
+ * truncate especially for spare file,
+ * and the truncate operation is usually
+ * followed with a close, so just set blocks
+ * to 1 here, and the following close will
+ * update it accordingly.
+ */
+ blocks = 1;
+ } else {
+ blocks = som->ms_blocks;
+ }
+ } else {
+ if (!(tmp_ma->ma_valid & MA_SOM)) {
+ /* Only set initial SOM Xattr data when both
+ * size and blocks are valid.
+ */
+ if (la->la_valid & (LA_SIZE | LA_LSIZE) &&
+ la->la_valid & (LA_BLOCKS | LA_LBLOCKS)) {
+ changed = true;
+ size = la->la_size;
+ blocks = la->la_blocks;
+ }
+ } else {
+ /* Double check whether it is already set
+ * to SOM_FL_STRICT in mdt_mfd_close.
+ * If file is in SOM_FL_STALE state, and
+ * the close indicates there is no data
+ * modified, skip to transimit to LAZY
+ * state.
+ */
+ if (som->ms_valid & SOM_FL_STRICT ||
+ (som->ms_valid & SOM_FL_STALE &&
+ !(ma->ma_attr_flags & MDS_DATA_MODIFIED)))
+ GOTO(out_lock, rc);
+
+ size = som->ms_size;
+ blocks = som->ms_blocks;
+ if (la->la_valid & (LA_SIZE | LA_LSIZE) &&
+ la->la_size > som->ms_size) {
+ changed = true;
+ size = la->la_size;
+ }
+ if (la->la_valid & (LA_BLOCKS | LA_LBLOCKS) &&
+ la->la_blocks > som->ms_blocks) {
+ changed = true;
+ blocks = la->la_blocks;
+ }
+ }
+ }
+ if (truncate || changed)
+ rc = mdt_set_som(info, o, SOM_FL_LAZY, size, blocks);
+ }
+
+out_lock:
+ mutex_unlock(&o->mot_som_mutex);