Whamcloud - gitweb
LU-5092 nodemap: convert member hash to a list
[fs/lustre-release.git] / lustre / ptlrpc / nodemap_member.c
index 1216fe7..81a0980 100644 (file)
 #define HASH_NODEMAP_MEMBER_MAX_BITS 7
 
 /**
- * member hash functions
+ * Delete a member from a member list
  *
- * The purpose of this hash is to maintain the list of
- * exports that are connected and associated with a
- * particular nodemap
- */
-static void nm_member_getref(struct obd_export *exp)
-{
-}
-
-void nm_member_putref(struct obd_export *exp)
-{
-}
-
-static __u32 nm_member_hashfn(struct cfs_hash *hash_body,
-                          const void *key, unsigned mask)
-{
-       return hash_long((unsigned long)key, hash_body->hs_bkt_bits) & mask;
-}
-
-static void *nm_member_hs_key(struct hlist_node *hnode)
-{
-       struct obd_export       *exp;
-
-       exp = hlist_entry(hnode, struct obd_export,
-                         exp_target_data.ted_nodemap_member);
-
-       return exp;
-}
-
-static int nm_member_hs_keycmp(const void *key, struct hlist_node *hnode)
-{
-       struct obd_export       *exp;
-
-       exp = hlist_entry(hnode, struct obd_export,
-                         exp_target_data.ted_nodemap_member);
-
-       return key == exp;
-}
-
-static void *nm_member_hs_hashobject(struct hlist_node *hnode)
-{
-       return hlist_entry(hnode, struct obd_export,
-                          exp_target_data.ted_nodemap_member);
-}
-
-static void nm_member_hs_get(struct cfs_hash *hs, struct hlist_node *hnode)
-{
-       struct obd_export       *exp;
-
-       exp = hlist_entry(hnode, struct obd_export,
-                         exp_target_data.ted_nodemap_member);
-       nm_member_getref(exp);
-}
-
-static void nm_member_hs_put_locked(struct cfs_hash *hs,
-                                struct hlist_node *hnode)
-{
-       struct obd_export       *exp;
-
-       exp = hlist_entry(hnode, struct obd_export,
-                         exp_target_data.ted_nodemap_member);
-       nm_member_putref(exp);
-}
-
-/**
- * Delete a member from a member hash
- *
- * \param      nodemap         nodemap containing hash
- * \paraa      nid             nid of member to delete
+ * \param      nodemap         nodemap containing list
+ * \param      exp             export member to delete
  */
 void nm_member_del(struct lu_nodemap *nodemap, struct obd_export *exp)
 {
-       struct obd_export *exp1;
+       mutex_lock(&nodemap->nm_member_list_lock);
+       list_del_init(&exp->exp_target_data.ted_nodemap_member);
+       mutex_unlock(&nodemap->nm_member_list_lock);
 
-       exp1 = cfs_hash_del_key(nodemap->nm_member_hash, exp);
-       if (exp1 != NULL)
-               class_export_put(exp1);
-
-       LASSERT(hlist_unhashed(&exp->exp_target_data.ted_nodemap_member));
        exp->exp_target_data.ted_nodemap = NULL;
-}
-
-static struct cfs_hash_ops nm_member_hash_operations = {
-       .hs_hash        = nm_member_hashfn,
-       .hs_key         = nm_member_hs_key,
-       .hs_keycmp      = nm_member_hs_keycmp,
-       .hs_object      = nm_member_hs_hashobject,
-       .hs_get         = nm_member_hs_get,
-       .hs_put_locked  = nm_member_hs_put_locked,
-};
-
-/**
- * Init a member hash of a nodemap
- *
- * \param      nodemap         nodemap containing the member hash
- */
-int nm_member_init_hash(struct lu_nodemap *nodemap)
-{
-       char nodemap_hashname[LUSTRE_NODEMAP_NAME_LENGTH + 3];
-
-
-       snprintf(nodemap_hashname, sizeof(nodemap_hashname),
-                "nm-%s", nodemap->nm_name);
-       nodemap->nm_member_hash = cfs_hash_create(nodemap_hashname,
-                                         HASH_NODEMAP_MEMBER_CUR_BITS,
-                                         HASH_NODEMAP_MEMBER_MAX_BITS,
-                                         HASH_NODEMAP_MEMBER_BKT_BITS, 0,
-                                         CFS_HASH_MIN_THETA,
-                                         CFS_HASH_MAX_THETA,
-                                         &nm_member_hash_operations,
-                                         CFS_HASH_DEFAULT);
-       if (nodemap->nm_member_hash == NULL)
-               return -ENOMEM;
-
-       return 0;
-}
-
-/**
- * Callback from deleting a hash member
- */
-static int nm_member_delete_hash_cb(struct cfs_hash *hs, struct cfs_hash_bd *bd,
-                                struct hlist_node *hnode, void *data)
-{
-       struct obd_export       *exp;
-
-       exp = hlist_entry(hnode, struct obd_export,
-                         exp_target_data.ted_nodemap_member);
-
-       exp->exp_target_data.ted_nodemap = NULL;
-       cfs_hash_bd_del_locked(hs, bd, hnode);
        class_export_put(exp);
-
-       return 0;
 }
 
 /**
- * Delete a member hash from a nodemap
+ * Delete a member list from a nodemap
  *
- * \param      nodemap         nodemap to remove the hash from
+ * \param      nodemap         nodemap to remove the list from
  */
-void nm_member_delete_hash(struct lu_nodemap *nodemap)
+void nm_member_delete_list(struct lu_nodemap *nodemap)
 {
-       cfs_hash_for_each_safe(nodemap->nm_member_hash,
-                              nm_member_delete_hash_cb,
-                              nodemap);
-       cfs_hash_putref(nodemap->nm_member_hash);
+       struct obd_export *exp;
+       struct obd_export *tmp;
+
+       mutex_lock(&nodemap->nm_member_list_lock);
+       list_for_each_entry_safe(exp, tmp, &nodemap->nm_member_list,
+                                exp_target_data.ted_nodemap_member) {
+               exp->exp_target_data.ted_nodemap = NULL;
+               list_del_init(&exp->exp_target_data.ted_nodemap_member);
+               class_export_put(exp);
+       }
+       mutex_unlock(&nodemap->nm_member_list_lock);
 }
 
 /**
  * Add a member export to a nodemap
  *
- * \param      nodemap         nodemap to search
- * \param      exp             obd_export to search
- * \retval     -EEXIST         export is already hashed to a different nodemap
+ * \param      nodemap         nodemap to add to
+ * \param      exp             obd_export to add
+ * \retval     -EEXIST         export is already part of a different nodemap
  * \retval     -EINVAL         export is NULL
  */
 int nm_member_add(struct lu_nodemap *nodemap, struct obd_export *exp)
 {
-       int     rc = 0;
-
        if (exp == NULL) {
                CWARN("attempted to add null export to nodemap %s\n",
                      nodemap->nm_name);
                return -EINVAL;
        }
 
-       if (hlist_unhashed(&exp->exp_target_data.ted_nodemap_member) == 0) {
+       if (exp->exp_target_data.ted_nodemap != NULL &&
+           !list_empty(&exp->exp_target_data.ted_nodemap_member)) {
                /* export is already member of nodemap */
                if (exp->exp_target_data.ted_nodemap == nodemap)
                        return 0;
@@ -215,16 +100,14 @@ int nm_member_add(struct lu_nodemap *nodemap, struct obd_export *exp)
                return -EEXIST;
        }
 
+       class_export_get(exp);
        exp->exp_target_data.ted_nodemap = nodemap;
+       mutex_lock(&nodemap->nm_member_list_lock);
+       list_add(&exp->exp_target_data.ted_nodemap_member,
+                &nodemap->nm_member_list);
+       mutex_unlock(&nodemap->nm_member_list_lock);
 
-       rc = cfs_hash_add_unique(nodemap->nm_member_hash, exp,
-                                &exp->exp_target_data.ted_nodemap_member);
-
-       if (rc == 0)
-               class_export_get(exp);
-       /* else -EALREADY - exp already in nodemap hash */
-
-       return rc;
+       return 0;
 }
 
 /**
@@ -243,35 +126,6 @@ static void nm_member_exp_revoke(struct obd_export *exp)
        ldlm_revoke_export_locks(exp);
 }
 
-static int nm_member_reclassify_cb(struct cfs_hash *hs, struct cfs_hash_bd *bd,
-                                  struct hlist_node *hnode, void *data)
-{
-       struct obd_export       *exp;
-       struct lu_nodemap       *nodemap;
-
-       exp = hlist_entry(hnode, struct obd_export,
-                         exp_target_data.ted_nodemap_member);
-       if (exp == NULL)
-               goto out;
-
-       /* Must use bd_del_locked inside a cfs_hash callback, and exp->nodemap
-        * should never be NULL. For those reasons, can't use member_del.
-        */
-       read_lock(&nm_range_tree_lock);
-       nodemap = nodemap_classify_nid(exp->exp_connection->c_peer.nid);
-       if (exp->exp_target_data.ted_nodemap != nodemap) {
-               cfs_hash_bd_del_locked(hs, bd, hnode);
-               exp->exp_target_data.ted_nodemap = nodemap;
-               cfs_hash_add_unique(nodemap->nm_member_hash, exp,
-                               &exp->exp_target_data.ted_nodemap_member);
-       }
-       read_unlock(&nm_range_tree_lock);
-
-       nm_member_exp_revoke(exp);
-out:
-       return 0;
-}
-
 /* Mutex used to serialize calls to reclassify_nodemap_lock */
 DEFINE_MUTEX(reclassify_nodemap_lock);
 
@@ -296,28 +150,41 @@ DEFINE_MUTEX(reclassify_nodemap_lock);
  */
 void nm_member_reclassify_nodemap(struct lu_nodemap *nodemap)
 {
+       struct obd_export *exp;
+       struct obd_export *tmp;
+       struct lu_nodemap *new_nodemap;
+
        /* reclassify only one nodemap at a time to avoid deadlock */
        mutex_lock(&reclassify_nodemap_lock);
-       cfs_hash_for_each_safe(nodemap->nm_member_hash,
-                              nm_member_reclassify_cb,
-                              NULL);
+       mutex_lock(&nodemap->nm_member_list_lock);
+       list_for_each_entry_safe(exp, tmp, &nodemap->nm_member_list,
+                                exp_target_data.ted_nodemap_member) {
+               lnet_nid_t nid = exp->exp_connection->c_peer.nid;
+
+               /* nodemap_classify_nid requires range tree lock */
+               read_lock(&nm_range_tree_lock);
+               new_nodemap = nodemap_classify_nid(nid);
+               read_unlock(&nm_range_tree_lock);
+               if (new_nodemap != nodemap) {
+                       /* don't use member_del because ted_nodemap
+                        * should never be null
+                        */
+                       list_del_init(&exp->exp_target_data.ted_nodemap_member);
+                       exp->exp_target_data.ted_nodemap = new_nodemap;
+
+                       /* could deadlock if new_nodemap also reclassifying */
+                       mutex_lock(&new_nodemap->nm_member_list_lock);
+                       list_add(&exp->exp_target_data.ted_nodemap_member,
+                                &new_nodemap->nm_member_list);
+                       mutex_unlock(&new_nodemap->nm_member_list_lock);
+                       nm_member_exp_revoke(exp);
+               }
+               nodemap_putref(new_nodemap);
+       }
+       mutex_unlock(&nodemap->nm_member_list_lock);
        mutex_unlock(&reclassify_nodemap_lock);
 }
 
-static int
-nm_member_revoke_locks_cb(struct cfs_hash *hs, struct cfs_hash_bd *bd,
-                         struct hlist_node *hnode, void *data)
-{
-       struct obd_export       *exp;
-       exp = hlist_entry(hnode, struct obd_export,
-                         exp_target_data.ted_nodemap_member);
-       if (exp == NULL)
-               return 0;
-
-       nm_member_exp_revoke(exp);
-       return 0;
-}
-
 /**
  * Revoke the locks for member exports. Changing the idmap is
  * akin to deleting the security context. If the locks are not
@@ -328,6 +195,12 @@ nm_member_revoke_locks_cb(struct cfs_hash *hs, struct cfs_hash_bd *bd,
  */
 void nm_member_revoke_locks(struct lu_nodemap *nodemap)
 {
-       cfs_hash_for_each(nodemap->nm_member_hash, nm_member_revoke_locks_cb,
-                         NULL);
+       struct obd_export *exp;
+       struct obd_export *tmp;
+
+       mutex_lock(&nodemap->nm_member_list_lock);
+       list_for_each_entry_safe(exp, tmp, &nodemap->nm_member_list,
+                           exp_target_data.ted_nodemap_member)
+               nm_member_exp_revoke(exp);
+       mutex_unlock(&nodemap->nm_member_list_lock);
 }