Whamcloud - gitweb
LU-12616 obclass: fix MDS start/stop race
[fs/lustre-release.git] / lustre / mdd / mdd_object.c
index a623314..a67cedc 100644 (file)
@@ -55,7 +55,7 @@ static const struct lu_object_operations mdd_lu_obj_ops;
 
 struct mdd_object_user {
        struct list_head        mou_list;       /**< linked off mod_users */
-       int                     mou_flags;      /**< open mode by client */
+       u64                     mou_open_flags; /**< open mode by client */
        __u64                   mou_uidgid;     /**< uid_gid on client */
        int                     mou_opencount;  /**< # opened */
        ktime_t                 mou_deniednext; /**< time of next access denied
@@ -70,28 +70,29 @@ static int mdd_xattr_get(const struct lu_env *env,
 static int mdd_changelog_data_store_by_fid(const struct lu_env *env,
                                           struct mdd_device *mdd,
                                           enum changelog_rec_type type,
-                                          int flags, const struct lu_fid *fid,
+                                          enum changelog_rec_flags clf_flags,
+                                          const struct lu_fid *fid,
                                           const char *xattr_name,
                                           struct thandle *handle);
 
 static inline bool has_prefix(const char *str, const char *prefix);
 
 
-static unsigned int flags_helper(int flags)
+static u32 flags_helper(u64 open_flags)
 {
-       unsigned int mflags = 0;
+       u32 open_mode = 0;
 
-       if (flags & MDS_FMODE_EXEC) {
-               mflags = MDS_FMODE_EXEC;
+       if (open_flags & MDS_FMODE_EXEC) {
+               open_mode = MDS_FMODE_EXEC;
        } else {
-               if (flags & MDS_FMODE_READ)
-                       mflags = MDS_FMODE_READ;
-               if (flags &
+               if (open_flags & MDS_FMODE_READ)
+                       open_mode = MDS_FMODE_READ;
+               if (open_flags &
                    (MDS_FMODE_WRITE | MDS_OPEN_TRUNC | MDS_OPEN_APPEND))
-                       mflags |= MDS_FMODE_WRITE;
+                       open_mode |= MDS_FMODE_WRITE;
        }
 
-       return mflags;
+       return open_mode;
 }
 
 /** Allocate/init a user and its sub-structures.
@@ -102,7 +103,7 @@ static unsigned int flags_helper(int flags)
  * \retval mou [OUT] success valid structure
  * \retval mou [OUT]
  */
-static struct mdd_object_user *mdd_obj_user_alloc(int flags,
+static struct mdd_object_user *mdd_obj_user_alloc(u64 open_flags,
                                                  uid_t uid, gid_t gid)
 {
        struct mdd_object_user *mou;
@@ -113,7 +114,7 @@ static struct mdd_object_user *mdd_obj_user_alloc(int flags,
        if (mou == NULL)
                RETURN(ERR_PTR(-ENOMEM));
 
-       mou->mou_flags = flags;
+       mou->mou_open_flags = open_flags;
        mou->mou_uidgid = ((__u64)uid << 32) | gid;
        mou->mou_opencount = 0;
        mou->mou_deniednext = ktime_set(0, 0);
@@ -142,7 +143,8 @@ static void mdd_obj_user_free(struct mdd_object_user *mou)
  */
 static
 struct mdd_object_user *mdd_obj_user_find(struct mdd_object *mdd_obj,
-                                         uid_t uid, gid_t gid, int flags)
+                                         uid_t uid, gid_t gid,
+                                         u64 open_flags)
 {
        struct mdd_object_user *mou;
        __u64 uidgid;
@@ -152,7 +154,8 @@ struct mdd_object_user *mdd_obj_user_find(struct mdd_object *mdd_obj,
        uidgid = ((__u64)uid << 32) | gid;
        list_for_each_entry(mou, &mdd_obj->mod_users, mou_list) {
                if (mou->mou_uidgid == uidgid &&
-                   flags_helper(mou->mou_flags) == flags_helper(flags))
+                   flags_helper(mou->mou_open_flags) ==
+                   flags_helper(open_flags))
                        RETURN(mou);
        }
        RETURN(NULL);
@@ -177,9 +180,7 @@ static int mdd_obj_user_add(struct mdd_object *mdd_obj,
        __u32 gid = mou->mou_uidgid & ((1UL << 32) - 1);
 
        ENTRY;
-
-       tmp = mdd_obj_user_find(mdd_obj, uid,
-                               gid, mou->mou_flags);
+       tmp = mdd_obj_user_find(mdd_obj, uid, gid, mou->mou_open_flags);
        if (tmp != NULL)
                RETURN(-EEXIST);
 
@@ -234,8 +235,7 @@ int mdd_la_get(const struct lu_env *env, struct mdd_object *obj,
                return rc;
        }
 
-       if (la->la_valid & LA_FLAGS &&
-           la->la_flags & LUSTRE_ORPHAN_FL)
+       if (la->la_valid & LA_FLAGS && la->la_flags & LUSTRE_ORPHAN_FL)
                obj->mod_flags |= ORPHAN_OBJ | DEAD_OBJ;
 
        return 0;
@@ -421,14 +421,14 @@ static int mdd_xattr_get(const struct lu_env *env,
                      strcmp(name, XATTR_NAME_LINK) == 0))
                RETURN(-ENOENT);
 
-       mdd_read_lock(env, mdd_obj, MOR_TGT_CHILD);
+       mdd_read_lock(env, mdd_obj, DT_TGT_CHILD);
        rc = mdo_xattr_get(env, mdd_obj, buf, name);
        mdd_read_unlock(env, mdd_obj);
 
        mdd = mdo2mdd(obj);
 
        /* record only getting user xattrs and acls */
-       if (rc >= 0 &&
+       if (rc >= 0 && buf->lb_buf &&
            mdd_changelog_enabled(env, mdd, CL_GETXATTR) &&
            (has_prefix(name, XATTR_USER_PREFIX) ||
             has_prefix(name, XATTR_NAME_POSIX_ACL_ACCESS) ||
@@ -487,7 +487,7 @@ int mdd_readlink(const struct lu_env *env, struct md_object *obj,
        LASSERT(next != NULL);
        LASSERT(next->do_body_ops != NULL);
        LASSERT(next->do_body_ops->dbo_read != NULL);
-       mdd_read_lock(env, mdd_obj, MOR_TGT_CHILD);
+       mdd_read_lock(env, mdd_obj, DT_TGT_CHILD);
        rc = dt_read(env, next, buf, &pos);
         mdd_read_unlock(env, mdd_obj);
         RETURN(rc);
@@ -504,7 +504,7 @@ static int mdd_xattr_list(const struct lu_env *env, struct md_object *obj,
 
         ENTRY;
 
-        mdd_read_lock(env, mdd_obj, MOR_TGT_CHILD);
+       mdd_read_lock(env, mdd_obj, DT_TGT_CHILD);
        rc = mdo_xattr_list(env, mdd_obj, buf);
         mdd_read_unlock(env, mdd_obj);
 
@@ -843,22 +843,23 @@ static int mdd_fix_attr(const struct lu_env *env, struct mdd_object *obj,
 static int mdd_changelog_data_store_by_fid(const struct lu_env *env,
                                           struct mdd_device *mdd,
                                           enum changelog_rec_type type,
-                                          int flags, const struct lu_fid *fid,
+                                          enum changelog_rec_flags clf_flags,
+                                          const struct lu_fid *fid,
                                           const char *xattr_name,
                                           struct thandle *handle)
 {
        const struct lu_ucred *uc = lu_ucred(env);
+       enum changelog_rec_extra_flags xflags = CLFE_INVALID;
        struct llog_changelog_rec *rec;
        struct lu_buf *buf;
        int reclen;
-       int xflags = CLFE_INVALID;
        int rc;
 
-       flags = (flags & CLF_FLAGMASK) | CLF_VERSION | CLF_EXTRA_FLAGS;
+       clf_flags = (clf_flags & CLF_FLAGMASK) | CLF_VERSION | CLF_EXTRA_FLAGS;
 
        if (uc) {
                if (uc->uc_jobid[0] != '\0')
-                       flags |= CLF_JOBID;
+                       clf_flags |= CLF_JOBID;
                xflags |= CLFE_UIDGID;
                xflags |= CLFE_NID;
        }
@@ -868,7 +869,7 @@ static int mdd_changelog_data_store_by_fid(const struct lu_env *env,
                xflags |= CLFE_XATTR;
 
        reclen = llog_data_len(LLOG_CHANGELOG_HDR_SZ +
-                              changelog_rec_offset(flags & CLF_SUPPORTED,
+                              changelog_rec_offset(clf_flags & CLF_SUPPORTED,
                                                    xflags & CLFE_SUPPORTED));
        buf = lu_buf_check_and_alloc(&mdd_env_info(env)->mti_big_buf, reclen);
        if (buf->lb_buf == NULL)
@@ -876,15 +877,15 @@ static int mdd_changelog_data_store_by_fid(const struct lu_env *env,
        rec = buf->lb_buf;
 
        rec->cr_hdr.lrh_len = reclen;
-       rec->cr.cr_flags = flags;
+       rec->cr.cr_flags = clf_flags;
        rec->cr.cr_type = (__u32)type;
        rec->cr.cr_tfid = *fid;
        rec->cr.cr_namelen = 0;
 
-       if (flags & CLF_JOBID)
+       if (clf_flags & CLF_JOBID)
                mdd_changelog_rec_ext_jobid(&rec->cr, uc->uc_jobid);
 
-       if (flags & CLF_EXTRA_FLAGS) {
+       if (clf_flags & CLF_EXTRA_FLAGS) {
                mdd_changelog_rec_ext_extra_flags(&rec->cr, xflags);
                if (xflags & CLFE_UIDGID)
                        mdd_changelog_rec_extra_uidgid(&rec->cr,
@@ -892,7 +893,7 @@ static int mdd_changelog_data_store_by_fid(const struct lu_env *env,
                if (xflags & CLFE_NID)
                        mdd_changelog_rec_extra_nid(&rec->cr, uc->uc_nid);
                if (xflags & CLFE_OPEN)
-                       mdd_changelog_rec_extra_omode(&rec->cr, flags);
+                       mdd_changelog_rec_extra_omode(&rec->cr, clf_flags);
                if (xflags & CLFE_XATTR) {
                        if (xattr_name == NULL)
                                RETURN(-EINVAL);
@@ -912,7 +913,8 @@ static int mdd_changelog_data_store_by_fid(const struct lu_env *env,
  * \param handle - transaction handle
  */
 int mdd_changelog_data_store(const struct lu_env *env, struct mdd_device *mdd,
-                            enum changelog_rec_type type, int flags,
+                            enum changelog_rec_type type,
+                            enum changelog_rec_flags clf_flags,
                             struct mdd_object *mdd_obj, struct thandle *handle)
 {
        int                              rc;
@@ -934,7 +936,7 @@ int mdd_changelog_data_store(const struct lu_env *env, struct mdd_device *mdd,
                RETURN(0);
        }
 
-       rc = mdd_changelog_data_store_by_fid(env, mdd, type, flags,
+       rc = mdd_changelog_data_store_by_fid(env, mdd, type, clf_flags,
                                             mdo2fid(mdd_obj), NULL, handle);
        if (rc == 0)
                mdd_obj->mod_cltime = ktime_get();
@@ -942,14 +944,15 @@ int mdd_changelog_data_store(const struct lu_env *env, struct mdd_device *mdd,
        RETURN(rc);
 }
 
-static int mdd_changelog_data_store_xattr(const struct lu_env *env,
-                                         struct mdd_device *mdd,
-                                         enum changelog_rec_type type,
-                                         int flags, struct mdd_object *mdd_obj,
-                                         const char *xattr_name,
-                                         struct thandle *handle)
+int mdd_changelog_data_store_xattr(const struct lu_env *env,
+                                  struct mdd_device *mdd,
+                                  enum changelog_rec_type type,
+                                  enum changelog_rec_flags clf_flags,
+                                  struct mdd_object *mdd_obj,
+                                  const char *xattr_name,
+                                  struct thandle *handle)
 {
-       int                              rc;
+       int rc;
 
        LASSERT(mdd_obj != NULL);
        LASSERT(handle != NULL);
@@ -969,7 +972,7 @@ static int mdd_changelog_data_store_xattr(const struct lu_env *env,
                RETURN(0);
        }
 
-       rc = mdd_changelog_data_store_by_fid(env, mdd, type, flags,
+       rc = mdd_changelog_data_store_by_fid(env, mdd, type, clf_flags,
                                             mdo2fid(mdd_obj), xattr_name,
                                             handle);
        if (rc == 0)
@@ -978,8 +981,11 @@ static int mdd_changelog_data_store_xattr(const struct lu_env *env,
        RETURN(rc);
 }
 
+/* only the bottom CLF_FLAGSHIFT bits of @flags are stored in the record,
+ * except for open flags have a dedicated record to store 32 bits of flags */
 static int mdd_changelog(const struct lu_env *env, enum changelog_rec_type type,
-                 int flags, struct md_device *m, const struct lu_fid *fid)
+                        enum changelog_rec_flags clf_flags,
+                        struct md_device *m, const struct lu_fid *fid)
 {
        struct thandle *handle;
        struct mdd_device *mdd = lu2mdd_dev(&m->md_lu_dev);
@@ -1005,7 +1011,7 @@ static int mdd_changelog(const struct lu_env *env, enum changelog_rec_type type,
        if (rc)
                GOTO(stop, rc);
 
-       rc = mdd_changelog_data_store_by_fid(env, mdd, type, flags,
+       rc = mdd_changelog_data_store_by_fid(env, mdd, type, clf_flags,
                                             fid, NULL, handle);
 
 stop:
@@ -1046,8 +1052,8 @@ static int mdd_attr_set_changelog(const struct lu_env *env,
        /* The record type is the lowest non-masked set bit */
        type = __ffs(bits);
 
-       /* FYI we only store the first CLF_FLAGMASK bits of la_valid */
-       return mdd_changelog_data_store(env, mdd, type, (int)valid,
+       /* XXX: we only store the low CLF_FLAGMASK bits of la_valid */
+       return mdd_changelog_data_store(env, mdd, type, valid,
                                        md2mdd_obj(obj), handle);
 }
 
@@ -1065,7 +1071,7 @@ static int mdd_declare_attr_set(const struct lu_env *env,
 
 #ifdef CONFIG_FS_POSIX_ACL
        if (attr->la_valid & LA_MODE) {
-                mdd_read_lock(env, obj, MOR_TGT_CHILD);
+               mdd_read_lock(env, obj, DT_TGT_CHILD);
                rc = mdo_xattr_get(env, obj, &LU_BUF_NULL,
                                   XATTR_NAME_ACL_ACCESS);
                 mdd_read_unlock(env, obj);
@@ -1092,6 +1098,7 @@ static int mdd_declare_attr_set(const struct lu_env *env,
 
 /*
  * LU-3671
+ * LU-7239
  *
  * permission changes may require sync operation, to mitigate performance
  * impact, only do this for dir and when permission is reduced.
@@ -1106,17 +1113,24 @@ static inline bool permission_needs_sync(const struct lu_attr *old,
        if (!S_ISDIR(old->la_mode))
                return false;
 
-       if (new->la_valid & (LA_UID | LA_GID))
+       if (new->la_valid & LA_UID && old->la_uid != new->la_uid)
                return true;
 
-       if (new->la_valid & LA_MODE &&
-           new->la_mode & (S_ISUID | S_ISGID | S_ISVTX))
+       if (new->la_valid & LA_GID && old->la_gid != new->la_gid)
                return true;
 
-       if ((new->la_valid & LA_MODE) &&
-           ((new->la_mode & old->la_mode) & S_IRWXUGO) !=
-            (old->la_mode & S_IRWXUGO))
-               return true;
+       if (new->la_valid & LA_MODE) {
+               /* turned on sticky bit */
+               if (!(old->la_mode & S_ISVTX) && (new->la_mode & S_ISVTX))
+                       return true;
+
+               /* set-GID has no impact on what is allowed, not checked */
+
+               /* turned off setuid bit, or one of rwx for someone */
+               if (((new->la_mode & old->la_mode) & (0777 | S_ISUID)) !=
+                    (old->la_mode & (0777 | S_ISUID)))
+                       return true;
+       }
 
        return false;
 }
@@ -1156,6 +1170,7 @@ int mdd_attr_set(const struct lu_env *env, struct md_object *obj,
        struct lu_attr *attr = MDD_ENV_VAR(env, cattr);
        const struct lu_attr *la = &ma->ma_attr;
        struct lu_ucred  *uc;
+       bool chrgrp_by_unprivileged_user = false;
        int rc;
        ENTRY;
 
@@ -1187,15 +1202,23 @@ int mdd_attr_set(const struct lu_env *env, struct md_object *obj,
        uc = lu_ucred_check(env);
        if (S_ISREG(attr->la_mode) && la->la_valid & LA_GID &&
            la->la_gid != attr->la_gid && uc != NULL && uc->uc_fsuid != 0) {
+               /* LU-10048: disable synchronous chgrp operation for it will
+                * cause deadlock between MDT and OST.
                la_copy->la_valid |= LA_FLAGS;
                la_copy->la_flags |= LUSTRE_SET_SYNC_FL;
+                */
+               chrgrp_by_unprivileged_user = true;
 
-               /* Flush the possible existing sync requests to OSTs to
-                * keep the order of sync for the current setattr operation
+               /* Flush the possible existing client setattr requests to OSTs
+                * to keep the order with the current setattr operation that
                 * will be sent directly to OSTs. see LU-5152 */
+               /* LU-11303 disable sync as this is too heavyweight.
+                * This should be replaced with a sync only for the object
+                * being modified here, not the whole filesystem.
                rc = dt_sync(env, mdd->mdd_child);
                if (rc)
                        GOTO(out, rc);
+                */
        }
 
        handle = mdd_trans_create(env, mdd);
@@ -1214,14 +1237,15 @@ int mdd_attr_set(const struct lu_env *env, struct md_object *obj,
        if (rc)
                GOTO(out, rc);
 
-       if (mdd->mdd_sync_permission && permission_needs_sync(attr, la))
+       if (!chrgrp_by_unprivileged_user && mdd->mdd_sync_permission &&
+           permission_needs_sync(attr, la))
                handle->th_sync = 1;
 
        if (la->la_valid & (LA_MTIME | LA_CTIME))
                CDEBUG(D_INODE, "setting mtime %llu, ctime %llu\n",
                       la->la_mtime, la->la_ctime);
 
-       mdd_write_lock(env, mdd_obj, MOR_TGT_CHILD);
+       mdd_write_lock(env, mdd_obj, DT_TGT_CHILD);
 
        /* LU-10509: setattr of LA_SIZE should be skipped case of DOM,
         * otherwise following truncate will do nothing and truncated
@@ -1325,6 +1349,10 @@ mdd_xattr_changelog_type(const struct lu_env *env, struct mdd_device *mdd,
        if (strcmp(XATTR_NAME_HSM, xattr_name) == 0)
                return CL_HSM;
 
+       /* Avoid logging SOM xattr for every file */
+       if (strcmp(XATTR_NAME_SOM, xattr_name) == 0)
+               return CL_NONE;
+
        if (has_prefix(xattr_name, XATTR_USER_PREFIX) ||
            has_prefix(xattr_name, XATTR_NAME_POSIX_ACL_ACCESS) ||
            has_prefix(xattr_name, XATTR_NAME_POSIX_ACL_DEFAULT) ||
@@ -1332,7 +1360,7 @@ mdd_xattr_changelog_type(const struct lu_env *env, struct mdd_device *mdd,
            has_prefix(xattr_name, XATTR_SECURITY_PREFIX))
                return CL_SETXATTR;
 
-       return -1;
+       return CL_NONE;
 }
 
 static int mdd_declare_xattr_set(const struct lu_env *env,
@@ -1368,23 +1396,25 @@ static int mdd_declare_xattr_set(const struct lu_env *env,
 static int mdd_hsm_update_locked(const struct lu_env *env,
                                 struct md_object *obj,
                                 const struct lu_buf *buf,
-                                struct thandle *handle, int *cl_flags)
+                                struct thandle *handle,
+                                enum changelog_rec_flags *clf_flags)
 {
        struct mdd_thread_info *info = mdd_env_info(env);
-       struct mdd_object      *mdd_obj = md2mdd_obj(obj);
-       struct lu_buf          *current_buf;
-       struct md_hsm          *current_mh;
-       struct md_hsm          *new_mh;
-       int                     rc;
-       ENTRY;
+       struct mdd_object *mdd_obj = md2mdd_obj(obj);
+       struct lu_buf *current_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 = lu_buf_check_and_alloc(&info->mti_xattr_buf,
-                               mdo2mdd(obj)->mdd_dt_conf.ddp_max_ea_size);
+                       MIN(mdd_obj2mdd_dev(mdd_obj)->mdd_dt_conf.ddp_max_ea_size,
+                           XATTR_SIZE_MAX));
        rc = mdo_xattr_get(env, mdd_obj, current_buf, XATTR_NAME_HSM);
        rc = lustre_buf2hsm(current_buf->lb_buf, rc, current_mh);
        if (rc < 0 && rc != -ENODATA)
@@ -1402,9 +1432,9 @@ static int mdd_hsm_update_locked(const struct lu_env *env,
 
        /* Flags differ, set flags for the changelog that will be added */
        if (current_mh->mh_flags != new_mh->mh_flags) {
-               hsm_set_cl_event(cl_flags, HE_STATE);
+               hsm_set_cl_event(clf_flags, HE_STATE);
                if (new_mh->mh_flags & HS_DIRTY)
-                       hsm_set_cl_flags(cl_flags, CLF_HSM_DIRTY);
+                       hsm_set_cl_flags(clf_flags, CLF_HSM_DIRTY);
        }
 
        OBD_FREE_PTR(new_mh);
@@ -1479,11 +1509,11 @@ static int mdd_xattr_merge(const struct lu_env *env, struct md_object *md_obj,
                RETURN(PTR_ERR(handle));
 
        if (rc > 0) {
-               mdd_write_lock(env, obj, MOR_TGT_CHILD);
-               mdd_write_lock(env, vic, MOR_TGT_CHILD);
+               mdd_write_lock(env, obj, DT_TGT_CHILD);
+               mdd_write_lock(env, vic, DT_TGT_CHILD);
        } else {
-               mdd_write_lock(env, vic, MOR_TGT_CHILD);
-               mdd_write_lock(env, obj, MOR_TGT_CHILD);
+               mdd_write_lock(env, vic, DT_TGT_CHILD);
+               mdd_write_lock(env, obj, DT_TGT_CHILD);
        }
 
        /* get EA of victim file */
@@ -1705,11 +1735,11 @@ static int mdd_xattr_split(const struct lu_env *env, struct md_object *md_obj,
                RETURN(PTR_ERR(handle));
 
        if (rc > 0) {
-               mdd_write_lock(env, obj, MOR_TGT_CHILD);
-               mdd_write_lock(env, vic, MOR_TGT_CHILD);
+               mdd_write_lock(env, obj, DT_TGT_CHILD);
+               mdd_write_lock(env, vic, DT_TGT_CHILD);
        } else {
-               mdd_write_lock(env, vic, MOR_TGT_CHILD);
-               mdd_write_lock(env, obj, MOR_TGT_CHILD);
+               mdd_write_lock(env, vic, DT_TGT_CHILD);
+               mdd_write_lock(env, obj, DT_TGT_CHILD);
        }
 
        /* get EA of mirrored file */
@@ -1812,13 +1842,13 @@ static int mdd_xattr_set(const struct lu_env *env, struct md_object *obj,
                         const struct lu_buf *buf, const char *name,
                         int fl)
 {
-       struct mdd_object       *mdd_obj = md2mdd_obj(obj);
-       struct lu_attr          *attr = MDD_ENV_VAR(env, cattr);
-       struct mdd_device       *mdd = mdo2mdd(obj);
-       struct thandle          *handle;
+       struct mdd_object *mdd_obj = md2mdd_obj(obj);
+       struct lu_attr *attr = MDD_ENV_VAR(env, cattr);
+       struct mdd_device *mdd = mdo2mdd(obj);
+       struct thandle *handle;
        enum changelog_rec_type  cl_type;
-       int                      cl_flags = 0;
-       int                      rc;
+       enum changelog_rec_flags clf_flags = 0;
+       int rc;
        ENTRY;
 
        rc = mdd_la_get(env, mdd_obj, attr);
@@ -1849,6 +1879,11 @@ static int mdd_xattr_set(const struct lu_env *env, struct md_object *obj,
                RETURN(rc);
        }
 
+       if (strcmp(name, XATTR_NAME_LMV) == 0) {
+               rc = mdd_dir_layout_shrink(env, obj, buf);
+               RETURN(rc);
+       }
+
        if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0 ||
            strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0) {
                struct posix_acl *acl;
@@ -1883,10 +1918,10 @@ static int mdd_xattr_set(const struct lu_env *env, struct md_object *obj,
        if (rc)
                GOTO(stop, rc);
 
-       mdd_write_lock(env, mdd_obj, MOR_TGT_CHILD);
+       mdd_write_lock(env, mdd_obj, DT_TGT_CHILD);
 
        if (strcmp(XATTR_NAME_HSM, name) == 0) {
-               rc = mdd_hsm_update_locked(env, obj, buf, handle, &cl_flags);
+               rc = mdd_hsm_update_locked(env, obj, buf, handle, &clf_flags);
                if (rc) {
                        mdd_write_unlock(env, mdd_obj);
                        GOTO(stop, rc);
@@ -1902,7 +1937,7 @@ static int mdd_xattr_set(const struct lu_env *env, struct md_object *obj,
        if (cl_type < 0)
                GOTO(stop, rc = 0);
 
-       rc = mdd_changelog_data_store_xattr(env, mdd, cl_type, cl_flags,
+       rc = mdd_changelog_data_store_xattr(env, mdd, cl_type, clf_flags,
                                            mdd_obj, name, handle);
 
        EXIT;
@@ -1964,7 +1999,7 @@ static int mdd_xattr_del(const struct lu_env *env, struct md_object *obj,
        if (rc)
                GOTO(stop, rc);
 
-       mdd_write_lock(env, mdd_obj, MOR_TGT_CHILD);
+       mdd_write_lock(env, mdd_obj, DT_TGT_CHILD);
        rc = mdo_xattr_del(env, mdd_obj, name, handle);
        mdd_write_unlock(env, mdd_obj);
        if (rc)
@@ -2033,8 +2068,8 @@ static int mdd_xattr_hsm_replace(const struct lu_env *env,
                                 struct thandle *handle)
 {
        struct hsm_attrs *attrs;
-       __u32 hsm_flags;
-       int flags = 0;
+       enum hsm_states hsm_flags;
+       enum changelog_rec_flags clf_flags = 0;
        int rc;
        ENTRY;
 
@@ -2049,9 +2084,9 @@ static int mdd_xattr_hsm_replace(const struct lu_env *env,
                RETURN(0);
 
        /* Add a changelog record for release. */
-       hsm_set_cl_event(&flags, HE_RELEASE);
+       hsm_set_cl_event(&clf_flags, HE_RELEASE);
        rc = mdd_changelog_data_store(env, mdo2mdd(&o->mod_obj), CL_HSM,
-                                     flags, o, handle);
+                                     clf_flags, o, handle);
        RETURN(rc);
 }
 
@@ -2186,29 +2221,65 @@ static inline int mdd_set_lmm_gen(struct lov_mds_md *lmm, __u32 *gen)
        return mdd_lmm_gen(lmm, gen, false);
 }
 
+static int mdd_dom_data_truncate(const struct lu_env *env,
+                                struct mdd_device *mdd, struct mdd_object *mo)
+{
+       struct thandle *th;
+       struct dt_object *dom;
+       int rc;
+
+       dom = dt_object_locate(mdd_object_child(mo), mdd->mdd_bottom);
+       if (!dom)
+               GOTO(out, rc = -ENODATA);
+
+       th = dt_trans_create(env, mdd->mdd_bottom);
+       if (IS_ERR(th))
+               GOTO(out, rc = PTR_ERR(th));
+
+       rc = dt_declare_punch(env, dom, 0, OBD_OBJECT_EOF, th);
+       if (rc)
+               GOTO(stop, rc);
+
+       rc = dt_trans_start_local(env, mdd->mdd_bottom, th);
+       if (rc != 0)
+               GOTO(stop, rc);
+
+       rc = dt_punch(env, dom, 0, OBD_OBJECT_EOF, th);
+stop:
+       dt_trans_stop(env, mdd->mdd_bottom, th);
+out:
+       /* Ignore failure but report the error */
+       if (rc)
+               CERROR("%s: "DFID" can't truncate DOM inode data, rc = %d\n",
+                      mdd_obj_dev_name(mo), PFID(mdo2fid(mo)), rc);
+       return rc;
+}
+
 /**
  * swap layouts between 2 lustre objects
  */
 static int mdd_swap_layouts(const struct lu_env *env, struct md_object *obj1,
                            struct md_object *obj2, __u64 flags)
 {
-       struct mdd_thread_info  *info = mdd_env_info(env);
-       struct mdd_object       *fst_o = md2mdd_obj(obj1);
-       struct mdd_object       *snd_o = md2mdd_obj(obj2);
-       struct lu_attr          *fst_la = MDD_ENV_VAR(env, cattr);
-       struct lu_attr          *snd_la = MDD_ENV_VAR(env, tattr);
-       struct mdd_device       *mdd = mdo2mdd(obj1);
-       struct lov_mds_md       *fst_lmm, *snd_lmm;
-       struct lu_buf           *fst_buf = &info->mti_buf[0];
-       struct lu_buf           *snd_buf = &info->mti_buf[1];
-       struct lu_buf           *fst_hsm_buf = &info->mti_buf[2];
-       struct lu_buf           *snd_hsm_buf = &info->mti_buf[3];
-       struct ost_id           *saved_oi = NULL;
-       struct thandle          *handle;
-       __u32                    fst_gen, snd_gen, saved_gen;
-       int                      fst_fl;
-       int                      rc;
-       int                      rc2;
+       struct mdd_thread_info *info = mdd_env_info(env);
+       struct mdd_object *fst_o = md2mdd_obj(obj1);
+       struct mdd_object *snd_o = md2mdd_obj(obj2);
+       struct lu_attr *fst_la = MDD_ENV_VAR(env, cattr);
+       struct lu_attr *snd_la = MDD_ENV_VAR(env, tattr);
+       struct mdd_device *mdd = mdo2mdd(obj1);
+       struct lov_mds_md *fst_lmm, *snd_lmm;
+       struct lu_buf *fst_buf = &info->mti_buf[0];
+       struct lu_buf *snd_buf = &info->mti_buf[1];
+       struct lu_buf *fst_hsm_buf = &info->mti_buf[2];
+       struct lu_buf *snd_hsm_buf = &info->mti_buf[3];
+       struct ost_id *saved_oi = NULL;
+       struct thandle *handle;
+       struct mdd_object *dom_o = NULL;
+       __u64 domsize_dom, domsize_vlt;
+       __u32 fst_gen, snd_gen, saved_gen;
+       int fst_fl;
+       int rc, rc2;
+
        ENTRY;
 
        CLASSERT(ARRAY_SIZE(info->mti_buf) >= 4);
@@ -2241,8 +2312,8 @@ static int mdd_swap_layouts(const struct lu_env *env, struct md_object *obj1,
                RETURN(PTR_ERR(handle));
 
        /* objects are already sorted */
-       mdd_write_lock(env, fst_o, MOR_TGT_CHILD);
-       mdd_write_lock(env, snd_o, MOR_TGT_CHILD);
+       mdd_write_lock(env, fst_o, DT_TGT_CHILD);
+       mdd_write_lock(env, snd_o, DT_TGT_CHILD);
 
        rc = mdd_stripe_get(env, fst_o, fst_buf, XATTR_NAME_LOV);
        if (rc < 0 && rc != -ENODATA)
@@ -2252,16 +2323,49 @@ static int mdd_swap_layouts(const struct lu_env *env, struct md_object *obj1,
        if (rc < 0 && rc != -ENODATA)
                GOTO(stop, rc);
 
-       /* check if file is DoM, it can be migrated only to another DoM layout
-        * with the same DoM component size
+       /* check if file has DoM. DoM file can be migrated only to another
+        * DoM layout with the same DoM component size or to an non-DOM
+        * layout. After migration to OSTs layout, local MDT inode data
+        * should be truncated.
+        * Objects are sorted by FIDs, considering that original file's FID
+        * is always smaller the snd_o is always original file we are migrating
+        * from.
+        */
+       domsize_dom = mdd_lmm_dom_size(snd_buf->lb_buf);
+       domsize_vlt = mdd_lmm_dom_size(fst_buf->lb_buf);
+
+       /* Only migration is supported for DoM files, not 'swap_layouts' so
+        * target file must be volatile and orphan.
         */
-       if (mdd_lmm_dom_size(fst_buf->lb_buf) !=
-           mdd_lmm_dom_size(snd_buf->lb_buf)) {
+       if (fst_o->mod_flags & (ORPHAN_OBJ | VOLATILE_OBJ)) {
+               dom_o = domsize_dom ? snd_o : NULL;
+       } else if (snd_o->mod_flags & (ORPHAN_OBJ | VOLATILE_OBJ)) {
+               swap(domsize_dom, domsize_vlt);
+               dom_o = domsize_dom ? fst_o : NULL;
+       } else if (domsize_dom > 0 || domsize_vlt > 0) {
+               /* 'lfs swap_layouts' case, neither file should have DoM */
+               rc = -EOPNOTSUPP;
+               CDEBUG(D_LAYOUT, "cannot swap layouts with DOM component, "
+                      "use migration instead: rc = %d\n", rc);
+               GOTO(stop, rc);
+       }
+
+       if (domsize_vlt > 0 && domsize_dom == 0) {
+               rc = -EOPNOTSUPP;
+               CDEBUG(D_LAYOUT, "cannot swap layout for "DFID": OST to DOM "
+                      "migration is not supported: rc = %d\n",
+                      PFID(mdo2fid(snd_o)), rc);
+               GOTO(stop, rc);
+       } else if (domsize_vlt > 0 && domsize_dom != domsize_vlt) {
                rc = -EOPNOTSUPP;
                CDEBUG(D_LAYOUT, "cannot swap layout for "DFID": new layout "
-                      "must have the same DoM component: rc = %d\n",
+                      "must have the same DoM component size: rc = %d\n",
                       PFID(mdo2fid(fst_o)), rc);
                GOTO(stop, rc);
+       } else if (domsize_vlt > 0) {
+               /* Migration with the same DOM component size, no need to
+                * truncate local data, it is still being used */
+               dom_o = NULL;
        }
 
        /* swapping 2 non existant layouts is a success */
@@ -2466,6 +2570,10 @@ out_restore:
 stop:
        rc = mdd_trans_stop(env, mdd, rc, handle);
 
+       /* Truncate local DOM data if all went well */
+       if (!rc && dom_o)
+               mdd_dom_data_truncate(env, mdd, dom_o);
+
        mdd_write_unlock(env, snd_o);
        mdd_write_unlock(env, fst_o);
 
@@ -2523,7 +2631,7 @@ mdd_layout_instantiate_component(const struct lu_env *env,
        if (rc)
                RETURN(rc);
 
-       mdd_write_lock(env, obj, MOR_TGT_CHILD);
+       mdd_write_lock(env, obj, DT_TGT_CHILD);
        rc = mdo_layout_change(env, obj, mlc, handle);
        mdd_write_unlock(env, obj);
        if (rc)
@@ -2600,7 +2708,7 @@ mdd_layout_update_rdonly(const struct lu_env *env, struct mdd_object *obj,
        /* it needs a sync tx to make FLR to work properly */
        handle->th_sync = 1;
 
-       mdd_write_lock(env, obj, MOR_TGT_CHILD);
+       mdd_write_lock(env, obj, DT_TGT_CHILD);
        rc = mdo_layout_change(env, obj, mlc, handle);
        if (!rc && fl) {
                /* SOM state transition from STRICT to STALE */
@@ -2667,7 +2775,7 @@ mdd_layout_update_write_pending(const struct lu_env *env,
        /* it needs a sync tx to make FLR to work properly */
        handle->th_sync = 1;
 
-       mdd_write_lock(env, obj, MOR_TGT_CHILD);
+       mdd_write_lock(env, obj, DT_TGT_CHILD);
        rc = mdo_layout_change(env, obj, mlc, handle);
        mdd_write_unlock(env, obj);
        if (rc)
@@ -2871,54 +2979,47 @@ void mdd_object_make_hint(const struct lu_env *env, struct mdd_object *parent,
        nc->do_ops->do_ah_init(env, hint, np, nc, attr->la_mode & S_IFMT);
 }
 
-/*
- * do NOT or the MAY_*'s, you'll get the weakest
- */
-int accmode(const struct lu_env *env, const struct lu_attr *la, int flags)
+static int accmode(const struct lu_env *env, const struct lu_attr *la,
+                  u64 open_flags)
 {
-       int res = 0;
-
        /* Sadly, NFSD reopens a file repeatedly during operation, so the
         * "acc_mode = 0" allowance for newly-created files isn't honoured.
         * NFSD uses the MDS_OPEN_OWNEROVERRIDE flag to say that a file
         * owner can write to a file even if it is marked readonly to hide
         * its brokenness. (bug 5781) */
-       if (flags & MDS_OPEN_OWNEROVERRIDE) {
+       if (open_flags & MDS_OPEN_OWNEROVERRIDE) {
                struct lu_ucred *uc = lu_ucred_check(env);
 
                if ((uc == NULL) || (la->la_uid == uc->uc_fsuid))
                        return 0;
        }
 
-       if (flags & MDS_FMODE_READ)
-               res |= MAY_READ;
-       if (flags & (MDS_FMODE_WRITE | MDS_OPEN_TRUNC | MDS_OPEN_APPEND))
-               res |= MAY_WRITE;
-       if (flags & MDS_FMODE_EXEC)
-               res = MAY_EXEC;
-       return res;
+       return mds_accmode(open_flags);
 }
 
 static int mdd_open_sanity_check(const struct lu_env *env,
-                               struct mdd_object *obj,
-                               const struct lu_attr *attr, int flag)
+                                struct mdd_object *obj,
+                                const struct lu_attr *attr, u64 open_flags)
 {
        int mode, rc;
        ENTRY;
 
-       /* EEXIST check */
-       if (mdd_is_dead_obj(obj))
+       /* EEXIST check, also opening of *open* orphans is allowed so we can
+        * open-by-handle unlinked files
+        */
+       if (mdd_is_dead_obj(obj) &&
+           likely(!(mdd_is_orphan_obj(obj) && obj->mod_count > 0)))
                RETURN(-ENOENT);
 
        if (S_ISLNK(attr->la_mode))
                RETURN(-ELOOP);
 
-       mode = accmode(env, attr, flag);
+       mode = accmode(env, attr, open_flags);
 
        if (S_ISDIR(attr->la_mode) && (mode & MAY_WRITE))
                RETURN(-EISDIR);
 
-       if (!(flag & MDS_OPEN_CREATED)) {
+       if (!(open_flags & MDS_OPEN_CREATED)) {
                rc = mdd_permission_internal(env, obj, attr, mode);
                if (rc)
                        RETURN(rc);
@@ -2926,13 +3027,14 @@ static int mdd_open_sanity_check(const struct lu_env *env,
 
        if (S_ISFIFO(attr->la_mode) || S_ISSOCK(attr->la_mode) ||
            S_ISBLK(attr->la_mode) || S_ISCHR(attr->la_mode))
-               flag &= ~MDS_OPEN_TRUNC;
+               open_flags &= ~MDS_OPEN_TRUNC;
 
        /* For writing append-only file must open it with append mode. */
        if (attr->la_flags & LUSTRE_APPEND_FL) {
-               if ((flag & MDS_FMODE_WRITE) && !(flag & MDS_OPEN_APPEND))
+               if ((open_flags & MDS_FMODE_WRITE) &&
+                   !(open_flags & MDS_OPEN_APPEND))
                        RETURN(-EPERM);
-               if (flag & MDS_OPEN_TRUNC)
+               if (open_flags & MDS_OPEN_TRUNC)
                        RETURN(-EPERM);
        }
 
@@ -2940,7 +3042,7 @@ static int mdd_open_sanity_check(const struct lu_env *env,
 }
 
 static int mdd_open(const struct lu_env *env, struct md_object *obj,
-                   int flags)
+                   u64 open_flags)
 {
        struct mdd_object *mdd_obj = md2mdd_obj(obj);
        struct md_device *md_dev = lu2md_dev(mdd2lu_dev(mdo2mdd(obj)));
@@ -2951,13 +3053,13 @@ static int mdd_open(const struct lu_env *env, struct md_object *obj,
        enum changelog_rec_type type = CL_OPEN;
        int rc = 0;
 
-       mdd_write_lock(env, mdd_obj, MOR_TGT_CHILD);
+       mdd_write_lock(env, mdd_obj, DT_TGT_CHILD);
 
        rc = mdd_la_get(env, mdd_obj, attr);
        if (rc != 0)
                GOTO(out, rc);
 
-       rc = mdd_open_sanity_check(env, mdd_obj, attr, flags);
+       rc = mdd_open_sanity_check(env, mdd_obj, attr, open_flags);
        if ((rc == -EACCES) && (mdd->mdd_cl.mc_mask & (1 << CL_DN_OPEN)))
                type = CL_DN_OPEN;
        else if (rc != 0)
@@ -2970,13 +3072,13 @@ static int mdd_open(const struct lu_env *env, struct md_object *obj,
 
 find:
        /* look for existing opener in list under mdd_write_lock */
-       mou = mdd_obj_user_find(mdd_obj, uc->uc_uid, uc->uc_gid, flags);
+       mou = mdd_obj_user_find(mdd_obj, uc->uc_uid, uc->uc_gid, open_flags);
 
        if (!mou) {
                int rc2;
 
                /* add user to list */
-               mou = mdd_obj_user_alloc(flags, uc->uc_uid, uc->uc_gid);
+               mou = mdd_obj_user_alloc(open_flags, uc->uc_uid, uc->uc_gid);
                if (IS_ERR(mou)) {
                        if (rc == 0)
                                rc = PTR_ERR(mou);
@@ -3012,7 +3114,8 @@ find:
                }
        }
 
-       mdd_changelog(env, type, flags, md_dev, mdo2fid(mdd_obj));
+       /* FYI, only the bottom 32 bits of open_flags are recorded */
+       mdd_changelog(env, type, open_flags, md_dev, mdo2fid(mdd_obj));
 
        EXIT;
 out:
@@ -3036,7 +3139,7 @@ static int mdd_declare_close(const struct lu_env *env, struct mdd_object *obj,
  * No permission check is needed.
  */
 static int mdd_close(const struct lu_env *env, struct md_object *obj,
-                    struct md_attr *ma, int mode)
+                    struct md_attr *ma, u64 open_flags)
 {
        struct mdd_object *mdd_obj = md2mdd_obj(obj);
        struct mdd_device *mdd = mdo2mdd(obj);
@@ -3044,12 +3147,12 @@ static int mdd_close(const struct lu_env *env, struct md_object *obj,
        int is_orphan = 0;
        int rc;
        bool blocked = false;
-       int last_close_by_uid = 0;
+       bool last_close_by_uid = false;
        const struct lu_ucred *uc = lu_ucred(env);
        ENTRY;
 
        if (ma->ma_valid & MA_FLAGS && ma->ma_attr_flags & MDS_KEEP_ORPHAN) {
-               mdd_write_lock(env, mdd_obj, MOR_TGT_CHILD);
+               mdd_write_lock(env, mdd_obj, DT_TGT_CHILD);
                mdd_obj->mod_count--;
                mdd_write_unlock(env, mdd_obj);
 
@@ -3104,7 +3207,7 @@ again:
        }
 
 cont:
-       mdd_write_lock(env, mdd_obj, MOR_TGT_CHILD);
+       mdd_write_lock(env, mdd_obj, DT_TGT_CHILD);
        rc = mdd_la_get(env, mdd_obj, &ma->ma_attr);
        if (rc != 0) {
                CERROR("%s: failed to get lu_attr of "DFID": rc = %d\n",
@@ -3126,8 +3229,9 @@ cont:
        mdd_obj->mod_count--; /*release open count */
 
        /* under mdd write lock */
-       /* If recording, see if we need to remove UID from list */
-       if (mdd_changelog_enabled(env, mdd, CL_OPEN)) {
+       /* If recording, see if we need to remove UID from list. uc is not
+        * initialized if the client has been evicted. */
+       if (mdd_changelog_enabled(env, mdd, CL_OPEN) && uc) {
                struct mdd_object_user *mou;
 
                /* look for UID in list */
@@ -3135,12 +3239,13 @@ cont:
                 * the user had the file open. So the corresponding close
                 * will not be logged.
                 */
-               mou = mdd_obj_user_find(mdd_obj, uc->uc_uid, uc->uc_gid, mode);
+               mou = mdd_obj_user_find(mdd_obj, uc->uc_uid, uc->uc_gid,
+                                       open_flags);
                if (mou) {
                        mou->mou_opencount--;
                        if (mou->mou_opencount == 0) {
                                mdd_obj_user_remove(mdd_obj, mou);
-                               last_close_by_uid = 1;
+                               last_close_by_uid = true;
                        }
                }
        }
@@ -3194,7 +3299,8 @@ out:
         * CL_OPEN. Plus Changelogs mask may not change often.
         */
        if (((!(mdd->mdd_cl.mc_mask & (1 << CL_OPEN)) &&
-             (mode & (MDS_FMODE_WRITE | MDS_OPEN_APPEND | MDS_OPEN_TRUNC))) ||
+             (open_flags & (MDS_FMODE_WRITE | MDS_OPEN_APPEND |
+                            MDS_OPEN_TRUNC))) ||
             ((mdd->mdd_cl.mc_mask & (1 << CL_OPEN)) && last_close_by_uid)) &&
            !(ma->ma_valid & MA_FLAGS && ma->ma_attr_flags & MDS_RECOV_OPEN)) {
                if (handle == NULL) {
@@ -3207,14 +3313,15 @@ out:
                        if (rc)
                                GOTO(stop, rc);
 
-                        rc = mdd_trans_start(env, mdo2mdd(obj), handle);
-                        if (rc)
-                                GOTO(stop, rc);
-                }
+                       rc = mdd_trans_start(env, mdo2mdd(obj), handle);
+                       if (rc)
+                               GOTO(stop, rc);
+               }
 
-                mdd_changelog_data_store(env, mdd, CL_CLOSE, mode,
-                                         mdd_obj, handle);
-        }
+               /* FYI, only the bottom 32 bits of open_flags are recorded */
+               mdd_changelog_data_store(env, mdd, CL_CLOSE, open_flags,
+                                        mdd_obj, handle);
+       }
 
 stop:
        if (handle != NULL && !IS_ERR(handle))
@@ -3340,7 +3447,7 @@ int mdd_readpage(const struct lu_env *env, struct md_object *obj,
                 return -ENOENT;
         }
 
-        mdd_read_lock(env, mdd_obj, MOR_TGT_CHILD);
+       mdd_read_lock(env, mdd_obj, DT_TGT_CHILD);
         rc = mdd_readpage_sanity_check(env, mdd_obj);
         if (rc)
                 GOTO(out_unlock, rc);