Whamcloud - gitweb
LU-5682 lfsck: optimize ldlm lock used by LFSCK
[fs/lustre-release.git] / lustre / lfsck / lfsck_namespace.c
index 585ab52..7755e33 100644 (file)
@@ -917,7 +917,7 @@ static int lfsck_namespace_insert_orphan(const struct lu_env *env,
        struct dt_device                *dev    = lfsck_obj2dev(orphan);
        struct dt_object                *parent;
        struct thandle                  *th     = NULL;
-       struct lustre_handle             plh    = { 0 };
+       struct lfsck_lock_handle        *pllh   = &info->lti_llh;
        struct lustre_handle             clh    = { 0 };
        struct linkea_data               ldata  = { NULL };
        struct lu_buf                    linkea_buf;
@@ -934,12 +934,7 @@ static int lfsck_namespace_insert_orphan(const struct lu_env *env,
        parent = lfsck->li_lpf_obj;
        pfid = lfsck_dto2fid(parent);
 
-       /* Hold update lock on the parent to prevent others to access. */
-       rc = lfsck_ibits_lock(env, lfsck, parent, &plh,
-                             MDS_INODELOCK_UPDATE, LCK_EX);
-       if (rc != 0)
-               GOTO(log, rc);
-
+again:
        do {
                namelen = snprintf(info->lti_key, NAME_MAX, DFID"%s-%s-%d",
                                   PFID(cfid), infix, type, idx++);
@@ -953,6 +948,29 @@ static int lfsck_namespace_insert_orphan(const struct lu_env *env,
                        exist = true;
        } while (rc == 0 && !exist);
 
+       rc = lfsck_lock(env, lfsck, parent, info->lti_key, pllh,
+                       MDS_INODELOCK_UPDATE, LCK_PW);
+       if (rc != 0)
+               GOTO(log, rc);
+
+       /* Re-check whether the name conflict with othrs after taken
+        * the ldlm lock. */
+       rc = dt_lookup(env, parent, (struct dt_rec *)&tfid,
+                      (const struct dt_key *)info->lti_key, BYPASS_CAPA);
+       if (rc == 0) {
+               if (!lu_fid_eq(cfid, &tfid)) {
+                       exist = false;
+                       lfsck_unlock(pllh);
+                       goto again;
+               }
+
+               exist = true;
+       } else if (rc != -ENOENT) {
+               GOTO(log, rc);
+       } else {
+               exist = false;
+       }
+
        cname->ln_name = info->lti_key;
        cname->ln_namelen = namelen;
        rc = linkea_data_new(&ldata, &info->lti_linkea_buf2);
@@ -964,8 +982,8 @@ static int lfsck_namespace_insert_orphan(const struct lu_env *env,
                GOTO(log, rc);
 
        rc = lfsck_ibits_lock(env, lfsck, orphan, &clh,
-                             MDS_INODELOCK_UPDATE | MDS_INODELOCK_LOOKUP,
-                             LCK_EX);
+                             MDS_INODELOCK_UPDATE | MDS_INODELOCK_LOOKUP |
+                             MDS_INODELOCK_XATTR, LCK_EX);
        if (rc != 0)
                GOTO(log, rc);
 
@@ -1080,7 +1098,7 @@ stop:
 
 log:
        lfsck_ibits_unlock(&clh, LCK_EX);
-       lfsck_ibits_unlock(&plh, LCK_EX);
+       lfsck_unlock(pllh);
        CDEBUG(D_LFSCK, "%s: namespace LFSCK insert orphan for the "
               "object "DFID", name = %s: rc = %d\n",
               lfsck_lfsck2name(lfsck), PFID(cfid),
@@ -1132,7 +1150,7 @@ static int lfsck_namespace_insert_normal(const struct lu_env *env,
        struct dt_object                *pobj   = NULL;
        struct dt_object                *cobj   = NULL;
        struct thandle                  *th     = NULL;
-       struct lustre_handle             lh     = { 0 };
+       struct lfsck_lock_handle        *llh    = &info->lti_llh;
        int                              rc     = 0;
        ENTRY;
 
@@ -1153,9 +1171,8 @@ static int lfsck_namespace_insert_normal(const struct lu_env *env,
        if (lfsck->li_bookmark_ram.lb_param & LPF_DRYRUN)
                GOTO(log, rc = 1);
 
-       /* Hold update lock on the pobj to prevent others to access. */
-       rc = lfsck_ibits_lock(env, lfsck, pobj, &lh,
-                             MDS_INODELOCK_UPDATE, LCK_EX);
+       rc = lfsck_lock(env, lfsck, parent, name, llh,
+                       MDS_INODELOCK_UPDATE, LCK_PW);
        if (rc != 0)
                GOTO(log, rc);
 
@@ -1217,7 +1234,7 @@ stop:
        dt_trans_stop(env, dev, th);
 
 unlock:
-       lfsck_ibits_unlock(&lh, LCK_EX);
+       lfsck_unlock(llh);
 
 log:
        CDEBUG(D_LFSCK, "%s: namespace LFSCK insert object "DFID" with "
@@ -1272,7 +1289,7 @@ static int lfsck_namespace_create_orphan_dir(const struct lu_env *env,
        struct dt_device                *dev    = lfsck_obj2dev(orphan);
        struct dt_object                *parent = NULL;
        struct thandle                  *th     = NULL;
-       struct lustre_handle             lh     = { 0 };
+       struct lfsck_lock_handle        *llh    = &info->lti_llh;
        struct linkea_data               ldata  = { NULL };
        struct lu_buf                    linkea_buf;
        struct lu_buf                    lmv_buf;
@@ -1319,22 +1336,35 @@ static int lfsck_namespace_create_orphan_dir(const struct lu_env *env,
        if (IS_ERR(dev))
                GOTO(log, rc = PTR_ERR(dev));
 
-       /* Hold update lock on the parent to prevent others to access. */
-       rc = lfsck_ibits_lock(env, lfsck, parent, &lh,
-                             MDS_INODELOCK_UPDATE, LCK_EX);
-       if (rc != 0)
-               GOTO(log, rc);
-
        idx = 0;
+
+again:
        do {
                namelen = snprintf(name, 31, DFID"-P-%d",
                                   PFID(cfid), idx++);
                rc = dt_lookup(env, parent, (struct dt_rec *)&tfid,
                               (const struct dt_key *)name, BYPASS_CAPA);
                if (rc != 0 && rc != -ENOENT)
-                       GOTO(unlock1, rc);
+                       GOTO(log, rc);
        } while (rc == 0);
 
+       rc = lfsck_lock(env, lfsck, parent, name, llh,
+                       MDS_INODELOCK_UPDATE, LCK_PW);
+       if (rc != 0)
+               GOTO(log, rc);
+
+       /* Re-check whether the name conflict with othrs after taken
+        * the ldlm lock. */
+       rc = dt_lookup(env, parent, (struct dt_rec *)&tfid,
+                      (const struct dt_key *)name, BYPASS_CAPA);
+       if (unlikely(rc == 0)) {
+               lfsck_unlock(llh);
+               goto again;
+       }
+
+       if (rc != -ENOENT)
+               GOTO(unlock1, rc);
+
        cname->ln_name = name;
        cname->ln_namelen = namelen;
 
@@ -1477,7 +1507,7 @@ stop:
        dt_trans_stop(env, dev, th);
 
 unlock1:
-       lfsck_ibits_unlock(&lh, LCK_EX);
+       lfsck_unlock(llh);
 
 log:
        CDEBUG(D_LFSCK, "%s: namespace LFSCK create orphan dir for "
@@ -1533,8 +1563,8 @@ static int lfsck_namespace_shrink_linkea(const struct lu_env *env,
        ENTRY;
 
        rc = lfsck_ibits_lock(env, lfsck, obj, &lh,
-                             MDS_INODELOCK_UPDATE |
-                             MDS_INODELOCK_XATTR, LCK_EX);
+                             MDS_INODELOCK_UPDATE | MDS_INODELOCK_XATTR,
+                             LCK_EX);
        if (rc != 0)
                GOTO(log, rc);
 
@@ -1649,20 +1679,21 @@ static int lfsck_namespace_shrink_linkea_cond(const struct lu_env *env,
                                              struct lu_name *cname,
                                              struct lu_fid *pfid)
 {
-       struct lu_fid           *cfid   = &lfsck_env_info(env)->lti_fid3;
-       struct lustre_handle     lh     = { 0 };
-       int                      rc;
+       struct lfsck_thread_info *info  = lfsck_env_info(env);
+       struct lu_fid            *cfid  = &info->lti_fid3;
+       struct lfsck_lock_handle *llh   = &info->lti_llh;
+       int                       rc;
        ENTRY;
 
-       rc = lfsck_ibits_lock(env, com->lc_lfsck, parent, &lh,
-                             MDS_INODELOCK_UPDATE, LCK_EX);
+       rc = lfsck_lock(env, com->lc_lfsck, parent, cname->ln_name, llh,
+                       MDS_INODELOCK_UPDATE, LCK_PR);
        if (rc != 0)
                RETURN(rc);
 
        dt_read_lock(env, parent, 0);
        if (unlikely(lfsck_is_dead_obj(parent))) {
                dt_read_unlock(env, parent);
-               lfsck_ibits_unlock(&lh, LCK_EX);
+               lfsck_unlock(llh);
                rc = lfsck_namespace_shrink_linkea(env, com, child, ldata,
                                                   cname, pfid, true);
 
@@ -1681,7 +1712,7 @@ static int lfsck_namespace_shrink_linkea_cond(const struct lu_env *env,
         * has removed the specified linkEA entry by race, then it is OK,
         * because the subsequent lfsck_namespace_shrink_linkea() can handle
         * such case. */
-       lfsck_ibits_unlock(&lh, LCK_EX);
+       lfsck_unlock(llh);
        if (rc == -ENOENT) {
                rc = lfsck_namespace_shrink_linkea(env, com, child, ldata,
                                                   cname, pfid, true);
@@ -1745,7 +1776,7 @@ static int lfsck_namespace_replace_cond(const struct lu_env *env,
        const char                      *name   = cname->ln_name;
        struct dt_object                *pobj   = NULL;
        struct dt_object                *cobj   = NULL;
-       struct lustre_handle             plh    = { 0 };
+       struct lfsck_lock_handle        *pllh   = &info->lti_llh;
        struct lustre_handle             clh    = { 0 };
        struct linkea_data               ldata  = { NULL };
        struct thandle                  *th     = NULL;
@@ -1763,9 +1794,8 @@ static int lfsck_namespace_replace_cond(const struct lu_env *env,
        if (unlikely(!dt_try_as_dir(env, pobj)))
                GOTO(log, rc = -ENOTDIR);
 
-       /* Hold update lock on the pobj to prevent others to access. */
-       rc = lfsck_ibits_lock(env, lfsck, pobj, &plh,
-                             MDS_INODELOCK_UPDATE, LCK_EX);
+       rc = lfsck_lock(env, lfsck, parent, name, pllh,
+                       MDS_INODELOCK_UPDATE, LCK_PW);
        if (rc != 0)
                GOTO(log, rc);
 
@@ -1807,7 +1837,8 @@ static int lfsck_namespace_replace_cond(const struct lu_env *env,
        /* lock the object to be destroyed. */
        rc = lfsck_ibits_lock(env, lfsck, cobj, &clh,
                              MDS_INODELOCK_UPDATE |
-                             MDS_INODELOCK_XATTR, LCK_EX);
+                             MDS_INODELOCK_UPDATE | MDS_INODELOCK_XATTR,
+                             LCK_EX);
        if (rc != 0)
                GOTO(log, rc);
 
@@ -1900,7 +1931,7 @@ stop:
 
 log:
        lfsck_ibits_unlock(&clh, LCK_EX);
-       lfsck_ibits_unlock(&plh, LCK_EX);
+       lfsck_unlock(pllh);
 
        if (cobj != NULL && !IS_ERR(cobj))
                lfsck_object_put(env, cobj);
@@ -2016,21 +2047,27 @@ int lfsck_namespace_repair_dirent(const struct lu_env *env,
                                  const char *name, const char *name2,
                                  __u16 type, bool update, bool dec)
 {
-       struct dt_insert_rec    *rec    = &lfsck_env_info(env)->lti_dt_rec;
-       const struct lu_fid     *cfid   = lfsck_dto2fid(child);
-       struct lu_fid            tfid;
-       struct lfsck_instance   *lfsck  = com->lc_lfsck;
-       struct dt_device        *dev    = lfsck_obj2dev(parent);
-       struct thandle          *th     = NULL;
-       struct lustre_handle     lh     = { 0 };
-       int                      rc     = 0;
+       struct lfsck_thread_info        *info   = lfsck_env_info(env);
+       struct dt_insert_rec            *rec    = &info->lti_dt_rec;
+       const struct lu_fid             *cfid   = lfsck_dto2fid(child);
+       struct lu_fid                    tfid;
+       struct lfsck_instance           *lfsck  = com->lc_lfsck;
+       struct dt_device                *dev    = lfsck->li_next;
+       struct thandle                  *th     = NULL;
+       struct lfsck_lock_handle        *llh    = &info->lti_llh;
+       struct lustre_handle             lh     = { 0 };
+       int                              rc     = 0;
        ENTRY;
 
        if (unlikely(!dt_try_as_dir(env, parent)))
                GOTO(log, rc = -ENOTDIR);
 
-       rc = lfsck_ibits_lock(env, lfsck, parent, &lh,
-                             MDS_INODELOCK_UPDATE, LCK_EX);
+       if (!update || strcmp(name, name2) == 0)
+               rc = lfsck_lock(env, lfsck, parent, name, llh,
+                               MDS_INODELOCK_UPDATE, LCK_PW);
+       else
+               rc = lfsck_ibits_lock(env, lfsck, parent, &lh,
+                                     MDS_INODELOCK_UPDATE, LCK_PW);
        if (rc != 0)
                GOTO(log, rc);
 
@@ -2116,7 +2153,9 @@ stop:
                                             LNTF_CHECK_LINKEA, true);
 
 unlock1:
-       lfsck_ibits_unlock(&lh, LCK_EX);
+       /* It is harmless even if unlock the unused lock_handle */
+       lfsck_ibits_unlock(&lh, LCK_PW);
+       lfsck_unlock(llh);
 
 log:
        CDEBUG(D_LFSCK, "%s: namespace LFSCK assistant found bad name "
@@ -2886,8 +2925,7 @@ static int lfsck_namespace_repair_nlink(const struct lu_env *env,
        LASSERT(S_ISREG(lfsck_object_type(obj)));
 
        rc = lfsck_ibits_lock(env, lfsck, obj, &lh,
-                             MDS_INODELOCK_UPDATE |
-                             MDS_INODELOCK_XATTR, LCK_EX);
+                             MDS_INODELOCK_UPDATE, LCK_PW);
        if (rc != 0)
                GOTO(log, rc);
 
@@ -2953,7 +2991,7 @@ stop:
        dt_trans_stop(env, dev, th);
 
 log:
-       lfsck_ibits_unlock(&lh, LCK_EX);
+       lfsck_ibits_unlock(&lh, LCK_PW);
        CDEBUG(D_LFSCK, "%s: namespace LFSCK repaired the object "DFID"'s "
               "nlink count from %u to %u: rc = %d\n",
               lfsck_lfsck2name(lfsck), PFID(cfid), old, la->la_nlink, rc);
@@ -4733,7 +4771,7 @@ int lfsck_namespace_repair_dangling(const struct lu_env *env,
        struct dt_object                *cobj   = NULL;
        const struct lu_name            *cname;
        struct linkea_data               ldata  = { NULL };
-       struct lustre_handle             lh     = { 0 };
+       struct lfsck_lock_handle        *llh    = &info->lti_llh;
        struct lu_buf                    linkea_buf;
        struct lu_buf                    lmv_buf;
        struct lfsck_instance           *lfsck  = com->lc_lfsck;
@@ -4776,8 +4814,8 @@ int lfsck_namespace_repair_dangling(const struct lu_env *env,
        if (rc != 0)
                GOTO(log, rc);
 
-       rc = lfsck_ibits_lock(env, lfsck, pobj, &lh,
-                             MDS_INODELOCK_UPDATE, LCK_EX);
+       rc = lfsck_lock(env, lfsck, parent, lnr->lnr_name, llh,
+                       MDS_INODELOCK_UPDATE, LCK_PR);
        if (rc != 0)
                GOTO(log, rc);
 
@@ -4923,7 +4961,7 @@ stop:
        dt_trans_stop(env, dev, th);
 
 log:
-       lfsck_ibits_unlock(&lh, LCK_EX);
+       lfsck_unlock(llh);
        CDEBUG(D_LFSCK, "%s: namespace LFSCK assistant found dangling "
               "reference for: parent "DFID", child "DFID", type %u, "
               "name %s. %s: rc = %d\n", lfsck_lfsck2name(lfsck),
@@ -6317,16 +6355,17 @@ int lfsck_update_name_entry(const struct lu_env *env,
                            struct dt_object *dir, const char *name,
                            const struct lu_fid *fid, __u32 type)
 {
-       struct dt_insert_rec    *rec    = &lfsck_env_info(env)->lti_dt_rec;
-       struct dt_device        *dev    = lfsck_obj2dev(dir);
-       struct lustre_handle     lh     = { 0 };
-       struct thandle          *th;
-       int                      rc;
-       bool                     exists = true;
+       struct lfsck_thread_info *info   = lfsck_env_info(env);
+       struct dt_insert_rec     *rec    = &info->lti_dt_rec;
+       struct lfsck_lock_handle *llh    = &info->lti_llh;
+       struct dt_device         *dev    = lfsck_obj2dev(dir);
+       struct thandle           *th;
+       int                       rc;
+       bool                      exists = true;
        ENTRY;
 
-       rc = lfsck_ibits_lock(env, lfsck, dir, &lh,
-                             MDS_INODELOCK_UPDATE, LCK_EX);
+       rc = lfsck_lock(env, lfsck, dir, name, llh,
+                       MDS_INODELOCK_UPDATE, LCK_PW);
        if (rc != 0)
                RETURN(rc);
 
@@ -6377,7 +6416,7 @@ stop:
        dt_trans_stop(env, dev, th);
 
 unlock:
-       lfsck_ibits_unlock(&lh, LCK_EX);
+       lfsck_unlock(llh);
        CDEBUG(D_LFSCK, "%s: update name entry "DFID"/%s with the FID "DFID
               " and the type %o: rc = %d\n", lfsck_lfsck2name(lfsck),
               PFID(lfsck_dto2fid(dir)), name, PFID(fid), type, rc);