X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fptlrpc%2Fnodemap_member.c;h=9871f8d285ffdd980b15a3ea454ae0a285df1f21;hb=512f2ff1b17db4d03979a1caa86f94defc6653b4;hp=08b269b2a8d467c32f709875dfbb845dfd4b5fbd;hpb=83f04354ff68a14d7492e35a9576c91492a1206c;p=fs%2Flustre-release.git diff --git a/lustre/ptlrpc/nodemap_member.c b/lustre/ptlrpc/nodemap_member.c index 08b269b..9871f8d 100644 --- a/lustre/ptlrpc/nodemap_member.c +++ b/lustre/ptlrpc/nodemap_member.c @@ -50,7 +50,7 @@ void nm_member_putref(struct obd_export *exp) static __u32 nm_member_hashfn(cfs_hash_t *hash_body, const void *key, unsigned mask) { - return cfs_hash_djb2_hash(key, strlen(key), mask); + return hash_long((unsigned long)key, hash_body->hs_bkt_bits) & mask; } static void *nm_member_hs_key(struct hlist_node *hnode) @@ -106,13 +106,14 @@ static void nm_member_hs_put_locked(cfs_hash_t *hs, */ void nm_member_del(struct lu_nodemap *nodemap, struct obd_export *exp) { + struct obd_export *exp1; - exp->exp_target_data.ted_nodemap = NULL; - exp = cfs_hash_del_key(nodemap->nm_member_hash, exp); - if (exp == NULL) - return; + exp1 = cfs_hash_del_key(nodemap->nm_member_hash, exp); + if (exp1 != NULL) + class_export_put(exp1); - class_export_put(exp); + LASSERT(hlist_unhashed(&exp->exp_target_data.ted_nodemap_member)); + exp->exp_target_data.ted_nodemap = NULL; } static cfs_hash_ops_t nm_member_hash_operations = { @@ -219,7 +220,7 @@ int nm_member_add(struct lu_nodemap *nodemap, struct obd_export *exp) rc = cfs_hash_add_unique(nodemap->nm_member_hash, exp, &exp->exp_target_data.ted_nodemap_member); - if (rc == 0 ) + if (rc == 0) class_export_get(exp); /* else -EALREADY - exp already in nodemap hash */ @@ -246,39 +247,61 @@ static int nm_member_reclassify_cb(cfs_hash_t *hs, cfs_hash_bd_t *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; - /* Call member add before del so exp->nodemap is never NULL. Must use - * bd_del_locked inside a cfs_hash callback. For those reasons, can't - * use member_del. + /* 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. */ - nodemap_add_member(exp->exp_connection->c_peer.nid, exp); - cfs_hash_bd_del_locked(hs, bd, hnode); - class_export_put(exp); + 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); + /** - * Reclassify the members of a nodemap after range changes or activation, - * based on the member export's NID and the nodemap's new NID ranges. Exports - * that are no longer classified as being part of this nodemap are moved to the - * nodemap whose NID ranges contain the export's NID, and their locks are - * revoked. + * Reclassify the members of a nodemap after range changes or activation. + * This function reclassifies the members of a nodemap based on the member + * export's NID and the nodemap's new NID ranges. Exports that are no longer + * classified as being part of this nodemap are moved to the nodemap whose + * NID ranges contain the export's NID, and their locks are revoked. + * + * Calls to this function are serialized due to a potential deadlock: Say there + * is a nodemap A and a nodemap B that both need to reclassify their members. + * If there is a member in nodemap A that should be in nodemap B, reclassify + * will attempt to add the member to nodemap B. If nodemap B is also + * reclassifying its members, then its hash is locked and nodemap A's attempt + * to add will block and wait for nodemap B's reclassify to finish. If + * nodemap B's reclassify then attempts to reclassify a member that should be + * in nodemap A, it will also try add the member to nodemap A's locked hash, + * causing a deadlock. * * \param nodemap nodemap with members to reclassify */ void nm_member_reclassify_nodemap(struct lu_nodemap *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_unlock(&reclassify_nodemap_lock); } static int nm_member_revoke_locks_cb(cfs_hash_t *hs, cfs_hash_bd_t *bd,