summaryrefslogtreecommitdiffstats
path: root/net/rxrpc/ar-internal.h
diff options
context:
space:
mode:
authorDavid Howells2016-07-01 08:51:50 +0200
committerDavid Howells2016-07-06 11:51:14 +0200
commit8496af50eb385c1cadff9ad396fd5359e96b6c27 (patch)
treeea5adee605917e9b7b1d3b809dc2458cbd07c271 /net/rxrpc/ar-internal.h
parentrcu: Suppress sparse warnings for rcu_dereference_raw() (diff)
downloadkernel-qcow2-linux-8496af50eb385c1cadff9ad396fd5359e96b6c27.tar.gz
kernel-qcow2-linux-8496af50eb385c1cadff9ad396fd5359e96b6c27.tar.xz
kernel-qcow2-linux-8496af50eb385c1cadff9ad396fd5359e96b6c27.zip
rxrpc: Use RCU to access a peer's service connection tree
Move to using RCU access to a peer's service connection tree when routing an incoming packet. This is done using a seqlock to trigger retrying of the tree walk if a change happened. Further, we no longer get a ref on the connection looked up in the data_ready handler unless we queue the connection's work item - and then only if the refcount > 0. Note that I'm avoiding the use of a hash table for service connections because each service connection is addressed by a 62-bit number (constructed from epoch and connection ID >> 2) that would allow the client to engage in bucket stuffing, given knowledge of the hash algorithm. Peers, however, are hashed as the network address is less controllable by the client. The total number of peers will also be limited in a future commit. Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'net/rxrpc/ar-internal.h')
-rw-r--r--net/rxrpc/ar-internal.h21
1 files changed, 12 insertions, 9 deletions
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index 0fe63baf1286..e292276c8539 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -10,6 +10,7 @@
*/
#include <linux/atomic.h>
+#include <linux/seqlock.h>
#include <net/sock.h>
#include <net/af_rxrpc.h>
#include <rxrpc/packet.h>
@@ -206,7 +207,7 @@ struct rxrpc_peer {
struct hlist_head error_targets; /* targets for net error distribution */
struct work_struct error_distributor;
struct rb_root service_conns; /* Service connections */
- rwlock_t conn_lock;
+ seqlock_t service_conn_lock;
spinlock_t lock; /* access lock */
unsigned int if_mtu; /* interface MTU for this peer */
unsigned int mtu; /* network MTU for this peer */
@@ -559,12 +560,10 @@ extern unsigned int rxrpc_connection_expiry;
extern struct list_head rxrpc_connections;
extern rwlock_t rxrpc_connection_lock;
-void rxrpc_conn_hash_proto_key(struct rxrpc_conn_proto *);
-void rxrpc_extract_conn_params(struct rxrpc_conn_proto *,
- struct rxrpc_local *, struct sk_buff *);
+int rxrpc_extract_addr_from_skb(struct sockaddr_rxrpc *, struct sk_buff *);
struct rxrpc_connection *rxrpc_alloc_connection(gfp_t);
-struct rxrpc_connection *rxrpc_find_connection(struct rxrpc_local *,
- struct sk_buff *);
+struct rxrpc_connection *rxrpc_find_connection_rcu(struct rxrpc_local *,
+ struct sk_buff *);
void __rxrpc_disconnect_call(struct rxrpc_call *);
void rxrpc_disconnect_call(struct rxrpc_call *);
void rxrpc_put_connection(struct rxrpc_connection *);
@@ -591,16 +590,20 @@ struct rxrpc_connection *rxrpc_get_connection_maybe(struct rxrpc_connection *con
return atomic_inc_not_zero(&conn->usage) ? conn : NULL;
}
-static inline void rxrpc_queue_conn(struct rxrpc_connection *conn)
+static inline bool rxrpc_queue_conn(struct rxrpc_connection *conn)
{
- if (rxrpc_get_connection_maybe(conn) &&
- !rxrpc_queue_work(&conn->processor))
+ if (!rxrpc_get_connection_maybe(conn))
+ return false;
+ if (!rxrpc_queue_work(&conn->processor))
rxrpc_put_connection(conn);
+ return true;
}
/*
* conn_service.c
*/
+struct rxrpc_connection *rxrpc_find_service_conn_rcu(struct rxrpc_peer *,
+ struct sk_buff *);
struct rxrpc_connection *rxrpc_incoming_connection(struct rxrpc_local *,
struct sockaddr_rxrpc *,
struct sk_buff *);