Commit f06cb291 authored by David Howells's avatar David Howells
Browse files

rxrpc: Make the set of connection IDs per local endpoint



Make the set of connection IDs per local endpoint so that endpoints don't
cause each other's connections to get dismissed.

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: linux-afs@lists.infradead.org
parent 57af281e
Loading
Loading
Loading
Loading
+0 −8
Original line number Diff line number Diff line
@@ -957,16 +957,9 @@ static const struct net_proto_family rxrpc_family_ops = {
static int __init af_rxrpc_init(void)
{
	int ret = -1;
	unsigned int tmp;

	BUILD_BUG_ON(sizeof(struct rxrpc_skb_priv) > sizeof_field(struct sk_buff, cb));

	get_random_bytes(&tmp, sizeof(tmp));
	tmp &= 0x3fffffff;
	if (tmp == 0)
		tmp = 1;
	idr_set_cursor(&rxrpc_client_conn_ids, tmp);

	ret = -ENOMEM;
	rxrpc_call_jar = kmem_cache_create(
		"rxrpc_call_jar", sizeof(struct rxrpc_call), 0,
@@ -1062,7 +1055,6 @@ static void __exit af_rxrpc_exit(void)
	 * are released.
	 */
	rcu_barrier();
	rxrpc_destroy_client_conn_ids();

	destroy_workqueue(rxrpc_workqueue);
	rxrpc_exit_security();
+3 −2
Original line number Diff line number Diff line
@@ -300,6 +300,8 @@ struct rxrpc_local {
	int			debug_id;	/* debug ID for printks */
	bool			dead;
	bool			service_closed;	/* Service socket closed */
	struct idr		conn_ids;	/* List of connection IDs */
	spinlock_t		conn_lock;	/* Lock for client connection pool */
	struct sockaddr_rxrpc	srx;		/* local address */
};

@@ -887,9 +889,8 @@ static inline bool rxrpc_is_client_call(const struct rxrpc_call *call)
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;

void rxrpc_destroy_client_conn_ids(void);
void rxrpc_destroy_client_conn_ids(struct rxrpc_local *local);
struct rxrpc_bundle *rxrpc_get_bundle(struct rxrpc_bundle *, enum rxrpc_bundle_trace);
void rxrpc_put_bundle(struct rxrpc_bundle *, enum rxrpc_bundle_trace);
int rxrpc_connect_call(struct rxrpc_sock *, struct rxrpc_call *,
+19 −25
Original line number Diff line number Diff line
@@ -34,12 +34,6 @@ __read_mostly unsigned int rxrpc_reap_client_connections = 900;
__read_mostly unsigned long rxrpc_conn_idle_client_expiry = 2 * 60 * HZ;
__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);

static void rxrpc_deactivate_bundle(struct rxrpc_bundle *bundle);

/*
@@ -51,65 +45,65 @@ static void rxrpc_deactivate_bundle(struct rxrpc_bundle *bundle);
static int rxrpc_get_client_connection_id(struct rxrpc_connection *conn,
					  gfp_t gfp)
{
	struct rxrpc_net *rxnet = conn->rxnet;
	struct rxrpc_local *local = conn->local;
	int id;

	_enter("");

	idr_preload(gfp);
	spin_lock(&rxrpc_conn_id_lock);
	spin_lock(&local->conn_lock);

	id = idr_alloc_cyclic(&rxrpc_client_conn_ids, conn,
	id = idr_alloc_cyclic(&local->conn_ids, conn,
			      1, 0x40000000, GFP_NOWAIT);
	if (id < 0)
		goto error;

	spin_unlock(&rxrpc_conn_id_lock);
	spin_unlock(&local->conn_lock);
	idr_preload_end();

	conn->proto.epoch = rxnet->epoch;
	conn->proto.epoch = local->rxnet->epoch;
	conn->proto.cid = id << RXRPC_CIDSHIFT;
	set_bit(RXRPC_CONN_HAS_IDR, &conn->flags);
	_leave(" [CID %x]", conn->proto.cid);
	return 0;

error:
	spin_unlock(&rxrpc_conn_id_lock);
	spin_unlock(&local->conn_lock);
	idr_preload_end();
	_leave(" = %d", id);
	return id;
}

/*
 * Release a connection ID for a client connection from the global pool.
 * Release a connection ID for a client connection.
 */
static void rxrpc_put_client_connection_id(struct rxrpc_connection *conn)
static void rxrpc_put_client_connection_id(struct rxrpc_local *local,
					   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,
			   conn->proto.cid >> RXRPC_CIDSHIFT);
		spin_unlock(&rxrpc_conn_id_lock);
		spin_lock(&local->conn_lock);
		idr_remove(&local->conn_ids, conn->proto.cid >> RXRPC_CIDSHIFT);
		spin_unlock(&local->conn_lock);
	}
}

/*
 * Destroy the client connection ID tree.
 */
void rxrpc_destroy_client_conn_ids(void)
void rxrpc_destroy_client_conn_ids(struct rxrpc_local *local)
{
	struct rxrpc_connection *conn;
	int id;

	if (!idr_is_empty(&rxrpc_client_conn_ids)) {
		idr_for_each_entry(&rxrpc_client_conn_ids, conn, id) {
	if (!idr_is_empty(&local->conn_ids)) {
		idr_for_each_entry(&local->conn_ids, conn, id) {
			pr_err("AF_RXRPC: Leaked client conn %p {%d}\n",
			       conn, refcount_read(&conn->ref));
		}
		BUG();
	}

	idr_destroy(&rxrpc_client_conn_ids);
	idr_destroy(&local->conn_ids);
}

/*
@@ -225,7 +219,7 @@ rxrpc_alloc_client_connection(struct rxrpc_bundle *bundle, gfp_t gfp)
	return conn;

error_1:
	rxrpc_put_client_connection_id(conn);
	rxrpc_put_client_connection_id(bundle->local, conn);
error_0:
	kfree(conn);
	_leave(" = %d", ret);
@@ -257,7 +251,7 @@ 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_cursor = idr_get_cursor(&conn->local->conn_ids);
	id = conn->proto.cid >> RXRPC_CIDSHIFT;
	distance = id - id_cursor;
	if (distance < 0)
@@ -982,7 +976,7 @@ void rxrpc_kill_client_conn(struct rxrpc_connection *conn)
	trace_rxrpc_client(conn, -1, rxrpc_client_cleanup);
	atomic_dec(&rxnet->nr_client_conns);

	rxrpc_put_client_connection_id(conn);
	rxrpc_put_client_connection_id(local, conn);
}

/*
+3 −3
Original line number Diff line number Diff line
@@ -100,10 +100,10 @@ struct rxrpc_connection *rxrpc_find_client_connection_rcu(struct rxrpc_local *lo

	_enter(",%x", sp->hdr.cid & RXRPC_CIDMASK);

	/* Look up client connections by connection ID alone as their IDs are
	 * unique for this machine.
	/* Look up client connections by connection ID alone as their
	 * IDs are unique for this machine.
	 */
	conn = idr_find(&rxrpc_client_conn_ids, sp->hdr.cid >> RXRPC_CIDSHIFT);
	conn = idr_find(&local->conn_ids, sp->hdr.cid >> RXRPC_CIDSHIFT);
	if (!conn || refcount_read(&conn->ref) == 0) {
		_debug("no conn");
		goto not_found;
+10 −0
Original line number Diff line number Diff line
@@ -89,6 +89,7 @@ static struct rxrpc_local *rxrpc_alloc_local(struct net *net,
					     const struct sockaddr_rxrpc *srx)
{
	struct rxrpc_local *local;
	u32 tmp;

	local = kzalloc(sizeof(struct rxrpc_local), GFP_KERNEL);
	if (local) {
@@ -109,6 +110,14 @@ static struct rxrpc_local *rxrpc_alloc_local(struct net *net,
		local->debug_id = atomic_inc_return(&rxrpc_debug_id);
		memcpy(&local->srx, srx, sizeof(*srx));
		local->srx.srx_service = 0;
		idr_init(&local->conn_ids);
		get_random_bytes(&tmp, sizeof(tmp));
		tmp &= 0x3fffffff;
		if (tmp == 0)
			tmp = 1;
		idr_set_cursor(&local->conn_ids, tmp);
		spin_lock_init(&local->conn_lock);

		trace_rxrpc_local(local->debug_id, rxrpc_local_new, 1, 1);
	}

@@ -409,6 +418,7 @@ void rxrpc_destroy_local(struct rxrpc_local *local)
	 * local endpoint.
	 */
	rxrpc_purge_queue(&local->rx_queue);
	rxrpc_destroy_client_conn_ids(local);
}

/*