Whamcloud - gitweb
LU-11089 obd: rename lu_keys_guard to lu_context_remembered_guard
[fs/lustre-release.git] / lustre / obdclass / lu_object.c
index 3ddade9..fbe034a 100644 (file)
@@ -133,22 +133,18 @@ EXPORT_SYMBOL(lu_site_wq_from_fid);
 void lu_object_put(const struct lu_env *env, struct lu_object *o)
 {
        struct lu_site_bkt_data *bkt;
-       struct lu_object_header *top;
-       struct lu_site *site;
-       struct lu_object *orig;
+       struct lu_object_header *top = o->lo_header;
+       struct lu_site *site = o->lo_dev->ld_site;
+       struct lu_object *orig = o;
        struct cfs_hash_bd bd;
-       const struct lu_fid *fid;
-
-       top  = o->lo_header;
-       site = o->lo_dev->ld_site;
-       orig = o;
+       const struct lu_fid *fid = lu_object_fid(o);
+       bool is_dying;
 
        /*
         * till we have full fids-on-OST implemented anonymous objects
         * are possible in OSP. such an object isn't listed in the site
         * so we should not remove it from the site.
         */
-       fid = lu_object_fid(o);
        if (fid_is_zero(fid)) {
                LASSERT(top->loh_hash.next == NULL
                        && top->loh_hash.pprev == NULL);
@@ -166,8 +162,14 @@ void lu_object_put(const struct lu_env *env, struct lu_object *o)
        cfs_hash_bd_get(site->ls_obj_hash, &top->loh_fid, &bd);
        bkt = cfs_hash_bd_extra_get(site->ls_obj_hash, &bd);
 
+       is_dying = lu_object_is_dying(top);
        if (!cfs_hash_bd_dec_and_lock(site->ls_obj_hash, &bd, &top->loh_ref)) {
-               if (lu_object_is_dying(top)) {
+               /* at this point the object reference is dropped and lock is
+                * not taken, so lu_object should not be touched because it
+                * can be freed by concurrent thread. Use local variable for
+                * check.
+                */
+               if (is_dying) {
                        /*
                         * somebody may be waiting for this, currently only
                         * used for cl_object, see cl_object_put_last().
@@ -186,6 +188,10 @@ void lu_object_put(const struct lu_env *env, struct lu_object *o)
                        o->lo_ops->loo_object_release(env, o);
        }
 
+       /* don't use local 'is_dying' here because if was taken without lock
+        * but here we need the latest actual value of it so check lu_object
+        * directly here.
+        */
        if (!lu_object_is_dying(top) &&
            (lu_object_exists(orig) || lu_object_is_cl(orig))) {
                LASSERT(list_empty(&top->loh_lru));
@@ -1345,7 +1351,6 @@ enum {
 
 static struct lu_context_key *lu_keys[LU_CONTEXT_KEY_NR] = { NULL, };
 
-DEFINE_RWLOCK(lu_keys_guard);
 static DECLARE_RWSEM(lu_key_initing);
 
 /**
@@ -1370,19 +1375,23 @@ int lu_context_key_register(struct lu_context_key *key)
         LASSERT(key->lct_owner != NULL);
 
         result = -ENFILE;
-       write_lock(&lu_keys_guard);
+       atomic_set(&key->lct_used, 1);
+       lu_ref_init(&key->lct_reference);
         for (i = 0; i < ARRAY_SIZE(lu_keys); ++i) {
-                if (lu_keys[i] == NULL) {
-                        key->lct_index = i;
-                       atomic_set(&key->lct_used, 1);
-                        lu_keys[i] = key;
-                        lu_ref_init(&key->lct_reference);
-                        result = 0;
-                       atomic_inc(&key_set_version);
-                        break;
-                }
+               if (lu_keys[i])
+                       continue;
+               key->lct_index = i;
+               if (cmpxchg(&lu_keys[i], NULL, key) != NULL)
+                       continue;
+
+               result = 0;
+               atomic_inc(&key_set_version);
+               break;
         }
-       write_unlock(&lu_keys_guard);
+       if (result) {
+               lu_ref_fini(&key->lct_reference);
+               atomic_set(&key->lct_used, 0);
+       }
        return result;
 }
 EXPORT_SYMBOL(lu_context_key_register);
@@ -1395,7 +1404,7 @@ static void key_fini(struct lu_context *ctx, int index)
                 key = lu_keys[index];
                 LASSERT(key != NULL);
                 LASSERT(key->lct_fini != NULL);
-               LASSERT(atomic_read(&key->lct_used) > 1);
+               LASSERT(atomic_read(&key->lct_used) > 0);
 
                 key->lct_fini(ctx, key, ctx->lc_value[index]);
                 lu_ref_del(&key->lct_reference, "ctx", ctx);
@@ -1430,16 +1439,10 @@ void lu_context_key_degister(struct lu_context_key *key)
        atomic_dec(&key->lct_used);
        wait_var_event(&key->lct_used, atomic_read(&key->lct_used) == 0);
 
-       write_lock(&lu_keys_guard);
-       if (lu_keys[key->lct_index]) {
-               lu_keys[key->lct_index] = NULL;
+       if (!WARN_ON(lu_keys[key->lct_index] == NULL))
                lu_ref_fini(&key->lct_reference);
-       }
-       write_unlock(&lu_keys_guard);
 
-       LASSERTF(atomic_read(&key->lct_used) == 0,
-                "key has instances: %d\n",
-                atomic_read(&key->lct_used));
+       smp_store_release(&lu_keys[key->lct_index], NULL);
 }
 EXPORT_SYMBOL(lu_context_key_degister);
 
@@ -1541,6 +1544,7 @@ EXPORT_SYMBOL(lu_context_key_get);
  * List of remembered contexts. XXX document me.
  */
 static LIST_HEAD(lu_context_remembered);
+static DEFINE_SPINLOCK(lu_context_remembered_guard);
 
 /**
  * Destroy \a key in all remembered contexts. This is used to destroy key
@@ -1561,13 +1565,13 @@ void lu_context_key_quiesce(struct lu_context_key *key)
                key->lct_tags |= LCT_QUIESCENT;
                up_write(&lu_key_initing);
 
-               write_lock(&lu_keys_guard);
+               spin_lock(&lu_context_remembered_guard);
                list_for_each_entry(ctx, &lu_context_remembered, lc_remember) {
                        spin_until_cond(READ_ONCE(ctx->lc_state) != LCS_LEAVING);
                        key_fini(ctx, key->lct_index);
                }
 
-               write_unlock(&lu_keys_guard);
+               spin_unlock(&lu_context_remembered_guard);
        }
 }
 
@@ -1673,9 +1677,9 @@ int lu_context_init(struct lu_context *ctx, __u32 tags)
        ctx->lc_state = LCS_INITIALIZED;
        ctx->lc_tags = tags;
        if (tags & LCT_REMEMBER) {
-               write_lock(&lu_keys_guard);
+               spin_lock(&lu_context_remembered_guard);
                list_add(&ctx->lc_remember, &lu_context_remembered);
-               write_unlock(&lu_keys_guard);
+               spin_unlock(&lu_context_remembered_guard);
        } else {
                INIT_LIST_HEAD(&ctx->lc_remember);
        }
@@ -1698,14 +1702,13 @@ void lu_context_fini(struct lu_context *ctx)
 
        if ((ctx->lc_tags & LCT_REMEMBER) == 0) {
                LASSERT(list_empty(&ctx->lc_remember));
-               keys_fini(ctx);
-
-       } else { /* could race with key degister */
-               write_lock(&lu_keys_guard);
-               keys_fini(ctx);
+       } else {
+               /* could race with key degister */
+               spin_lock(&lu_context_remembered_guard);
                list_del_init(&ctx->lc_remember);
-               write_unlock(&lu_keys_guard);
+               spin_unlock(&lu_context_remembered_guard);
        }
+       keys_fini(ctx);
 }
 EXPORT_SYMBOL(lu_context_fini);
 
@@ -1784,37 +1787,37 @@ u32 lu_session_tags_default;
 #ifdef HAVE_SERVER_SUPPORT
 void lu_context_tags_update(__u32 tags)
 {
-       write_lock(&lu_keys_guard);
+       spin_lock(&lu_context_remembered_guard);
        lu_context_tags_default |= tags;
        atomic_inc(&key_set_version);
-       write_unlock(&lu_keys_guard);
+       spin_unlock(&lu_context_remembered_guard);
 }
 EXPORT_SYMBOL(lu_context_tags_update);
 
 void lu_context_tags_clear(__u32 tags)
 {
-       write_lock(&lu_keys_guard);
+       spin_lock(&lu_context_remembered_guard);
        lu_context_tags_default &= ~tags;
        atomic_inc(&key_set_version);
-       write_unlock(&lu_keys_guard);
+       spin_unlock(&lu_context_remembered_guard);
 }
 EXPORT_SYMBOL(lu_context_tags_clear);
 
 void lu_session_tags_update(__u32 tags)
 {
-       write_lock(&lu_keys_guard);
+       spin_lock(&lu_context_remembered_guard);
        lu_session_tags_default |= tags;
        atomic_inc(&key_set_version);
-       write_unlock(&lu_keys_guard);
+       spin_unlock(&lu_context_remembered_guard);
 }
 EXPORT_SYMBOL(lu_session_tags_update);
 
 void lu_session_tags_clear(__u32 tags)
 {
-       write_lock(&lu_keys_guard);
+       spin_lock(&lu_context_remembered_guard);
        lu_session_tags_default &= ~tags;
        atomic_inc(&key_set_version);
-       write_unlock(&lu_keys_guard);
+       spin_unlock(&lu_context_remembered_guard);
 }
 EXPORT_SYMBOL(lu_session_tags_clear);
 #endif /* HAVE_SERVER_SUPPORT */