Whamcloud - gitweb
LU-7713 osd: osd-zfs should serialize destroy vs. others
[fs/lustre-release.git] / lustre / mdd / mdd_dir.c
index db4ddad..eab1629 100644 (file)
@@ -85,11 +85,12 @@ __mdd_lookup(const struct lu_env *env, struct md_object *pobj,
        if (unlikely(mdd_is_dead_obj(mdd_obj)))
                RETURN(-ESTALE);
 
+       if (!mdd_object_exists(mdd_obj))
+               RETURN(-ESTALE);
+
        if (mdd_object_remote(mdd_obj)) {
                CDEBUG(D_INFO, "%s: Object "DFID" locates on remote server\n",
                       mdd2obd_dev(m)->obd_name, PFID(mdo2fid(mdd_obj)));
-       } else if (!mdd_object_exists(mdd_obj)) {
-               RETURN(-ESTALE);
        }
 
        rc = mdd_permission_internal_locked(env, mdd_obj, pattr, mask,
@@ -231,6 +232,10 @@ static int mdd_is_parent(const struct lu_env *env,
                parent = mdd_object_find(env, mdd, pfid);
                if (IS_ERR(parent))
                        GOTO(out, rc = PTR_ERR(parent));
+
+               if (!mdd_object_exists(parent))
+                       GOTO(out, rc = -EINVAL);
+
                p1 = parent;
         }
         EXIT;
@@ -375,8 +380,6 @@ int mdd_may_create(const struct lu_env *env, struct mdd_object *pobj,
                   const struct lu_attr *pattr, struct mdd_object *cobj,
                   bool check_perm)
 {
-       struct mdd_thread_info *info = mdd_env_info(env);
-       struct lu_buf   *xbuf;
        int rc = 0;
        ENTRY;
 
@@ -386,18 +389,6 @@ int mdd_may_create(const struct lu_env *env, struct mdd_object *pobj,
        if (mdd_is_dead_obj(pobj))
                RETURN(-ENOENT);
 
-       /* If the parent is a sub-stripe, check whether it is dead */
-       xbuf = mdd_buf_get(env, info->mti_key, sizeof(info->mti_key));
-       rc = mdo_xattr_get(env, pobj, xbuf, XATTR_NAME_LMV);
-       if (unlikely(rc > 0)) {
-               struct lmv_mds_md_v1  *lmv1 = xbuf->lb_buf;
-
-               if (le32_to_cpu(lmv1->lmv_magic) == LMV_MAGIC_STRIPE &&
-                   le32_to_cpu(lmv1->lmv_hash_type) & LMV_HASH_FLAG_DEAD)
-                       RETURN(-ESTALE);
-       }
-       rc = 0;
-
        if (check_perm)
                rc = mdd_permission_internal_locked(env, pobj, pattr,
                                                    MAY_WRITE | MAY_EXEC,
@@ -1158,10 +1149,15 @@ struct lu_buf *mdd_links_get(const struct lu_env *env,
 int mdd_links_write(const struct lu_env *env, struct mdd_object *mdd_obj,
                    struct linkea_data *ldata, struct thandle *handle)
 {
-       const struct lu_buf *buf = mdd_buf_get_const(env, ldata->ld_buf->lb_buf,
-                                                    ldata->ld_leh->leh_len);
+       const struct lu_buf *buf;
        int                 rc;
 
+       if (ldata == NULL || ldata->ld_buf == NULL ||
+           ldata->ld_leh == NULL)
+               return 0;
+
+       buf = mdd_buf_get_const(env, ldata->ld_buf->lb_buf,
+                               ldata->ld_leh->leh_len);
        if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_NO_LINKEA))
                return 0;
 
@@ -1408,21 +1404,18 @@ out_pending:
         return rc;
 }
 
-static int mdd_mark_dead_object(const struct lu_env *env,
+static int mdd_mark_orphan_object(const struct lu_env *env,
                                struct mdd_object *obj, struct thandle *handle,
                                bool declare)
 {
        struct lu_attr *attr = MDD_ENV_VAR(env, la_for_start);
        int rc;
 
-       if (!declare)
-               obj->mod_flags |= DEAD_OBJ;
-
        if (!S_ISDIR(mdd_object_type(obj)))
                return 0;
 
        attr->la_valid = LA_FLAGS;
-       attr->la_flags = LUSTRE_SLAVE_DEAD_FL;
+       attr->la_flags = LUSTRE_ORPHAN_FL;
 
        if (declare)
                rc = mdo_declare_attr_set(env, obj, attr, handle);
@@ -1438,15 +1431,18 @@ static int mdd_declare_finish_unlink(const struct lu_env *env,
 {
        int     rc;
 
-       rc = mdd_mark_dead_object(env, obj, handle, true);
+       /* Sigh, we do not know if the unlink object will become orphan in
+        * declare phase, but fortunately the flags here does not matter
+        * in current declare implementation */
+       rc = mdd_mark_orphan_object(env, obj, handle, true);
        if (rc != 0)
                return rc;
 
-       rc = orph_declare_index_insert(env, obj, mdd_object_type(obj), handle);
+       rc = mdo_declare_destroy(env, obj, handle);
        if (rc != 0)
                return rc;
 
-       rc = mdo_declare_destroy(env, obj, handle);
+       rc = orph_declare_index_insert(env, obj, mdd_object_type(obj), handle);
        if (rc != 0)
                return rc;
 
@@ -1461,34 +1457,37 @@ int mdd_finish_unlink(const struct lu_env *env,
                      struct thandle *th)
 {
        int rc = 0;
-        int is_dir = S_ISDIR(ma->ma_attr.la_mode);
-        ENTRY;
+       int is_dir = S_ISDIR(ma->ma_attr.la_mode);
+       ENTRY;
 
-        LASSERT(mdd_write_locked(env, obj) != 0);
+       LASSERT(mdd_write_locked(env, obj) != 0);
 
        if (ma->ma_attr.la_nlink == 0 || is_dir) {
-               rc = mdd_mark_dead_object(env, obj, th, false);
-               if (rc != 0)
-                       RETURN(rc);
-
-                /* add new orphan and the object
-                 * will be deleted during mdd_close() */
-                if (obj->mod_count) {
-                        rc = __mdd_orphan_add(env, obj, th);
-                        if (rc == 0)
-                                CDEBUG(D_HA, "Object "DFID" is inserted into "
-                                        "orphan list, open count = %d\n",
-                                        PFID(mdd_object_fid(obj)),
-                                        obj->mod_count);
-                        else
-                                CERROR("Object "DFID" fail to be an orphan, "
-                                       "open count = %d, maybe cause failed "
-                                       "open replay\n",
-                                        PFID(mdd_object_fid(obj)),
-                                        obj->mod_count);
-                } else {
+               /* add new orphan and the object
+                * will be deleted during mdd_close() */
+               obj->mod_flags |= DEAD_OBJ;
+               if (obj->mod_count) {
+                       rc = __mdd_orphan_add(env, obj, th);
+                       if (rc == 0)
+                               CDEBUG(D_HA, "Object "DFID" is inserted into "
+                                       "orphan list, open count = %d\n",
+                                       PFID(mdd_object_fid(obj)),
+                                       obj->mod_count);
+                       else
+                               CERROR("Object "DFID" fail to be an orphan, "
+                                      "open count = %d, maybe cause failed "
+                                      "open replay\n",
+                                       PFID(mdd_object_fid(obj)),
+                                       obj->mod_count);
+
+                       /* mark object as an orphan here, not
+                        * before __mdd_orphan_add() as racing
+                        * mdd_la_get() may propagate ORPHAN_OBJ
+                        * causing the asserition */
+                       rc = mdd_mark_orphan_object(env, obj, th, false);
+               } else {
                        rc = mdo_destroy(env, obj, th);
-                }
+               }
        } else if (!is_dir) {
                /* old files may not have link ea; ignore errors */
                mdd_links_del(env, obj, mdo2fid(pobj), lname, th);
@@ -1594,7 +1593,7 @@ static bool mdd_hsm_archive_exists(const struct lu_env *env,
                if (rc < 0)
                        RETURN(false);
 
-               ma->ma_valid = MA_HSM;
+               ma->ma_valid |= MA_HSM;
        }
        if (ma->ma_hsm.mh_flags & HS_EXISTS)
                RETURN(true);
@@ -1622,7 +1621,7 @@ static int mdd_unlink(const struct lu_env *env, struct md_object *pobj,
        struct mdd_object *mdd_cobj = NULL;
        struct mdd_device *mdd = mdo2mdd(pobj);
        struct thandle    *handle;
-       int rc, is_dir = 0;
+       int rc, is_dir = 0, cl_flags = 0;
        ENTRY;
 
        /* cobj == NULL means only delete name entry */
@@ -1643,6 +1642,11 @@ static int mdd_unlink(const struct lu_env *env, struct md_object *pobj,
                        RETURN(rc);
 
                is_dir = S_ISDIR(cattr->la_mode);
+               /* search for an existing archive.
+                * we should check ahead as the object
+                * can be destroyed in this transaction */
+               if (mdd_hsm_archive_exists(env, mdd_cobj, ma))
+                       cl_flags |= CLF_UNLINK_HSM_EXISTS;
        }
 
        rc = mdd_unlink_sanity_check(env, mdd_pobj, pattr, mdd_cobj, cattr);
@@ -1720,30 +1724,33 @@ static int mdd_unlink(const struct lu_env *env, struct md_object *pobj,
        ma->ma_attr = *cattr;
        ma->ma_valid |= MA_INODE;
        rc = mdd_finish_unlink(env, mdd_cobj, ma, mdd_pobj, lname, handle);
+       if (rc != 0)
+               GOTO(cleanup, rc);
 
        /* fetch updated nlink */
-       if (rc == 0)
-               rc = mdd_la_get(env, mdd_cobj, cattr);
+       rc = mdd_la_get(env, mdd_cobj, cattr);
+       /* if object is removed then we can't get its attrs,
+        * use last get */
+       if (rc == -ENOENT) {
+               cattr->la_nlink = 0;
+               rc = 0;
+       }
 
-       /* if object is removed then we can't get its attrs, use last get */
        if (cattr->la_nlink == 0) {
                ma->ma_attr = *cattr;
                ma->ma_valid |= MA_INODE;
        }
+
        EXIT;
 cleanup:
        if (likely(mdd_cobj != NULL))
                mdd_write_unlock(env, mdd_cobj);
 
        if (rc == 0) {
-               int cl_flags = 0;
-
-               if (cattr->la_nlink == 0) {
+               if (cattr->la_nlink == 0)
                        cl_flags |= CLF_UNLINK_LAST;
-                       /* search for an existing archive */
-                       if (mdd_hsm_archive_exists(env, mdd_cobj, ma))
-                               cl_flags |= CLF_UNLINK_HSM_EXISTS;
-               }
+               else
+                       cl_flags &= ~CLF_UNLINK_HSM_EXISTS;
 
                rc = mdd_changelog_ns_store(env, mdd,
                        is_dir ? CL_RMDIR : CL_UNLINK, cl_flags,
@@ -1945,9 +1952,9 @@ static int mdd_create_sanity_check(const struct lu_env *env,
        int rc;
        ENTRY;
 
-        /* EEXIST check */
-        if (mdd_is_dead_obj(obj))
-                RETURN(-ENOENT);
+       /* EEXIST check */
+       if (mdd_is_dead_obj(obj))
+               RETURN(-ENOENT);
 
        /*
          * In some cases this lookup is not needed - we know before if name
@@ -2797,6 +2804,11 @@ static int mdd_rename(const struct lu_env *env,
                rc = mdd_la_get(env, mdd_tobj, tattr);
                if (rc)
                        GOTO(out_pending, rc);
+               /* search for an existing archive.
+                * we should check ahead as the object
+                * can be destroyed in this transaction */
+               if (mdd_hsm_archive_exists(env, mdd_tobj, ma))
+                       cl_flags |= CLF_RENAME_LAST_EXISTS;
        }
 
        rc = mdd_la_get(env, mdd_tpobj, tpattr);
@@ -2944,7 +2956,12 @@ static int mdd_rename(const struct lu_env *env,
 
                /* fetch updated nlink */
                rc = mdd_la_get(env, mdd_tobj, tattr);
-               if (rc != 0) {
+               if (rc == -ENOENT) {
+                       /* the object got removed, let's
+                        * return the latest known attributes */
+                       tattr->la_nlink = 0;
+                       rc = 0;
+               } else if (rc != 0) {
                        CERROR("%s: Failed to get nlink for tobj "
                                DFID": rc = %d\n",
                                mdd2obd_dev(mdd)->obd_name,
@@ -2955,11 +2972,10 @@ static int mdd_rename(const struct lu_env *env,
                ma->ma_attr = *tattr;
                ma->ma_valid |= MA_INODE;
 
-               if (tattr->la_nlink == 0) {
+               if (tattr->la_nlink == 0)
                        cl_flags |= CLF_RENAME_LAST;
-                       if (mdd_hsm_archive_exists(env, mdd_tobj, ma))
-                               cl_flags |= CLF_RENAME_LAST_EXISTS;
-               }
+               else
+                       cl_flags &= ~CLF_RENAME_LAST_EXISTS;
         }
 
        la->la_valid = LA_CTIME | LA_MTIME;
@@ -3046,6 +3062,7 @@ out_pending:
  **/
 static int mdd_linkea_update_child_internal(const struct lu_env *env,
                                            struct mdd_object *parent,
+                                           struct mdd_object *newparent,
                                            struct mdd_object *child,
                                            const char *name, int namelen,
                                            struct thandle *handle,
@@ -3082,7 +3099,7 @@ static int mdd_linkea_update_child_internal(const struct lu_env *env,
                                    &lname, &fid);
 
                if (strncmp(lname.ln_name, name, namelen) != 0 ||
-                   lu_fid_eq(&fid, mdd_object_fid(parent))) {
+                   !lu_fid_eq(&fid, mdd_object_fid(parent))) {
                        ldata.ld_lee = (struct link_ea_entry *)
                                       ((char *)ldata.ld_lee +
                                        ldata.ld_reclen);
@@ -3092,10 +3109,10 @@ static int mdd_linkea_update_child_internal(const struct lu_env *env,
                CDEBUG(D_INFO, "%s: update "DFID" with %.*s:"DFID"\n",
                       mdd2obd_dev(mdd)->obd_name, PFID(mdd_object_fid(child)),
                       lname.ln_namelen, lname.ln_name,
-                      PFID(mdd_object_fid(parent)));
+                      PFID(mdd_object_fid(newparent)));
                /* update to the new parent fid */
                linkea_entry_pack(ldata.ld_lee, &lname,
-                                 mdd_object_fid(parent));
+                                 mdd_object_fid(newparent));
                if (declare)
                        rc = mdd_declare_links_add(env, child, handle, &ldata,
                                                   MLAO_IGNORE);
@@ -3108,21 +3125,25 @@ static int mdd_linkea_update_child_internal(const struct lu_env *env,
 
 static int mdd_linkea_declare_update_child(const struct lu_env *env,
                                           struct mdd_object *parent,
+                                          struct mdd_object *newparent,
                                           struct mdd_object *child,
                                           const char *name, int namelen,
                                           struct thandle *handle)
 {
-       return mdd_linkea_update_child_internal(env, parent, child, name,
+       return mdd_linkea_update_child_internal(env, parent, newparent,
+                                               child, name,
                                                namelen, handle, true);
 }
 
 static int mdd_linkea_update_child(const struct lu_env *env,
                                   struct mdd_object *parent,
+                                  struct mdd_object *newparent,
                                   struct mdd_object *child,
                                   const char *name, int namelen,
                                   struct thandle *handle)
 {
-       return mdd_linkea_update_child_internal(env, parent, child, name,
+       return mdd_linkea_update_child_internal(env, parent, newparent,
+                                               child, name,
                                                namelen, handle, false);
 }
 
@@ -3413,7 +3434,7 @@ static int mdd_declare_migrate_create(const struct lu_env *env,
                                             buf, 0, handle);
                if (rc != 0)
                        return rc;
-       } else if (S_ISDIR(la->la_mode)) {
+       } else if (S_ISDIR(la->la_mode) && ldata != NULL) {
                rc = mdd_declare_links_add(env, mdd_tobj, handle, ldata,
                                           MLAO_IGNORE);
                if (rc != 0)
@@ -3497,7 +3518,12 @@ static int mdd_migrate_create(const struct lu_env *env,
                }
        } else if (S_ISDIR(la->la_mode)) {
                rc = mdd_links_read(env, mdd_sobj, ldata);
-               if (rc < 0 && rc != -ENODATA)
+               if (rc == -ENODATA) {
+                       /* ignore the non-linkEA error */
+                       ldata = NULL;
+                       rc = 0;
+               }
+               if (rc < 0)
                        RETURN(rc);
        }
 
@@ -3531,13 +3557,16 @@ static int mdd_migrate_create(const struct lu_env *env,
        if (rc != 0)
                GOTO(stop_trans, rc);
 
+       /* don't set nlink from the original object */
+       la->la_valid &= ~LA_NLINK;
+
        /* create the target object */
        rc = mdd_object_create(env, mdd_pobj, mdd_tobj, la, spec, NULL, NULL,
                               hint, handle);
        if (rc != 0)
                GOTO(stop_trans, rc);
 
-       if (S_ISDIR(la->la_mode)) {
+       if (S_ISDIR(la->la_mode) && ldata != NULL) {
                rc = mdd_links_write(env, mdd_tobj, ldata, handle);
                if (rc != 0)
                        GOTO(stop_trans, rc);
@@ -3710,7 +3739,7 @@ static int mdd_migrate_entries(const struct lu_env *env,
                                GOTO(out_put, rc);
                }
 
-               rc = mdd_linkea_declare_update_child(env, mdd_tobj,
+               rc = mdd_linkea_declare_update_child(env, mdd_sobj,mdd_tobj,
                                                     child, name,
                                                     strlen(name),
                                                     handle);
@@ -3749,7 +3778,8 @@ static int mdd_migrate_entries(const struct lu_env *env,
                                GOTO(out_put, rc);
                }
 
-               rc = mdd_linkea_update_child(env, mdd_tobj, child, name,
+               rc = mdd_linkea_update_child(env, mdd_sobj, mdd_tobj,
+                                            child, name,
                                             strlen(name), handle);
 
 out_put:
@@ -4011,13 +4041,12 @@ static int mdd_migrate_update_name(const struct lu_env *env,
 
        mdd_write_lock(env, mdd_sobj, MOR_TGT_CHILD);
 
-       /* Increase mod_count to add the source object to the orphan list,
-        * so if other clients still send RPC to the old object, then these
-        * objects can help the request to find the new object, see
-        * mdt_reint_open() */
-       mdd_sobj->mod_count++;
-       rc = mdd_finish_unlink(env, mdd_sobj, ma, mdd_pobj, lname, handle);
-       mdd_sobj->mod_count--;
+       mdd_sobj->mod_flags |= DEAD_OBJ;
+       rc = mdd_mark_orphan_object(env, mdd_sobj, handle, false);
+       if (rc != 0)
+               GOTO(out_unlock, rc);
+
+       rc = __mdd_orphan_add(env, mdd_sobj, handle);
        if (rc != 0)
                GOTO(out_unlock, rc);