From: Mr NeilBrown Date: Tue, 7 Apr 2020 16:20:47 +0000 (-0400) Subject: LU-8130 ptlrpc: convert conn_hash to rhashtable X-Git-Tag: 2.13.55~84 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=37b29a8f709aa4bd2e22cbb3549257b28cd85610 LU-8130 ptlrpc: convert conn_hash to rhashtable Linux has a resizeable hashtable implementation in lib, so we should use that instead of having one in libcfs. This patch converts the ptlrpc conn_hash to use rhashtable. In the process we gain lockless lookup. As connections are never deleted until the hash table is destroyed, there is no need to count the reference in the hash table. There is also no need to enable automatic_shrinking. Linux-commit: ac2370ac2bc5215daf78546cd8d925510065bb7f Signed-off-by: Mr NeilBrown Change-Id: I0537564ba544ed06be42ba243606a884a1290f20 Reviewed-on: https://review.whamcloud.com/33616 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Shaun Tancheff Reviewed-by: Oleg Drokin --- diff --git a/lustre/include/lustre_net.h b/lustre/include/lustre_net.h index eea505a..f456e6c 100644 --- a/lustre/include/lustre_net.h +++ b/lustre/include/lustre_net.h @@ -51,6 +51,7 @@ * @{ */ #include +#include #include #include #include @@ -530,7 +531,7 @@ struct ptlrpc_replay_async_args { */ struct ptlrpc_connection { /** linkage for connections hash table */ - struct hlist_node c_hash; + struct rhash_head c_hash; /** Our own lnet nid for this connection */ lnet_nid_t c_self; /** Remote side nid for this connection */ diff --git a/lustre/include/obd_support.h b/lustre/include/obd_support.h index d0db70a..492c2b9 100644 --- a/lustre/include/obd_support.h +++ b/lustre/include/obd_support.h @@ -80,9 +80,6 @@ extern char obd_jobid_var[]; #define HASH_LQE_BKT_BITS 5 #define HASH_LQE_CUR_BITS 7 #define HASH_LQE_MAX_BITS 12 -#define HASH_CONN_BKT_BITS 5 -#define HASH_CONN_CUR_BITS 5 -#define HASH_CONN_MAX_BITS 15 #define HASH_EXP_LOCK_BKT_BITS 5 #define HASH_EXP_LOCK_CUR_BITS 7 #define HASH_EXP_LOCK_MAX_BITS 16 diff --git a/lustre/ldlm/ldlm_lib.c b/lustre/ldlm/ldlm_lib.c index b0649fd..2b62e25f 100644 --- a/lustre/ldlm/ldlm_lib.c +++ b/lustre/ldlm/ldlm_lib.c @@ -1456,6 +1456,9 @@ dont_check_exports: export->exp_connection = ptlrpc_connection_get(req->rq_peer, req->rq_self, &cluuid); + if (!export->exp_connection) + GOTO(out, rc = -ENOTCONN); + obd_nid_add(export->exp_obd, export); lustre_msg_set_handle(req->rq_repmsg, &conn); diff --git a/lustre/ptlrpc/connection.c b/lustre/ptlrpc/connection.c index 369eace..62db6aa 100644 --- a/lustre/ptlrpc/connection.c +++ b/lustre/ptlrpc/connection.c @@ -31,14 +31,50 @@ */ #define DEBUG_SUBSYSTEM S_RPC + +#include +#include #include #include #include #include "ptlrpc_internal.h" -static struct cfs_hash *conn_hash; -static struct cfs_hash_ops conn_hash_ops; +static struct rhashtable conn_hash; + +/* + * struct lnet_process_id may contain unassigned bytes which might not + * be zero, so we cannot just hash and compare bytes. + */ + +static u32 lnet_process_id_hash(const void *data, u32 len, u32 seed) +{ + const struct lnet_process_id *lpi = data; + + seed = cfs_hash_32(seed ^ lpi->pid, 32); + seed ^= cfs_hash_64(lpi->nid, 32); + return seed; +} + +static int lnet_process_id_cmp(struct rhashtable_compare_arg *arg, + const void *obj) +{ + const struct lnet_process_id *lpi = arg->key; + const struct ptlrpc_connection *con = obj; + + if (lpi->nid == con->c_peer.nid && + lpi->pid == con->c_peer.pid) + return 0; + return -ESRCH; +} + +static const struct rhashtable_params conn_hash_params = { + .key_len = 1, /* actually variable-length */ + .key_offset = offsetof(struct ptlrpc_connection, c_peer), + .head_offset = offsetof(struct ptlrpc_connection, c_hash), + .hashfn = lnet_process_id_hash, + .obj_cmpfn = lnet_process_id_cmp, +}; struct ptlrpc_connection * ptlrpc_connection_get(struct lnet_process_id peer, lnet_nid_t self, @@ -48,9 +84,11 @@ ptlrpc_connection_get(struct lnet_process_id peer, lnet_nid_t self, ENTRY; peer.nid = LNetPrimaryNID(peer.nid); - conn = cfs_hash_lookup(conn_hash, &peer); - if (conn) + conn = rhashtable_lookup_fast(&conn_hash, &peer, conn_hash_params); + if (conn) { + ptlrpc_connection_addref(conn); GOTO(out, conn); + } OBD_ALLOC_PTR(conn); if (!conn) @@ -58,7 +96,6 @@ ptlrpc_connection_get(struct lnet_process_id peer, lnet_nid_t self, conn->c_peer = peer; conn->c_self = self; - INIT_HLIST_NODE(&conn->c_hash); atomic_set(&conn->c_refcount, 1); if (uuid) obd_str2uuid(&conn->c_remote_uuid, uuid->uuid); @@ -67,15 +104,25 @@ ptlrpc_connection_get(struct lnet_process_id peer, lnet_nid_t self, * Add the newly created conn to the hash, on key collision we * lost a racing addition and must destroy our newly allocated * connection. The object which exists in the hash will be - * returned and may be compared against out object. + * returned,otherwise NULL is returned on success. */ - /* In the function below, .hs_keycmp resolves to - * conn_keycmp() */ - /* coverity[overrun-buffer-val] */ - conn2 = cfs_hash_findadd_unique(conn_hash, &peer, &conn->c_hash); - if (conn != conn2) { +try_again: + conn2 = rhashtable_lookup_get_insert_fast(&conn_hash, &conn->c_hash, + conn_hash_params); + if (conn2) { + /* insertion failed */ OBD_FREE_PTR(conn); + if (IS_ERR(conn2)) { + /* hash table could be resizing. */ + if (PTR_ERR(conn2) == -ENOMEM || + PTR_ERR(conn2) == -EBUSY) { + msleep(5); + goto try_again; + } + return NULL; + } conn = conn2; + ptlrpc_connection_addref(conn); } EXIT; out: @@ -93,7 +140,7 @@ int ptlrpc_connection_put(struct ptlrpc_connection *conn) if (!conn) RETURN(rc); - LASSERT(atomic_read(&conn->c_refcount) > 1); + LASSERT(atomic_read(&conn->c_refcount) > 0); /* * We do not remove connection from hashtable and @@ -111,7 +158,7 @@ int ptlrpc_connection_put(struct ptlrpc_connection *conn) * when ptlrpc_connection_fini()->lh_exit->conn_exit() * path is called. */ - if (atomic_dec_return(&conn->c_refcount) == 1) + if (atomic_dec_return(&conn->c_refcount) == 0) rc = 1; CDEBUG(D_INFO, "PUT conn=%p refcount %d to %s\n", @@ -134,90 +181,11 @@ ptlrpc_connection_addref(struct ptlrpc_connection *conn) RETURN(conn); } -int ptlrpc_connection_init(void) -{ - ENTRY; - - conn_hash = cfs_hash_create("CONN_HASH", - HASH_CONN_CUR_BITS, - HASH_CONN_MAX_BITS, - HASH_CONN_BKT_BITS, 0, - CFS_HASH_MIN_THETA, - CFS_HASH_MAX_THETA, - &conn_hash_ops, CFS_HASH_DEFAULT); - if (!conn_hash) - RETURN(-ENOMEM); - - RETURN(0); -} - -void ptlrpc_connection_fini(void) { - ENTRY; - cfs_hash_putref(conn_hash); - EXIT; -} - -/* - * Hash operations for net_peer<->connection - */ -static unsigned -conn_hashfn(struct cfs_hash *hs, const void *key, unsigned mask) -{ - return cfs_hash_djb2_hash(key, sizeof(struct lnet_process_id), mask); -} - -static int -conn_keycmp(const void *key, struct hlist_node *hnode) -{ - struct ptlrpc_connection *conn; - const struct lnet_process_id *conn_key; - - LASSERT(key != NULL); - conn_key = (struct lnet_process_id *)key; - conn = hlist_entry(hnode, struct ptlrpc_connection, c_hash); - - return conn_key->nid == conn->c_peer.nid && - conn_key->pid == conn->c_peer.pid; -} - -static void * -conn_key(struct hlist_node *hnode) -{ - struct ptlrpc_connection *conn; - conn = hlist_entry(hnode, struct ptlrpc_connection, c_hash); - return &conn->c_peer; -} - -static void * -conn_object(struct hlist_node *hnode) -{ - return hlist_entry(hnode, struct ptlrpc_connection, c_hash); -} - static void -conn_get(struct cfs_hash *hs, struct hlist_node *hnode) +conn_exit(void *vconn, void *data) { - struct ptlrpc_connection *conn; + struct ptlrpc_connection *conn = vconn; - conn = hlist_entry(hnode, struct ptlrpc_connection, c_hash); - atomic_inc(&conn->c_refcount); -} - -static void -conn_put_locked(struct cfs_hash *hs, struct hlist_node *hnode) -{ - struct ptlrpc_connection *conn; - - conn = hlist_entry(hnode, struct ptlrpc_connection, c_hash); - atomic_dec(&conn->c_refcount); -} - -static void -conn_exit(struct cfs_hash *hs, struct hlist_node *hnode) -{ - struct ptlrpc_connection *conn; - - conn = hlist_entry(hnode, struct ptlrpc_connection, c_hash); /* * Nothing should be left. Connection user put it and * connection also was deleted from table by this time @@ -229,12 +197,12 @@ conn_exit(struct cfs_hash *hs, struct hlist_node *hnode) OBD_FREE_PTR(conn); } -static struct cfs_hash_ops conn_hash_ops = { - .hs_hash = conn_hashfn, - .hs_keycmp = conn_keycmp, - .hs_key = conn_key, - .hs_object = conn_object, - .hs_get = conn_get, - .hs_put_locked = conn_put_locked, - .hs_exit = conn_exit, -}; +int ptlrpc_connection_init(void) +{ + return rhashtable_init(&conn_hash, &conn_hash_params); +} + +void ptlrpc_connection_fini(void) +{ + rhashtable_free_and_destroy(&conn_hash, conn_exit, NULL); +}