Whamcloud - gitweb
Revert "b=19808 2.6.29-fc11 patchless client support"
[fs/lustre-release.git] / lustre / obdclass / cl_object.c
index 98f7c09..3d6ef8c 100644 (file)
@@ -60,6 +60,7 @@
 #include <obd_support.h>
 #include <lustre_fid.h>
 #include <libcfs/list.h>
+#include <libcfs/libcfs_hash.h> /* for cfs_hash stuff */
 /* lu_time_global_{init,fini}() */
 #include <lu_time.h>
 
@@ -223,7 +224,7 @@ int cl_object_attr_get(const struct lu_env *env, struct cl_object *obj,
         struct lu_object_header *top;
         int result;
 
-        LASSERT(spin_is_locked(cl_object_attr_guard(obj)));
+        LASSERT_SPIN_LOCKED(cl_object_attr_guard(obj));
         ENTRY;
 
         top = obj->co_lu.lo_header;
@@ -255,7 +256,7 @@ int cl_object_attr_set(const struct lu_env *env, struct cl_object *obj,
         struct lu_object_header *top;
         int result;
 
-        LASSERT(spin_is_locked(cl_object_attr_guard(obj)));
+        LASSERT_SPIN_LOCKED(cl_object_attr_guard(obj));
         ENTRY;
 
         top = obj->co_lu.lo_header;
@@ -298,7 +299,7 @@ int cl_object_glimpse(const struct lu_env *env, struct cl_object *obj,
                                 break;
                 }
         }
-        LU_OBJECT_HEADER(D_DLMTRACE, env, &obj->co_lu,
+        LU_OBJECT_HEADER(D_DLMTRACE, env, lu_object_top(top),
                          "size: "LPU64" mtime: "LPU64" atime: "LPU64" "
                          "ctime: "LPU64" blocks: "LPU64"\n",
                          lvb->lvb_size, lvb->lvb_mtime, lvb->lvb_atime,
@@ -369,6 +370,22 @@ void cl_object_prune(const struct lu_env *env, struct cl_object *obj)
 }
 EXPORT_SYMBOL(cl_object_prune);
 
+/**
+ * Check if the object has locks.
+ */
+int cl_object_has_locks(struct cl_object *obj)
+{
+        struct cl_object_header *head = cl_object_header(obj);
+        int has;
+
+        spin_lock(&head->coh_lock_guard);
+        has = list_empty(&head->coh_locks);
+        spin_unlock(&head->coh_lock_guard);
+
+        return (has == 0);
+}
+EXPORT_SYMBOL(cl_object_has_locks);
+
 void cache_stats_init(struct cache_stats *cs, const char *name)
 {
         cs->cs_name = name;
@@ -463,7 +480,7 @@ int cl_site_stats_print(const struct cl_site *site, char *page, int count)
                 [CLS_QUEUING]   = "q",
                 [CLS_ENQUEUED]  = "e",
                 [CLS_HELD]      = "h",
-                [CLS_UNLOCKING] = "u",
+                [CLS_INTRANSIT] = "t",
                 [CLS_CACHED]    = "c",
                 [CLS_FREEING]   = "f"
         };
@@ -500,13 +517,6 @@ EXPORT_SYMBOL(cl_site_stats_print);
  *
  */
 
-/*
- * TBD: Description.
- *
- * XXX: this assumes that re-entrant file system calls (e.g., ->writepage())
- * do not modify already existing current->journal_info.
- */
-
 static CFS_LIST_HEAD(cl_envs);
 static unsigned cl_envs_cached_nr  = 0;
 static unsigned cl_envs_cached_max = 128; /* XXX: prototype: arbitrary limit
@@ -517,6 +527,16 @@ struct cl_env {
         void             *ce_magic;
         struct lu_env     ce_lu;
         struct lu_context ce_ses;
+        /**
+         * This allows cl_env to be entered into cl_env_hash which implements
+         * the current thread -> client environment lookup.
+         */
+        struct hlist_node ce_node;
+        /**
+         * Owner for the current cl_env, the key for cfs_hash.
+         * Now current thread pointer is stored.
+         */
+        void             *ce_owner;
         /*
          * Linkage into global list of all client environments. Used for
          * garbage collection.
@@ -526,13 +546,11 @@ struct cl_env {
          *
          */
         int               ce_ref;
-        void             *ce_prev;
         /*
          * Debugging field: address of the caller who made original
          * allocation.
          */
         void             *ce_debug;
-        void             *ce_owner;
 };
 
 #define CL_ENV_INC(counter) atomic_inc(&cl_env_stats.counter)
@@ -543,6 +561,83 @@ struct cl_env {
                 atomic_dec(&cl_env_stats.counter);                      \
         } while (0)
 
+/*****************************************************************************
+ * Routins to use cfs_hash functionality to bind the current thread
+ * to cl_env
+ */
+
+/** lustre hash to manage the cl_env for current thread */
+static cfs_hash_t *cl_env_hash;
+static void cl_env_init0(struct cl_env *cle, void *debug);
+
+static unsigned cl_env_hops_hash(cfs_hash_t *lh, void *key, unsigned mask)
+{
+#if BITS_PER_LONG == 64
+        return cfs_hash_u64_hash((__u64)key, mask);
+#else
+        return cfs_hash_u32_hash((__u32)key, mask);
+#endif
+}
+
+static void *cl_env_hops_obj(struct hlist_node *hn)
+{
+        struct cl_env *cle = hlist_entry(hn, struct cl_env, ce_node);
+        LASSERT(cle->ce_magic == &cl_env_init0);
+        return (void *)cle;
+}
+
+static int cl_env_hops_compare(void *key, struct hlist_node *hn)
+{
+        struct cl_env *cle = cl_env_hops_obj(hn);
+
+        LASSERT(cle->ce_owner != NULL);
+        return (key == cle->ce_owner);
+}
+
+static cfs_hash_ops_t cl_env_hops = {
+        .hs_hash    = cl_env_hops_hash,
+        .hs_compare = cl_env_hops_compare,
+        .hs_key     = cl_env_hops_obj,
+        .hs_get     = cl_env_hops_obj,
+        .hs_put     = cl_env_hops_obj,
+};
+
+static inline struct cl_env *cl_env_fetch(void)
+{
+        struct cl_env *cle;
+        cle = cfs_hash_lookup(cl_env_hash, cfs_current());
+        LASSERT(ergo(cle, cle->ce_magic == &cl_env_init0));
+        return cle;
+}
+
+static inline void cl_env_attach(struct cl_env *cle)
+{
+        if (cle) {
+                int rc;
+                LASSERT(cle->ce_owner == NULL);
+                cle->ce_owner = cfs_current();
+                rc = cfs_hash_add_unique(cl_env_hash, cle->ce_owner,
+                                            &cle->ce_node);
+                LASSERT(rc == 0);
+        }
+}
+
+static inline struct cl_env *cl_env_detach(struct cl_env *cle)
+{
+        if (cle == NULL)
+                cle = cl_env_fetch();
+        if (cle && cle->ce_owner) {
+                void *cookie;
+                LASSERT(cle->ce_owner == cfs_current());
+                cookie = cfs_hash_del(cl_env_hash, cle->ce_owner,
+                                         &cle->ce_node);
+                cle->ce_owner = NULL;
+                LASSERT(cookie == cle);
+        }
+        return cle;
+}
+/* ----------------------- hash routines end ---------------------------- */
+
 static void cl_env_init0(struct cl_env *cle, void *debug)
 {
         LASSERT(cle->ce_ref == 0);
@@ -550,10 +645,7 @@ static void cl_env_init0(struct cl_env *cle, void *debug)
         LASSERT(cle->ce_debug == NULL && cle->ce_owner == NULL);
 
         cle->ce_ref = 1;
-        cle->ce_prev = current->journal_info;
         cle->ce_debug = debug;
-        cle->ce_owner = current;
-        current->journal_info = cle;
         CL_ENV_INC(cs_busy);
 }
 
@@ -562,7 +654,7 @@ static struct lu_env *cl_env_new(__u32 tags, void *debug)
         struct lu_env *env;
         struct cl_env *cle;
 
-        OBD_SLAB_ALLOC_PTR(cle, cl_env_kmem);
+        OBD_SLAB_ALLOC_PTR_GFP(cle, cl_env_kmem, CFS_ALLOC_IO);
         if (cle != NULL) {
                 int rc;
 
@@ -648,8 +740,8 @@ struct lu_env *cl_env_peek(int *refcheck)
         CLASSERT(offsetof(struct cl_env, ce_magic) == 0);
 
         env = NULL;
-        cle = current->journal_info;
-        if (cle != NULL && cle->ce_magic == &cl_env_init0) {
+        cle = cl_env_fetch();
+        if (cle != NULL) {
                 CL_ENV_INC(cs_hit);
                 env = &cle->ce_lu;
                 *refcheck = ++cle->ce_ref;
@@ -683,6 +775,7 @@ struct lu_env *cl_env_get(int *refcheck)
                         struct cl_env *cle;
 
                         cle = cl_env_container(env);
+                        cl_env_attach(cle);
                         *refcheck = cle->ce_ref;
                         CDEBUG(D_OTHER, "%i@%p\n", cle->ce_ref, cle);
                 }
@@ -715,6 +808,7 @@ EXPORT_SYMBOL(cl_env_alloc);
 
 static void cl_env_exit(struct cl_env *cle)
 {
+        LASSERT(cle->ce_owner == NULL);
         lu_context_exit(&cle->ce_lu.le_ctx);
         lu_context_exit(&cle->ce_ses);
 }
@@ -765,12 +859,8 @@ void cl_env_put(struct lu_env *env, int *refcheck)
         CDEBUG(D_OTHER, "%i@%p\n", cle->ce_ref, cle);
         if (--cle->ce_ref == 0) {
                 CL_ENV_DEC(cs_busy);
-                current->journal_info = cle->ce_prev;
-                LASSERT(cle->ce_prev == NULL ||
-                        cl_env_container(cle->ce_prev)->ce_magic !=
-                        &cl_env_init0);
+                cl_env_detach(cle);
                 cle->ce_debug = NULL;
-                cle->ce_owner = NULL;
                 cl_env_exit(cle);
                 /*
                  * Don't bother to take a lock here.
@@ -794,36 +884,21 @@ EXPORT_SYMBOL(cl_env_put);
 /**
  * Declares a point of re-entrancy.
  *
- * In Linux kernel environments are attached to the thread through
- * current->journal_info pointer that is used by other sub-systems also. When
- * lustre code is invoked in the situation where current->journal_info is
- * potentially already set, cl_env_reenter() is called to save
- * current->journal_info value, so that current->journal_info field can be
- * used to store pointer to the environment.
- *
  * \see cl_env_reexit()
  */
 void *cl_env_reenter(void)
 {
-        void *cookie;
-
-        cookie = current->journal_info;
-        current->journal_info = NULL;
-        CDEBUG(D_OTHER, "cookie: %p\n", cookie);
-        return cookie;
+        return cl_env_detach(NULL);
 }
 EXPORT_SYMBOL(cl_env_reenter);
 
 /**
  * Exits re-entrancy.
- *
- * This restores old value of current->journal_info that was saved by
- * cl_env_reenter().
  */
 void cl_env_reexit(void *cookie)
 {
-        current->journal_info = cookie;
-        CDEBUG(D_OTHER, "cookie: %p\n", cookie);
+        cl_env_detach(NULL);
+        cl_env_attach(cookie);
 }
 EXPORT_SYMBOL(cl_env_reexit);
 
@@ -838,10 +913,9 @@ void cl_env_implant(struct lu_env *env, int *refcheck)
 {
         struct cl_env *cle = cl_env_container(env);
 
-        LASSERT(current->journal_info == NULL);
         LASSERT(cle->ce_ref > 0);
 
-        current->journal_info = cle;
+        cl_env_attach(cle);
         cl_env_get(refcheck);
         CDEBUG(D_OTHER, "%i@%p\n", cle->ce_ref, cle);
 }
@@ -854,13 +928,12 @@ void cl_env_unplant(struct lu_env *env, int *refcheck)
 {
         struct cl_env *cle = cl_env_container(env);
 
-        LASSERT(cle == current->journal_info);
         LASSERT(cle->ce_ref > 1);
 
         CDEBUG(D_OTHER, "%i@%p\n", cle->ce_ref, cle);
 
+        cl_env_detach(cle);
         cl_env_put(env, refcheck);
-        current->journal_info = NULL;
 }
 EXPORT_SYMBOL(cl_env_unplant);
 
@@ -879,7 +952,12 @@ struct lu_env *cl_env_nested_get(struct cl_env_nest *nest)
                 }
         }
         env = cl_env_get(&nest->cen_refcheck);
-        LASSERT(ergo(!IS_ERR(env), !cl_io_is_going(env)));
+        if (IS_ERR(env)) {
+                cl_env_reexit(nest->cen_cookie);
+                return env;
+        }
+
+        LASSERT(!cl_io_is_going(env));
         return env;
 }
 EXPORT_SYMBOL(cl_env_nested_get);
@@ -925,7 +1003,6 @@ void cl_lvb2attr(struct cl_attr *attr, const struct ost_lvb *lvb)
 }
 EXPORT_SYMBOL(cl_lvb2attr);
 
-
 /*****************************************************************************
  *
  * Temporary prototype thing: mirror obd-devices into cl devices.
@@ -995,8 +1072,12 @@ static void *cl_key_init(const struct lu_context *ctx,
         struct cl_thread_info *info;
 
         info = cl0_key_init(ctx, key);
-        if (!IS_ERR(info))
-                lu_ref_init(&info->clt_locks_locked);
+        if (!IS_ERR(info)) {
+                int i;
+
+                for (i = 0; i < ARRAY_SIZE(info->clt_counters); ++i)
+                        lu_ref_init(&info->clt_counters[i].ctc_locks_locked);
+        }
         return info;
 }
 
@@ -1004,9 +1085,11 @@ static void cl_key_fini(const struct lu_context *ctx,
                         struct lu_context_key *key, void *data)
 {
         struct cl_thread_info *info;
+        int i;
 
         info = data;
-        lu_ref_fini(&info->clt_locks_locked);
+        for (i = 0; i < ARRAY_SIZE(info->clt_counters); ++i)
+                lu_ref_fini(&info->clt_counters[i].ctc_locks_locked);
         cl0_key_fini(ctx, key, data);
 }
 
@@ -1014,14 +1097,16 @@ static void cl_key_exit(const struct lu_context *ctx,
                         struct lu_context_key *key, void *data)
 {
         struct cl_thread_info *info = data;
+        int i;
 
-        LASSERT(info->clt_nr_locks_locked == 0);
-        LASSERT(info->clt_nr_held == 0);
-        LASSERT(info->clt_nr_used == 0);
-        LASSERT(info->clt_nr_locks_acquired == 0);
-
-        lu_ref_fini(&info->clt_locks_locked);
-        lu_ref_init(&info->clt_locks_locked);
+        for (i = 0; i < ARRAY_SIZE(info->clt_counters); ++i) {
+                LASSERT(info->clt_counters[i].ctc_nr_held == 0);
+                LASSERT(info->clt_counters[i].ctc_nr_used == 0);
+                LASSERT(info->clt_counters[i].ctc_nr_locks_acquired == 0);
+                LASSERT(info->clt_counters[i].ctc_nr_locks_locked == 0);
+                lu_ref_fini(&info->clt_counters[i].ctc_locks_locked);
+                lu_ref_init(&info->clt_counters[i].ctc_locks_locked);
+        }
 }
 
 static struct lu_context_key cl_key = {
@@ -1052,6 +1137,11 @@ int cl_global_init(void)
 {
         int result;
 
+        cl_env_hash = cfs_hash_create("cl_env", 8, 10, &cl_env_hops,
+                                      CFS_HASH_REHASH);
+        if (cl_env_hash == NULL)
+                return -ENOMEM;
+
         result = lu_kmem_init(cl_object_caches);
         if (result == 0) {
                 LU_CONTEXT_KEY_INIT(&cl_key);
@@ -1062,6 +1152,8 @@ int cl_global_init(void)
                                 result = cl_page_init();
                 }
         }
+        if (result)
+                cfs_hash_destroy(cl_env_hash);
         return result;
 }
 
@@ -1074,4 +1166,5 @@ void cl_global_fini(void)
         cl_page_fini();
         lu_context_key_degister(&cl_key);
         lu_kmem_fini(cl_object_caches);
+        cfs_hash_destroy(cl_env_hash);
 }