From 1c7f9caa99df3082a3e506673721d359147843d3 Mon Sep 17 00:00:00 2001 From: Kit Westneat Date: Wed, 1 Jul 2015 09:53:46 -0400 Subject: [PATCH] LU-5092 nodemap: convert member hash to a list The members of a nodemap were stored in a hash, but they were only iterated against, not accessed by key. This patch converts the hash to a list in order to simplify things. Signed-off-by: Kit Westneat Change-Id: Ic1df4035d1c53a7c7966c4c528d20cefc7258d0e Reviewed-on: http://review.whamcloud.com/14885 Tested-by: Jenkins Reviewed-by: James Simmons Tested-by: Maloo Reviewed-by: John L. Hammond Reviewed-by: Oleg Drokin --- lustre/include/lustre_export.h | 2 +- lustre/include/lustre_nodemap.h | 43 ++++--- lustre/mgs/mgs_handler.c | 22 ++-- lustre/ptlrpc/nodemap_handler.c | 78 ++++++++++-- lustre/ptlrpc/nodemap_internal.h | 5 +- lustre/ptlrpc/nodemap_lproc.c | 49 +++----- lustre/ptlrpc/nodemap_member.c | 265 ++++++++++----------------------------- 7 files changed, 188 insertions(+), 276 deletions(-) diff --git a/lustre/include/lustre_export.h b/lustre/include/lustre_export.h index d6e5c11..2431972 100644 --- a/lustre/include/lustre_export.h +++ b/lustre/include/lustre_export.h @@ -71,7 +71,7 @@ struct tg_export_data { /** nodemap this export is a member of */ struct lu_nodemap *ted_nodemap; - struct hlist_node ted_nodemap_member; + struct list_head ted_nodemap_member; /* Every reply data fields below are * protected by ted_lcd_lock */ diff --git a/lustre/include/lustre_nodemap.h b/lustre/include/lustre_nodemap.h index 90555e3..221f8d7 100644 --- a/lustre/include/lustre_nodemap.h +++ b/lustre/include/lustre_nodemap.h @@ -54,48 +54,48 @@ enum nodemap_tree_type { struct lu_nodemap { /* human readable ID */ - char nm_name[LUSTRE_NODEMAP_NAME_LENGTH + 1]; + char nm_name[LUSTRE_NODEMAP_NAME_LENGTH + 1]; /* flags to govern nodemap behavior */ - bool nmf_trust_client_ids:1, - nmf_allow_root_access:1, - nmf_block_lookups:1, - nmf_hmac_required:1, - nmf_encryption_required:1; + bool nmf_trust_client_ids:1, + nmf_allow_root_access:1, + nmf_block_lookups:1, + nmf_hmac_required:1, + nmf_encryption_required:1; /* unique ID set by MGS */ - int nm_id; + unsigned int nm_id; /* nodemap ref counter */ - atomic_t nm_refcount; + atomic_t nm_refcount; /* UID to squash unmapped UIDs */ - uid_t nm_squash_uid; + uid_t nm_squash_uid; /* GID to squash unmapped GIDs */ - gid_t nm_squash_gid; + gid_t nm_squash_gid; /* NID range list */ - struct list_head nm_ranges; + struct list_head nm_ranges; /* lock for idmap red/black trees */ - rwlock_t nm_idmap_lock; + rwlock_t nm_idmap_lock; /* UID map keyed by local UID */ - struct rb_root nm_fs_to_client_uidmap; + struct rb_root nm_fs_to_client_uidmap; /* UID map keyed by remote UID */ - struct rb_root nm_client_to_fs_uidmap; + struct rb_root nm_client_to_fs_uidmap; /* GID map keyed by local UID */ - struct rb_root nm_fs_to_client_gidmap; + struct rb_root nm_fs_to_client_gidmap; /* GID map keyed by remote UID */ - struct rb_root nm_client_to_fs_gidmap; + struct rb_root nm_client_to_fs_gidmap; /* proc directory entry */ struct proc_dir_entry *nm_proc_entry; /* attached client members of this nodemap */ - struct cfs_hash *nm_member_hash; + struct mutex nm_member_list_lock; + struct list_head nm_member_list; /* access by nodemap name */ - struct hlist_node nm_hash; + struct hlist_node nm_hash; /* used when unloading nodemaps */ - struct list_head nm_list; + struct list_head nm_list; }; void nodemap_activate(const bool value); int nodemap_add(const char *nodemap_name); int nodemap_del(const char *nodemap_name); -struct lu_nodemap *nodemap_classify_nid(lnet_nid_t nid); int nodemap_add_member(lnet_nid_t nid, struct obd_export *exp); void nodemap_del_member(struct obd_export *exp); int nodemap_parse_range(const char *range_string, lnet_nid_t range[2]); @@ -116,4 +116,7 @@ __u32 nodemap_map_id(struct lu_nodemap *nodemap, enum nodemap_tree_type tree_type, __u32 id); ssize_t nodemap_map_acl(struct lu_nodemap *nodemap, void *buf, size_t size, enum nodemap_tree_type tree_type); +void nodemap_test_nid(lnet_nid_t nid, char *name_buf, size_t name_len); +__u32 nodemap_test_id(lnet_nid_t nid, enum nodemap_id_type idtype, + __u32 client_id); #endif /* _LUSTRE_NODEMAP_H */ diff --git a/lustre/mgs/mgs_handler.c b/lustre/mgs/mgs_handler.c index 2fc88bf..d3a0038 100644 --- a/lustre/mgs/mgs_handler.c +++ b/lustre/mgs/mgs_handler.c @@ -631,7 +631,6 @@ static int mgs_iocontrol_nodemap(const struct lu_env *env, struct obd_ioctl_data *data) { struct lustre_cfg *lcfg = NULL; - struct lu_nodemap *nodemap; lnet_nid_t nid; const char *nodemap_name = NULL; const char *nidstr = NULL; @@ -639,8 +638,9 @@ static int mgs_iocontrol_nodemap(const struct lu_env *env, const char *idtype_str = NULL; char *param = NULL; char fs_idstr[16]; + char name_buf[LUSTRE_NODEMAP_NAME_LENGTH + 1]; int rc = 0; - __u32 client_id; + unsigned long client_id; __u32 fs_id; __u32 cmd; int idtype; @@ -687,10 +687,10 @@ static int mgs_iocontrol_nodemap(const struct lu_env *env, GOTO(out_lcfg, rc = -EINVAL); nidstr = lustre_cfg_string(lcfg, 1); nid = libcfs_str2nid(nidstr); - nodemap = nodemap_classify_nid(nid); - memset(data->ioc_pbuf1, 0, data->ioc_plen1); - if (copy_to_user(data->ioc_pbuf1, nodemap->nm_name, - strlen(nodemap->nm_name)) != 0) + nodemap_test_nid(nid, name_buf, sizeof(name_buf)); + rc = copy_to_user(data->ioc_pbuf1, name_buf, + MIN(data->ioc_plen1, sizeof(name_buf))); + if (rc != 0) GOTO(out_lcfg, rc = -EFAULT); break; case LCFG_NODEMAP_TEST_ID: @@ -701,16 +701,16 @@ static int mgs_iocontrol_nodemap(const struct lu_env *env, client_idstr = lustre_cfg_string(lcfg, 3); nid = libcfs_str2nid(nidstr); - nodemap = nodemap_classify_nid(nid); - client_id = simple_strtoul(client_idstr, NULL, 10); - if (strcmp(idtype_str, "uid") == 0) idtype = NODEMAP_UID; else idtype = NODEMAP_GID; - fs_id = nodemap_map_id(nodemap, idtype, NODEMAP_CLIENT_TO_FS, - client_id); + rc = kstrtoul(client_idstr, 10, &client_id); + if (rc != 0) + GOTO(out_lcfg, rc = -EINVAL); + + fs_id = nodemap_test_id(nid, idtype, client_id); if (data->ioc_plen1 < sizeof(fs_idstr)) GOTO(out_lcfg, rc = -EINVAL); diff --git a/lustre/ptlrpc/nodemap_handler.c b/lustre/ptlrpc/nodemap_handler.c index 7445c94..984e45d 100644 --- a/lustre/ptlrpc/nodemap_handler.c +++ b/lustre/ptlrpc/nodemap_handler.c @@ -89,10 +89,10 @@ static void nodemap_destroy(struct lu_nodemap *nodemap) idmap_delete_tree(nodemap); write_unlock(&nodemap->nm_idmap_lock); nm_member_reclassify_nodemap(nodemap); - if (!cfs_hash_is_empty(nodemap->nm_member_hash)) + if (!list_empty(&nodemap->nm_member_list)) CWARN("nodemap_destroy failed to reclassify all members\n"); - nm_member_delete_hash(nodemap); + nm_member_delete_list(nodemap); OBD_FREE_PTR(nodemap); } @@ -287,7 +287,8 @@ out: } /** - * classify the nid into the proper nodemap + * Classify the nid into the proper nodemap. Caller must hold + * nm_range_tree_lock, and call nodemap_putref when done with nodemap. * * \param nid nid to classify * \retval nodemap nodemap containing the nid @@ -296,14 +297,17 @@ out: struct lu_nodemap *nodemap_classify_nid(lnet_nid_t nid) { struct lu_nid_range *range; + struct lu_nodemap *nodemap; range = range_search(nid); if (range != NULL) - return range->rn_nodemap; + nodemap = range->rn_nodemap; + else + nodemap = default_nodemap; + nodemap_getref(nodemap); - return default_nodemap; + return nodemap; } -EXPORT_SYMBOL(nodemap_classify_nid); /** * simple check for default nodemap @@ -402,6 +406,7 @@ int nodemap_add_member(lnet_nid_t nid, struct obd_export *exp) nodemap = nodemap_classify_nid(nid); rc = nm_member_add(nodemap, exp); read_unlock(&nm_range_tree_lock); + nodemap_putref(nodemap); return rc; } EXPORT_SYMBOL(nodemap_add_member); @@ -769,16 +774,11 @@ static int nodemap_create(const char *name, bool is_default) GOTO(out, rc = -EEXIST); } - - rc = nm_member_init_hash(nodemap); - if (rc != 0) { - OBD_FREE_PTR(nodemap); - goto out; - } - INIT_LIST_HEAD(&nodemap->nm_ranges); INIT_LIST_HEAD(&nodemap->nm_list); + INIT_LIST_HEAD(&nodemap->nm_member_list); + mutex_init(&nodemap->nm_member_list_lock); rwlock_init(&nodemap->nm_idmap_lock); nodemap->nm_fs_to_client_uidmap = RB_ROOT; nodemap->nm_client_to_fs_uidmap = RB_ROOT; @@ -1052,3 +1052,55 @@ void nm_member_revoke_all() cfs_hash_for_each_safe(nodemap_hash, nm_member_revoke_all_cb, NULL); } +/** + * Returns the nodemap classification for a given nid into an ioctl buffer. + * Useful for testing the nodemap configuration to make sure it is working as + * expected. + * + * \param nid nid to classify + * \param[out] name_buf buffer to write the nodemap name to + * \param name_len length of buffer + */ +void nodemap_test_nid(lnet_nid_t nid, char *name_buf, size_t name_len) +{ + struct lu_nodemap *nodemap; + + read_lock(&nm_range_tree_lock); + nodemap = nodemap_classify_nid(nid); + read_unlock(&nm_range_tree_lock); + + strncpy(name_buf, nodemap->nm_name, name_len); + if (name_len > 0) + name_buf[name_len - 1] = '\0'; + + nodemap_putref(nodemap); +} +EXPORT_SYMBOL(nodemap_test_nid); + +/** + * Returns the id mapping for a given nid/id pair. Useful for testing the + * nodemap configuration to make sure it is working as expected. + * + * \param nid nid to classify + * \param idtype uid or gid + * \param client_id id to map to fs + * + * \retval the mapped fs_id of the given client_id + */ +__u32 nodemap_test_id(lnet_nid_t nid, enum nodemap_id_type idtype, + __u32 client_id) +{ + struct lu_nodemap *nodemap; + __u32 fs_id; + + read_lock(&nm_range_tree_lock); + nodemap = nodemap_classify_nid(nid); + read_unlock(&nm_range_tree_lock); + + fs_id = nodemap_map_id(nodemap, idtype, NODEMAP_CLIENT_TO_FS, + client_id); + nodemap_putref(nodemap); + + return fs_id; +} +EXPORT_SYMBOL(nodemap_test_id); diff --git a/lustre/ptlrpc/nodemap_internal.h b/lustre/ptlrpc/nodemap_internal.h index 01a812e..34c4c64 100644 --- a/lustre/ptlrpc/nodemap_internal.h +++ b/lustre/ptlrpc/nodemap_internal.h @@ -95,16 +95,17 @@ struct lu_idmap *idmap_search(struct lu_nodemap *nodemap, enum nodemap_id_type id_type, __u32 id); int nodemap_cleanup_nodemaps(void); -int nm_member_init_hash(struct lu_nodemap *nodemap); int nm_member_add(struct lu_nodemap *nodemap, struct obd_export *exp); void nm_member_del(struct lu_nodemap *nodemap, struct obd_export *exp); -void nm_member_delete_hash(struct lu_nodemap *nodemap); +void nm_member_delete_list(struct lu_nodemap *nodemap); +struct lu_nodemap *nodemap_classify_nid(lnet_nid_t nid); void nm_member_reclassify_nodemap(struct lu_nodemap *nodemap); void nm_member_revoke_locks(struct lu_nodemap *nodemap); void nm_member_revoke_all(void); struct rb_node *nm_rb_next_postorder(const struct rb_node *node); struct rb_node *nm_rb_first_postorder(const struct rb_root *root); +void nodemap_putref(struct lu_nodemap *nodemap); #define nm_rbtree_postorder_for_each_entry_safe(pos, n, \ root, field) \ diff --git a/lustre/ptlrpc/nodemap_lproc.c b/lustre/ptlrpc/nodemap_lproc.c index 458f375..123e7a7 100644 --- a/lustre/ptlrpc/nodemap_lproc.c +++ b/lustre/ptlrpc/nodemap_lproc.c @@ -151,48 +151,31 @@ static int nodemap_ranges_open(struct inode *inode, struct file *file) } /** - * Hash callback, reads and prints the exports attached to this nodemap. + * Reads and prints the exports attached to the given nodemap. * - * \param hs nodemap member hash - * \param bd unused - * \param hnode current member in hash - * \param data seq_file to print to - * \retval 0 success - */ -static int nodemap_exports_show_cb(struct cfs_hash *hs, struct cfs_hash_bd *bd, - struct hlist_node *hnode, void *data) -{ - struct seq_file *m = data; - struct obd_export *exp; - char nidstr[LNET_NIDSTR_SIZE] = ""; - - exp = hlist_entry(hnode, struct obd_export, - exp_target_data.ted_nodemap_member); - if (exp->exp_connection != NULL) - libcfs_nid2str_r(exp->exp_connection->c_peer.nid, - nidstr, sizeof(nidstr)); - - seq_printf(m, " { nid: %s, uuid: %s },", - nidstr, exp->exp_client_uuid.uuid); - - return 0; -} - -/** - * Reads and prints the exports attached to the given nodemap via hash - * foreach callback. - * - * \param m seq file in proc fs + * \param m seq file in proc fs, stores nodemap * \param data unused * \retval 0 success */ static int nodemap_exports_show(struct seq_file *m, void *data) { - struct lu_nodemap *nodemap = m->private; + struct lu_nodemap *nodemap = m->private; + struct obd_export *exp; + char nidstr[LNET_NIDSTR_SIZE] = ""; seq_printf(m, "[\n"); - cfs_hash_for_each(nodemap->nm_member_hash, nodemap_exports_show_cb, m); + mutex_lock(&nodemap->nm_member_list_lock); + list_for_each_entry(exp, &nodemap->nm_member_list, + exp_target_data.ted_nodemap_member) { + if (exp->exp_connection != NULL) + libcfs_nid2str_r(exp->exp_connection->c_peer.nid, + nidstr, sizeof(nidstr)); + + seq_printf(m, " { nid: %s, uuid: %s },", + nidstr, exp->exp_client_uuid.uuid); + } + mutex_unlock(&nodemap->nm_member_list_lock); seq_printf(m, "\n"); seq_printf(m, "]\n"); diff --git a/lustre/ptlrpc/nodemap_member.c b/lustre/ptlrpc/nodemap_member.c index 1216fe7..81a0980 100644 --- a/lustre/ptlrpc/nodemap_member.c +++ b/lustre/ptlrpc/nodemap_member.c @@ -33,174 +33,59 @@ #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); } -- 1.8.3.1