Whamcloud - gitweb
LU-12017 ldlm: DoM truncate deadlock
[fs/lustre-release.git] / lustre / ldlm / ldlm_resource.c
index 311d2aa..baf935e 100644 (file)
@@ -43,6 +43,7 @@
 
 struct kmem_cache *ldlm_resource_slab, *ldlm_lock_slab;
 struct kmem_cache *ldlm_interval_tree_slab;
+struct kmem_cache *ldlm_inodebits_slab;
 
 int ldlm_srv_namespace_nr = 0;
 int ldlm_cli_namespace_nr = 0;
@@ -1401,29 +1402,59 @@ struct ldlm_namespace *ldlm_namespace_first_locked(enum ldlm_side client)
                            struct ldlm_namespace, ns_list_chain);
 }
 
+static bool ldlm_resource_extent_new(struct ldlm_resource *res)
+{
+       int idx;
+
+       OBD_SLAB_ALLOC(res->lr_itree, ldlm_interval_tree_slab,
+                      sizeof(*res->lr_itree) * LCK_MODE_NUM);
+       if (res->lr_itree == NULL)
+               return false;
+       /* Initialize interval trees for each lock mode. */
+       for (idx = 0; idx < LCK_MODE_NUM; idx++) {
+               res->lr_itree[idx].lit_size = 0;
+               res->lr_itree[idx].lit_mode = 1 << idx;
+               res->lr_itree[idx].lit_root = NULL;
+       }
+       return true;
+}
+
+static bool ldlm_resource_inodebits_new(struct ldlm_resource *res)
+{
+       int i;
+
+       OBD_ALLOC_PTR(res->lr_ibits_queues);
+       if (res->lr_ibits_queues == NULL)
+               return false;
+       for (i = 0; i < MDS_INODELOCK_NUMBITS; i++)
+               INIT_LIST_HEAD(&res->lr_ibits_queues->liq_waiting[i]);
+       return true;
+}
+
 /** Create and initialize new resource. */
 static struct ldlm_resource *ldlm_resource_new(enum ldlm_type ldlm_type)
 {
        struct ldlm_resource *res;
-       int idx;
+       bool rc;
 
        OBD_SLAB_ALLOC_PTR_GFP(res, ldlm_resource_slab, GFP_NOFS);
        if (res == NULL)
                return NULL;
 
-       if (ldlm_type == LDLM_EXTENT) {
-               OBD_SLAB_ALLOC(res->lr_itree, ldlm_interval_tree_slab,
-                              sizeof(*res->lr_itree) * LCK_MODE_NUM);
-               if (res->lr_itree == NULL) {
-                       OBD_SLAB_FREE_PTR(res, ldlm_resource_slab);
-                       return NULL;
-               }
-               /* Initialize interval trees for each lock mode. */
-               for (idx = 0; idx < LCK_MODE_NUM; idx++) {
-                       res->lr_itree[idx].lit_size = 0;
-                       res->lr_itree[idx].lit_mode = 1 << idx;
-                       res->lr_itree[idx].lit_root = NULL;
-               }
+       switch (ldlm_type) {
+       case LDLM_EXTENT:
+               rc = ldlm_resource_extent_new(res);
+               break;
+       case LDLM_IBITS:
+               rc = ldlm_resource_inodebits_new(res);
+               break;
+       default:
+               rc = true;
+               break;
+       }
+       if (!rc) {
+               OBD_SLAB_FREE_PTR(res, ldlm_resource_slab);
+               return NULL;
        }
 
        INIT_LIST_HEAD(&res->lr_granted);
@@ -1441,6 +1472,20 @@ static struct ldlm_resource *ldlm_resource_new(enum ldlm_type ldlm_type)
        return res;
 }
 
+static void ldlm_resource_free(struct ldlm_resource *res)
+{
+       if (res->lr_type == LDLM_EXTENT) {
+               if (res->lr_itree != NULL)
+                       OBD_SLAB_FREE(res->lr_itree, ldlm_interval_tree_slab,
+                                     sizeof(*res->lr_itree) * LCK_MODE_NUM);
+       } else if (res->lr_type == LDLM_IBITS) {
+               if (res->lr_ibits_queues != NULL)
+                       OBD_FREE_PTR(res->lr_ibits_queues);
+       }
+
+       OBD_SLAB_FREE(res, ldlm_resource_slab, sizeof *res);
+}
+
 /**
  * Return a reference to resource with given name, creating it if necessary.
  * Args: namespace with ns_lock unlocked
@@ -1495,10 +1540,7 @@ ldlm_resource_get(struct ldlm_namespace *ns, struct ldlm_resource *parent,
                cfs_hash_bd_unlock(ns->ns_rs_hash, &bd, 1);
                /* Clean lu_ref for failed resource. */
                lu_ref_fini(&res->lr_reference);
-               if (res->lr_itree != NULL)
-                       OBD_SLAB_FREE(res->lr_itree, ldlm_interval_tree_slab,
-                                     sizeof(*res->lr_itree) * LCK_MODE_NUM);
-               OBD_SLAB_FREE(res, ldlm_resource_slab, sizeof *res);
+               ldlm_resource_free(res);
 found:
                res = hlist_entry(hnode, struct ldlm_resource, lr_hash);
                return res;
@@ -1574,10 +1616,7 @@ int ldlm_resource_putref(struct ldlm_resource *res)
                cfs_hash_bd_unlock(ns->ns_rs_hash, &bd, 1);
                if (ns->ns_lvbo && ns->ns_lvbo->lvbo_free)
                        ns->ns_lvbo->lvbo_free(res);
-               if (res->lr_itree != NULL)
-                       OBD_SLAB_FREE(res->lr_itree, ldlm_interval_tree_slab,
-                                     sizeof(*res->lr_itree) * LCK_MODE_NUM);
-               OBD_SLAB_FREE(res, ldlm_resource_slab, sizeof *res);
+               ldlm_resource_free(res);
                return 1;
        }
        return 0;
@@ -1602,6 +1641,9 @@ void ldlm_resource_add_lock(struct ldlm_resource *res, struct list_head *head,
        LASSERT(list_empty(&lock->l_res_link));
 
        list_add_tail(&lock->l_res_link, head);
+
+       if (res->lr_type == LDLM_IBITS)
+               ldlm_inodebits_add_lock(res, head, lock);
 }
 
 /**
@@ -1635,10 +1677,17 @@ void ldlm_resource_unlink_lock(struct ldlm_lock *lock)
        int type = lock->l_resource->lr_type;
 
        check_res_locked(lock->l_resource);
-       if (type == LDLM_IBITS || type == LDLM_PLAIN)
+       switch (type) {
+       case LDLM_PLAIN:
                ldlm_unlink_lock_skiplist(lock);
-       else if (type == LDLM_EXTENT)
+               break;
+       case LDLM_EXTENT:
                ldlm_extent_unlink_lock(lock);
+               break;
+       case LDLM_IBITS:
+               ldlm_inodebits_unlink_lock(lock);
+               break;
+       }
        list_del_init(&lock->l_res_link);
 }
 EXPORT_SYMBOL(ldlm_resource_unlink_lock);