Whamcloud - gitweb
LU-11367 som: integrate LSOM with lfs find
[fs/lustre-release.git] / lustre / mdt / mdt_som.c
index ed47a53..ccd80ee 100644 (file)
  * Size on MDS revival
  *
  * Author: Jinshan Xiong <jinshan.xiong@intel.com>
+ * Author: Yingjin Qian <qian@ddn.com>
  */
 
 #define DEBUG_SUBSYSTEM S_MDS
 
 #include "mdt_internal.h"
 
+/*
+ * Swab and extract SOM attributes from on-disk xattr.
+ *
+ * \param buf - is a buffer containing the on-disk LSOM extended attribute.
+ * \param rc  - is the SOM xattr stored in \a buf
+ * \param ms  - is the md_som structure where to extract SOM attributes.
+ */
+int lustre_buf2som(void *buf, int rc, struct md_som *ms)
+{
+       struct lustre_som_attrs *attrs = (struct lustre_som_attrs *)buf;
+       ENTRY;
+
+       if (rc == 0 || rc == -ENODATA)
+               /* no LSOM attributes */
+               RETURN(-ENODATA);
+
+       if (rc < 0)
+               /* error hit while fetching xattr */
+               RETURN(rc);
+
+       /* unpack LSOM attributes */
+       lustre_som_swab(attrs);
+
+       /* fill in-memory md_som structure */
+       ms->ms_valid = attrs->lsa_valid;
+       ms->ms_size = attrs->lsa_size;
+       ms->ms_blocks = attrs->lsa_blocks;
+
+       RETURN(0);
+}
+
 int mdt_get_som(struct mdt_thread_info *info, struct mdt_object *obj,
-               struct lu_attr *attr)
+               struct md_attr *ma)
 {
        struct lu_buf *buf = &info->mti_buf;
-       struct lustre_som_attrs *som;
+       struct lu_attr *attr = &ma->ma_attr;
        int rc;
 
-       som = buf->lb_buf = info->mti_xattr_buf;
+       buf->lb_buf = info->mti_xattr_buf;
        buf->lb_len = sizeof(info->mti_xattr_buf);
+       CLASSERT(sizeof(struct lustre_som_attrs) <=
+                sizeof(info->mti_xattr_buf));
        rc = mo_xattr_get(info->mti_env, mdt_object_child(obj), buf,
                          XATTR_NAME_SOM);
-       if (rc >= (int)sizeof(*som) && (som->lsa_valid & LSOM_FL_VALID)) {
-               attr->la_valid |= LA_SIZE | LA_BLOCKS;
-               attr->la_size = som->lsa_size;
-               attr->la_blocks = som->lsa_blocks;
+       rc = lustre_buf2som(info->mti_xattr_buf, rc, &ma->ma_som);
+       if (rc == 0) {
+               struct md_som *som = &ma->ma_som;
 
-               /* Size on MDS is valid and could be returned to client */
-               info->mti_som_valid = 1;
+               ma->ma_valid |= MA_SOM;
 
                CDEBUG(D_INODE, DFID": Reading som attrs: "
-                      "valid: %x, size: %lld, blocks: %lld, rc: %d.\n",
-                      PFID(mdt_object_fid(obj)), som->lsa_valid,
-                      som->lsa_size, som->lsa_blocks, rc);
+                      "valid: %x, size: %lld, blocks: %lld\n",
+                      PFID(mdt_object_fid(obj)), som->ms_valid,
+                      som->ms_size, som->ms_blocks);
+
+               if (som->ms_valid & SOM_FL_STRICT) {
+                       attr->la_valid |= LA_SIZE | LA_BLOCKS;
+
+                       /*
+                        * Size on MDS is valid and could be returned
+                        * to client.
+                        */
+                       attr->la_size = som->ms_size;
+                       attr->la_blocks = som->ms_blocks;
+                       info->mti_som_valid = 1;
+               }
+       } else if (rc == -ENODATA) {
+               rc = 0;
        }
 
-       return (rc > 0 || rc == -ENODATA) ? 0 : rc;
+       return rc;
 }
 
+/**
+ * Update SOM on-disk attributes.
+ */
 int mdt_set_som(struct mdt_thread_info *info, struct mdt_object *obj,
-               struct lu_attr *attr)
+               enum lustre_som_flags flag, __u64 size, __u64 blocks)
 {
        struct md_object *next = mdt_object_child(obj);
        struct lu_buf *buf = &info->mti_buf;
        struct lustre_som_attrs *som;
        int rc;
+
        ENTRY;
 
-       buf->lb_buf = info->mti_xattr_buf;
-       buf->lb_len = sizeof(info->mti_xattr_buf);
-       rc = mo_xattr_get(info->mti_env, next, buf, XATTR_NAME_SOM);
-       if (rc < 0 && rc != -ENODATA)
-               RETURN(rc);
+       CDEBUG(D_INODE,
+              DFID": Set SOM attrs S/B/F: %lld/%lld/%x.\n",
+              PFID(mdt_object_fid(obj)), size, blocks, flag);
 
-       som = buf->lb_buf;
+       som = (struct lustre_som_attrs *)info->mti_xattr_buf;
+       CLASSERT(sizeof(info->mti_xattr_buf) >= sizeof(*som));
 
-       CDEBUG(D_INODE,
-              DFID": Set som attrs: S/B: %lld/%lld to %lld/%lld, rc: %d\n",
-              PFID(mdt_object_fid(obj)), som->lsa_size, som->lsa_blocks,
-              attr->la_size, attr->la_blocks, rc);
-
-       if (rc == -ENODATA)
-               memset(som, 0, sizeof(*som));
-       if (attr->la_valid & (LA_SIZE | LA_BLOCKS)) {
-               som->lsa_valid |= LSOM_FL_VALID;
-               som->lsa_size = attr->la_size;
-               som->lsa_blocks = attr->la_blocks;
-       }
+       som->lsa_valid = flag;
+       som->lsa_size = size;
+       som->lsa_blocks = blocks;
+       memset(&som->lsa_reserved, 0, sizeof(som->lsa_reserved));
+       lustre_som_swab(som);
+
+       /* update SOM attributes */
+       buf->lb_buf = som;
        buf->lb_len = sizeof(*som);
        rc = mo_xattr_set(info->mti_env, next, buf, XATTR_NAME_SOM, 0);
+
+       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);
        RETURN(rc);
 }