From: "Matthew Wilcox (Oracle)" <wi...@infradead.org> The XArray requires a separate cursor, but embeds the lock, so it's a minor saving. Also, there's no need to preload.
Signed-off-by: Matthew Wilcox (Oracle) <wi...@infradead.org> --- net/rxrpc/af_rxrpc.c | 2 +- net/rxrpc/ar-internal.h | 3 ++- net/rxrpc/conn_client.c | 49 +++++++++++++++-------------------------- net/rxrpc/conn_object.c | 2 +- 4 files changed, 22 insertions(+), 34 deletions(-) diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index d09eaf153544..16e289bbc825 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -981,7 +981,7 @@ static int __init af_rxrpc_init(void) tmp &= 0x3fffffff; if (tmp == 0) tmp = 1; - idr_set_cursor(&rxrpc_client_conn_ids, tmp); + rxrpc_client_conn_next = tmp; ret = -ENOMEM; rxrpc_call_jar = kmem_cache_create( diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index 63b26baa108a..7721448aa7a4 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -898,7 +898,8 @@ extern unsigned int rxrpc_max_client_connections; extern unsigned int rxrpc_reap_client_connections; extern unsigned long rxrpc_conn_idle_client_expiry; extern unsigned long rxrpc_conn_idle_client_fast_expiry; -extern struct idr rxrpc_client_conn_ids; +extern struct xarray rxrpc_client_conn_ids; +extern u32 rxrpc_client_conn_next; void rxrpc_destroy_client_conn_ids(void); int rxrpc_connect_call(struct rxrpc_sock *, struct rxrpc_call *, diff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c index aea82f909c60..d967de7a5eb9 100644 --- a/net/rxrpc/conn_client.c +++ b/net/rxrpc/conn_client.c @@ -72,7 +72,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/slab.h> -#include <linux/idr.h> +#include <linux/xarray.h> #include <linux/timer.h> #include <linux/sched/signal.h> @@ -86,14 +86,14 @@ __read_mostly unsigned long rxrpc_conn_idle_client_fast_expiry = 2 * HZ; /* * We use machine-unique IDs for our client connections. */ -DEFINE_IDR(rxrpc_client_conn_ids); -static DEFINE_SPINLOCK(rxrpc_conn_id_lock); +DEFINE_XARRAY_ALLOC1(rxrpc_client_conn_ids); +u32 rxrpc_client_conn_next; static void rxrpc_cull_active_client_conns(struct rxrpc_net *); /* * Get a connection ID and epoch for a client connection from the global pool. - * The connection struct pointer is then recorded in the idr radix tree. The + * The connection struct pointer is then recorded in the XArray. The * epoch doesn't change until the client is rebooted (or, at least, unless the * module is unloaded). */ @@ -101,21 +101,15 @@ static int rxrpc_get_client_connection_id(struct rxrpc_connection *conn, gfp_t gfp) { struct rxrpc_net *rxnet = conn->params.local->rxnet; - int id; + int err, id; _enter(""); - idr_preload(gfp); - spin_lock(&rxrpc_conn_id_lock); - - id = idr_alloc_cyclic(&rxrpc_client_conn_ids, conn, - 1, 0x40000000, GFP_NOWAIT); - if (id < 0) + err = xa_alloc_cyclic(&rxrpc_client_conn_ids, &id, conn, + XA_LIMIT(1, 0x40000000), &rxrpc_client_conn_next, gfp); + if (err < 0) goto error; - spin_unlock(&rxrpc_conn_id_lock); - idr_preload_end(); - conn->proto.epoch = rxnet->epoch; conn->proto.cid = id << RXRPC_CIDSHIFT; set_bit(RXRPC_CONN_HAS_IDR, &conn->flags); @@ -123,10 +117,8 @@ static int rxrpc_get_client_connection_id(struct rxrpc_connection *conn, return 0; error: - spin_unlock(&rxrpc_conn_id_lock); - idr_preload_end(); - _leave(" = %d", id); - return id; + _leave(" = %d", err); + return err; } /* @@ -135,30 +127,26 @@ static int rxrpc_get_client_connection_id(struct rxrpc_connection *conn, static void rxrpc_put_client_connection_id(struct rxrpc_connection *conn) { if (test_bit(RXRPC_CONN_HAS_IDR, &conn->flags)) { - spin_lock(&rxrpc_conn_id_lock); - idr_remove(&rxrpc_client_conn_ids, + xa_erase(&rxrpc_client_conn_ids, conn->proto.cid >> RXRPC_CIDSHIFT); - spin_unlock(&rxrpc_conn_id_lock); } } /* - * Destroy the client connection ID tree. + * There should be no outstanding client connections. */ void rxrpc_destroy_client_conn_ids(void) { - struct rxrpc_connection *conn; - int id; + if (!xa_empty(&rxrpc_client_conn_ids)) { + struct rxrpc_connection *conn; + unsigned long id; - if (!idr_is_empty(&rxrpc_client_conn_ids)) { - idr_for_each_entry(&rxrpc_client_conn_ids, conn, id) { + xa_for_each(&rxrpc_client_conn_ids, id, conn) { pr_err("AF_RXRPC: Leaked client conn %p {%d}\n", conn, atomic_read(&conn->usage)); } BUG(); } - - idr_destroy(&rxrpc_client_conn_ids); } /* @@ -234,7 +222,7 @@ rxrpc_alloc_client_connection(struct rxrpc_conn_parameters *cp, gfp_t gfp) static bool rxrpc_may_reuse_conn(struct rxrpc_connection *conn) { struct rxrpc_net *rxnet = conn->params.local->rxnet; - int id_cursor, id, distance, limit; + int id, distance, limit; if (test_bit(RXRPC_CONN_DONT_REUSE, &conn->flags)) goto dont_reuse; @@ -248,9 +236,8 @@ static bool rxrpc_may_reuse_conn(struct rxrpc_connection *conn) * times the maximum number of client conns away from the current * allocation point to try and keep the IDs concentrated. */ - id_cursor = idr_get_cursor(&rxrpc_client_conn_ids); id = conn->proto.cid >> RXRPC_CIDSHIFT; - distance = id - id_cursor; + distance = id - rxrpc_client_conn_next; if (distance < 0) distance = -distance; limit = max(rxrpc_max_client_connections * 4, 1024U); diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c index 434ef392212b..31eef9c2a9ac 100644 --- a/net/rxrpc/conn_object.c +++ b/net/rxrpc/conn_object.c @@ -115,7 +115,7 @@ struct rxrpc_connection *rxrpc_find_connection_rcu(struct rxrpc_local *local, /* Look up client connections by connection ID alone as their * IDs are unique for this machine. */ - conn = idr_find(&rxrpc_client_conn_ids, + conn = xa_load(&rxrpc_client_conn_ids, sp->hdr.cid >> RXRPC_CIDSHIFT); if (!conn || atomic_read(&conn->usage) == 0) { _debug("no conn"); -- 2.23.0.rc1