Commit 2baec2c3 authored by David Howells's avatar David Howells Committed by David S. Miller

rxrpc: Support network namespacing

Support network namespacing in AF_RXRPC with the following changes:

 (1) All the local endpoint, peer and call lists, locks, counters, etc. are
     moved into the per-namespace record.

 (2) All the connection tracking is moved into the per-namespace record
     with the exception of the client connection ID tree, which is kept
     global so that connection IDs are kept unique per-machine.

 (3) Each namespace gets its own epoch.  This allows each network namespace
     to pretend to be a separate client machine.

 (4) The /proc/net/rxrpc_xxx files are now called /proc/net/rxrpc/xxx and
     the contents reflect the namespace.

fs/afs/ should be okay with this patch as it explicitly requires the current
net namespace to be init_net to permit a mount to proceed at the moment.  It
will, however, need updating so that cells, IP addresses and DNS records are
per-namespace also.
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 878cd3ba
...@@ -19,6 +19,7 @@ rxrpc-y := \ ...@@ -19,6 +19,7 @@ rxrpc-y := \
local_event.o \ local_event.o \
local_object.o \ local_object.o \
misc.o \ misc.o \
net_ns.o \
output.o \ output.o \
peer_event.o \ peer_event.o \
peer_object.o \ peer_object.o \
......
...@@ -38,9 +38,6 @@ MODULE_PARM_DESC(debug, "RxRPC debugging mask"); ...@@ -38,9 +38,6 @@ MODULE_PARM_DESC(debug, "RxRPC debugging mask");
static struct proto rxrpc_proto; static struct proto rxrpc_proto;
static const struct proto_ops rxrpc_rpc_ops; static const struct proto_ops rxrpc_rpc_ops;
/* local epoch for detecting local-end reset */
u32 rxrpc_epoch;
/* current debugging ID */ /* current debugging ID */
atomic_t rxrpc_debug_id; atomic_t rxrpc_debug_id;
...@@ -155,7 +152,7 @@ static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len) ...@@ -155,7 +152,7 @@ static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len)
memcpy(&rx->srx, srx, sizeof(rx->srx)); memcpy(&rx->srx, srx, sizeof(rx->srx));
local = rxrpc_lookup_local(&rx->srx); local = rxrpc_lookup_local(sock_net(sock->sk), &rx->srx);
if (IS_ERR(local)) { if (IS_ERR(local)) {
ret = PTR_ERR(local); ret = PTR_ERR(local);
goto error_unlock; goto error_unlock;
...@@ -434,7 +431,7 @@ static int rxrpc_sendmsg(struct socket *sock, struct msghdr *m, size_t len) ...@@ -434,7 +431,7 @@ static int rxrpc_sendmsg(struct socket *sock, struct msghdr *m, size_t len)
ret = -EAFNOSUPPORT; ret = -EAFNOSUPPORT;
goto error_unlock; goto error_unlock;
} }
local = rxrpc_lookup_local(&rx->srx); local = rxrpc_lookup_local(sock_net(sock->sk), &rx->srx);
if (IS_ERR(local)) { if (IS_ERR(local)) {
ret = PTR_ERR(local); ret = PTR_ERR(local);
goto error_unlock; goto error_unlock;
...@@ -582,9 +579,6 @@ static int rxrpc_create(struct net *net, struct socket *sock, int protocol, ...@@ -582,9 +579,6 @@ static int rxrpc_create(struct net *net, struct socket *sock, int protocol,
_enter("%p,%d", sock, protocol); _enter("%p,%d", sock, protocol);
if (!net_eq(net, &init_net))
return -EAFNOSUPPORT;
/* we support transport protocol UDP/UDP6 only */ /* we support transport protocol UDP/UDP6 only */
if (protocol != PF_INET && if (protocol != PF_INET &&
IS_ENABLED(CONFIG_AF_RXRPC_IPV6) && protocol != PF_INET6) IS_ENABLED(CONFIG_AF_RXRPC_IPV6) && protocol != PF_INET6)
...@@ -780,8 +774,6 @@ static int __init af_rxrpc_init(void) ...@@ -780,8 +774,6 @@ static int __init af_rxrpc_init(void)
BUILD_BUG_ON(sizeof(struct rxrpc_skb_priv) > FIELD_SIZEOF(struct sk_buff, cb)); BUILD_BUG_ON(sizeof(struct rxrpc_skb_priv) > FIELD_SIZEOF(struct sk_buff, cb));
get_random_bytes(&rxrpc_epoch, sizeof(rxrpc_epoch));
rxrpc_epoch |= RXRPC_RANDOM_EPOCH;
get_random_bytes(&tmp, sizeof(tmp)); get_random_bytes(&tmp, sizeof(tmp));
tmp &= 0x3fffffff; tmp &= 0x3fffffff;
if (tmp == 0) if (tmp == 0)
...@@ -809,6 +801,10 @@ static int __init af_rxrpc_init(void) ...@@ -809,6 +801,10 @@ static int __init af_rxrpc_init(void)
goto error_security; goto error_security;
} }
ret = register_pernet_subsys(&rxrpc_net_ops);
if (ret)
goto error_pernet;
ret = proto_register(&rxrpc_proto, 1); ret = proto_register(&rxrpc_proto, 1);
if (ret < 0) { if (ret < 0) {
pr_crit("Cannot register protocol\n"); pr_crit("Cannot register protocol\n");
...@@ -839,11 +835,6 @@ static int __init af_rxrpc_init(void) ...@@ -839,11 +835,6 @@ static int __init af_rxrpc_init(void)
goto error_sysctls; goto error_sysctls;
} }
#ifdef CONFIG_PROC_FS
proc_create("rxrpc_calls", 0, init_net.proc_net, &rxrpc_call_seq_fops);
proc_create("rxrpc_conns", 0, init_net.proc_net,
&rxrpc_connection_seq_fops);
#endif
return 0; return 0;
error_sysctls: error_sysctls:
...@@ -855,6 +846,8 @@ static int __init af_rxrpc_init(void) ...@@ -855,6 +846,8 @@ static int __init af_rxrpc_init(void)
error_sock: error_sock:
proto_unregister(&rxrpc_proto); proto_unregister(&rxrpc_proto);
error_proto: error_proto:
unregister_pernet_subsys(&rxrpc_net_ops);
error_pernet:
rxrpc_exit_security(); rxrpc_exit_security();
error_security: error_security:
destroy_workqueue(rxrpc_workqueue); destroy_workqueue(rxrpc_workqueue);
...@@ -875,14 +868,16 @@ static void __exit af_rxrpc_exit(void) ...@@ -875,14 +868,16 @@ static void __exit af_rxrpc_exit(void)
unregister_key_type(&key_type_rxrpc); unregister_key_type(&key_type_rxrpc);
sock_unregister(PF_RXRPC); sock_unregister(PF_RXRPC);
proto_unregister(&rxrpc_proto); proto_unregister(&rxrpc_proto);
rxrpc_destroy_all_calls(); unregister_pernet_subsys(&rxrpc_net_ops);
rxrpc_destroy_all_connections();
ASSERTCMP(atomic_read(&rxrpc_n_tx_skbs), ==, 0); ASSERTCMP(atomic_read(&rxrpc_n_tx_skbs), ==, 0);
ASSERTCMP(atomic_read(&rxrpc_n_rx_skbs), ==, 0); ASSERTCMP(atomic_read(&rxrpc_n_rx_skbs), ==, 0);
rxrpc_destroy_all_locals();
remove_proc_entry("rxrpc_conns", init_net.proc_net); /* Make sure the local and peer records pinned by any dying connections
remove_proc_entry("rxrpc_calls", init_net.proc_net); * are released.
*/
rcu_barrier();
rxrpc_destroy_client_conn_ids();
destroy_workqueue(rxrpc_workqueue); destroy_workqueue(rxrpc_workqueue);
rxrpc_exit_security(); rxrpc_exit_security();
kmem_cache_destroy(rxrpc_call_jar); kmem_cache_destroy(rxrpc_call_jar);
......
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
#include <linux/atomic.h> #include <linux/atomic.h>
#include <linux/seqlock.h> #include <linux/seqlock.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/af_rxrpc.h> #include <net/af_rxrpc.h>
#include <rxrpc/packet.h> #include <rxrpc/packet.h>
...@@ -64,6 +66,37 @@ enum { ...@@ -64,6 +66,37 @@ enum {
RXRPC_CLOSE, /* socket is being closed */ RXRPC_CLOSE, /* socket is being closed */
}; };
/*
* Per-network namespace data.
*/
struct rxrpc_net {
struct proc_dir_entry *proc_net; /* Subdir in /proc/net */
u32 epoch; /* Local epoch for detecting local-end reset */
struct list_head calls; /* List of calls active in this namespace */
rwlock_t call_lock; /* Lock for ->calls */
struct list_head conn_proc_list; /* List of conns in this namespace for proc */
struct list_head service_conns; /* Service conns in this namespace */
rwlock_t conn_lock; /* Lock for ->conn_proc_list, ->service_conns */
struct delayed_work service_conn_reaper;
unsigned int nr_client_conns;
unsigned int nr_active_client_conns;
bool kill_all_client_conns;
spinlock_t client_conn_cache_lock; /* Lock for ->*_client_conns */
spinlock_t client_conn_discard_lock; /* Prevent multiple discarders */
struct list_head waiting_client_conns;
struct list_head active_client_conns;
struct list_head idle_client_conns;
struct delayed_work client_conn_reaper;
struct list_head local_endpoints;
struct mutex local_mutex; /* Lock for ->local_endpoints */
spinlock_t peer_hash_lock; /* Lock for ->peer_hash */
DECLARE_HASHTABLE (peer_hash, 10);
};
/* /*
* Service backlog preallocation. * Service backlog preallocation.
* *
...@@ -211,6 +244,7 @@ struct rxrpc_security { ...@@ -211,6 +244,7 @@ struct rxrpc_security {
struct rxrpc_local { struct rxrpc_local {
struct rcu_head rcu; struct rcu_head rcu;
atomic_t usage; atomic_t usage;
struct rxrpc_net *rxnet; /* The network ns in which this resides */
struct list_head link; struct list_head link;
struct socket *socket; /* my UDP socket */ struct socket *socket; /* my UDP socket */
struct work_struct processor; struct work_struct processor;
...@@ -601,7 +635,6 @@ struct rxrpc_ack_summary { ...@@ -601,7 +635,6 @@ struct rxrpc_ack_summary {
* af_rxrpc.c * af_rxrpc.c
*/ */
extern atomic_t rxrpc_n_tx_skbs, rxrpc_n_rx_skbs; extern atomic_t rxrpc_n_tx_skbs, rxrpc_n_rx_skbs;
extern u32 rxrpc_epoch;
extern atomic_t rxrpc_debug_id; extern atomic_t rxrpc_debug_id;
extern struct workqueue_struct *rxrpc_workqueue; extern struct workqueue_struct *rxrpc_workqueue;
...@@ -634,8 +667,6 @@ extern const char *const rxrpc_call_states[]; ...@@ -634,8 +667,6 @@ extern const char *const rxrpc_call_states[];
extern const char *const rxrpc_call_completions[]; extern const char *const rxrpc_call_completions[];
extern unsigned int rxrpc_max_call_lifetime; extern unsigned int rxrpc_max_call_lifetime;
extern struct kmem_cache *rxrpc_call_jar; extern struct kmem_cache *rxrpc_call_jar;
extern struct list_head rxrpc_calls;
extern rwlock_t rxrpc_call_lock;
struct rxrpc_call *rxrpc_find_call_by_user_ID(struct rxrpc_sock *, unsigned long); struct rxrpc_call *rxrpc_find_call_by_user_ID(struct rxrpc_sock *, unsigned long);
struct rxrpc_call *rxrpc_alloc_call(gfp_t); struct rxrpc_call *rxrpc_alloc_call(gfp_t);
...@@ -653,7 +684,7 @@ void rxrpc_see_call(struct rxrpc_call *); ...@@ -653,7 +684,7 @@ void rxrpc_see_call(struct rxrpc_call *);
void rxrpc_get_call(struct rxrpc_call *, enum rxrpc_call_trace); void rxrpc_get_call(struct rxrpc_call *, enum rxrpc_call_trace);
void rxrpc_put_call(struct rxrpc_call *, enum rxrpc_call_trace); void rxrpc_put_call(struct rxrpc_call *, enum rxrpc_call_trace);
void rxrpc_cleanup_call(struct rxrpc_call *); void rxrpc_cleanup_call(struct rxrpc_call *);
void __exit rxrpc_destroy_all_calls(void); void rxrpc_destroy_all_calls(struct rxrpc_net *);
static inline bool rxrpc_is_service_call(const struct rxrpc_call *call) static inline bool rxrpc_is_service_call(const struct rxrpc_call *call)
{ {
...@@ -773,7 +804,8 @@ int rxrpc_connect_call(struct rxrpc_call *, struct rxrpc_conn_parameters *, ...@@ -773,7 +804,8 @@ int rxrpc_connect_call(struct rxrpc_call *, struct rxrpc_conn_parameters *,
void rxrpc_expose_client_call(struct rxrpc_call *); void rxrpc_expose_client_call(struct rxrpc_call *);
void rxrpc_disconnect_client_call(struct rxrpc_call *); void rxrpc_disconnect_client_call(struct rxrpc_call *);
void rxrpc_put_client_conn(struct rxrpc_connection *); void rxrpc_put_client_conn(struct rxrpc_connection *);
void __exit rxrpc_destroy_all_client_connections(void); void rxrpc_discard_expired_client_conns(struct work_struct *);
void rxrpc_destroy_all_client_connections(struct rxrpc_net *);
/* /*
* conn_event.c * conn_event.c
...@@ -784,9 +816,6 @@ void rxrpc_process_connection(struct work_struct *); ...@@ -784,9 +816,6 @@ void rxrpc_process_connection(struct work_struct *);
* conn_object.c * conn_object.c
*/ */
extern unsigned int rxrpc_connection_expiry; extern unsigned int rxrpc_connection_expiry;
extern struct list_head rxrpc_connections;
extern struct list_head rxrpc_connection_proc_list;
extern rwlock_t rxrpc_connection_lock;
int rxrpc_extract_addr_from_skb(struct sockaddr_rxrpc *, 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_alloc_connection(gfp_t);
...@@ -800,7 +829,8 @@ void rxrpc_see_connection(struct rxrpc_connection *); ...@@ -800,7 +829,8 @@ void rxrpc_see_connection(struct rxrpc_connection *);
void rxrpc_get_connection(struct rxrpc_connection *); void rxrpc_get_connection(struct rxrpc_connection *);
struct rxrpc_connection *rxrpc_get_connection_maybe(struct rxrpc_connection *); struct rxrpc_connection *rxrpc_get_connection_maybe(struct rxrpc_connection *);
void rxrpc_put_service_conn(struct rxrpc_connection *); void rxrpc_put_service_conn(struct rxrpc_connection *);
void __exit rxrpc_destroy_all_connections(void); void rxrpc_service_connection_reaper(struct work_struct *);
void rxrpc_destroy_all_connections(struct rxrpc_net *);
static inline bool rxrpc_conn_is_client(const struct rxrpc_connection *conn) static inline bool rxrpc_conn_is_client(const struct rxrpc_connection *conn)
{ {
...@@ -828,7 +858,7 @@ static inline void rxrpc_put_connection(struct rxrpc_connection *conn) ...@@ -828,7 +858,7 @@ static inline void rxrpc_put_connection(struct rxrpc_connection *conn)
*/ */
struct rxrpc_connection *rxrpc_find_service_conn_rcu(struct rxrpc_peer *, struct rxrpc_connection *rxrpc_find_service_conn_rcu(struct rxrpc_peer *,
struct sk_buff *); struct sk_buff *);
struct rxrpc_connection *rxrpc_prealloc_service_connection(gfp_t); struct rxrpc_connection *rxrpc_prealloc_service_connection(struct rxrpc_net *, gfp_t);
void rxrpc_new_incoming_connection(struct rxrpc_connection *, struct sk_buff *); void rxrpc_new_incoming_connection(struct rxrpc_connection *, struct sk_buff *);
void rxrpc_unpublish_service_conn(struct rxrpc_connection *); void rxrpc_unpublish_service_conn(struct rxrpc_connection *);
...@@ -861,9 +891,9 @@ extern void rxrpc_process_local_events(struct rxrpc_local *); ...@@ -861,9 +891,9 @@ extern void rxrpc_process_local_events(struct rxrpc_local *);
/* /*
* local_object.c * local_object.c
*/ */
struct rxrpc_local *rxrpc_lookup_local(const struct sockaddr_rxrpc *); struct rxrpc_local *rxrpc_lookup_local(struct net *, const struct sockaddr_rxrpc *);
void __rxrpc_put_local(struct rxrpc_local *); void __rxrpc_put_local(struct rxrpc_local *);
void __exit rxrpc_destroy_all_locals(void); void rxrpc_destroy_all_locals(struct rxrpc_net *);
static inline void rxrpc_get_local(struct rxrpc_local *local) static inline void rxrpc_get_local(struct rxrpc_local *local)
{ {
...@@ -901,6 +931,17 @@ extern unsigned int rxrpc_resend_timeout; ...@@ -901,6 +931,17 @@ extern unsigned int rxrpc_resend_timeout;
extern const s8 rxrpc_ack_priority[]; extern const s8 rxrpc_ack_priority[];
/*
* net_ns.c
*/
extern unsigned int rxrpc_net_id;
extern struct pernet_operations rxrpc_net_ops;
static inline struct rxrpc_net *rxrpc_net(struct net *net)
{
return net_generic(net, rxrpc_net_id);
}
/* /*
* output.c * output.c
*/ */
......
...@@ -38,6 +38,7 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx, ...@@ -38,6 +38,7 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx,
{ {
const void *here = __builtin_return_address(0); const void *here = __builtin_return_address(0);
struct rxrpc_call *call; struct rxrpc_call *call;
struct rxrpc_net *rxnet = rxrpc_net(sock_net(&rx->sk));
int max, tmp; int max, tmp;
unsigned int size = RXRPC_BACKLOG_MAX; unsigned int size = RXRPC_BACKLOG_MAX;
unsigned int head, tail, call_head, call_tail; unsigned int head, tail, call_head, call_tail;
...@@ -79,7 +80,7 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx, ...@@ -79,7 +80,7 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx,
if (CIRC_CNT(head, tail, size) < max) { if (CIRC_CNT(head, tail, size) < max) {
struct rxrpc_connection *conn; struct rxrpc_connection *conn;
conn = rxrpc_prealloc_service_connection(gfp); conn = rxrpc_prealloc_service_connection(rxnet, gfp);
if (!conn) if (!conn)
return -ENOMEM; return -ENOMEM;
b->conn_backlog[head] = conn; b->conn_backlog[head] = conn;
...@@ -136,9 +137,9 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx, ...@@ -136,9 +137,9 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx,
write_unlock(&rx->call_lock); write_unlock(&rx->call_lock);
write_lock(&rxrpc_call_lock); write_lock(&rxnet->call_lock);
list_add_tail(&call->link, &rxrpc_calls); list_add_tail(&call->link, &rxnet->calls);
write_unlock(&rxrpc_call_lock); write_unlock(&rxnet->call_lock);
b->call_backlog[call_head] = call; b->call_backlog[call_head] = call;
smp_store_release(&b->call_backlog_head, (call_head + 1) & (size - 1)); smp_store_release(&b->call_backlog_head, (call_head + 1) & (size - 1));
...@@ -185,6 +186,7 @@ int rxrpc_service_prealloc(struct rxrpc_sock *rx, gfp_t gfp) ...@@ -185,6 +186,7 @@ int rxrpc_service_prealloc(struct rxrpc_sock *rx, gfp_t gfp)
void rxrpc_discard_prealloc(struct rxrpc_sock *rx) void rxrpc_discard_prealloc(struct rxrpc_sock *rx)
{ {
struct rxrpc_backlog *b = rx->backlog; struct rxrpc_backlog *b = rx->backlog;
struct rxrpc_net *rxnet = rxrpc_net(sock_net(&rx->sk));
unsigned int size = RXRPC_BACKLOG_MAX, head, tail; unsigned int size = RXRPC_BACKLOG_MAX, head, tail;
if (!b) if (!b)
...@@ -209,10 +211,10 @@ void rxrpc_discard_prealloc(struct rxrpc_sock *rx) ...@@ -209,10 +211,10 @@ void rxrpc_discard_prealloc(struct rxrpc_sock *rx)
tail = b->conn_backlog_tail; tail = b->conn_backlog_tail;
while (CIRC_CNT(head, tail, size) > 0) { while (CIRC_CNT(head, tail, size) > 0) {
struct rxrpc_connection *conn = b->conn_backlog[tail]; struct rxrpc_connection *conn = b->conn_backlog[tail];
write_lock(&rxrpc_connection_lock); write_lock(&rxnet->conn_lock);
list_del(&conn->link); list_del(&conn->link);
list_del(&conn->proc_link); list_del(&conn->proc_link);
write_unlock(&rxrpc_connection_lock); write_unlock(&rxnet->conn_lock);
kfree(conn); kfree(conn);
tail = (tail + 1) & (size - 1); tail = (tail + 1) & (size - 1);
} }
......
...@@ -44,8 +44,6 @@ const char *const rxrpc_call_completions[NR__RXRPC_CALL_COMPLETIONS] = { ...@@ -44,8 +44,6 @@ const char *const rxrpc_call_completions[NR__RXRPC_CALL_COMPLETIONS] = {
}; };
struct kmem_cache *rxrpc_call_jar; struct kmem_cache *rxrpc_call_jar;
LIST_HEAD(rxrpc_calls);
DEFINE_RWLOCK(rxrpc_call_lock);
static void rxrpc_call_timer_expired(unsigned long _call) static void rxrpc_call_timer_expired(unsigned long _call)
{ {
...@@ -207,6 +205,7 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx, ...@@ -207,6 +205,7 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,
__releases(&rx->sk.sk_lock.slock) __releases(&rx->sk.sk_lock.slock)
{ {
struct rxrpc_call *call, *xcall; struct rxrpc_call *call, *xcall;
struct rxrpc_net *rxnet = rxrpc_net(sock_net(&rx->sk));
struct rb_node *parent, **pp; struct rb_node *parent, **pp;
const void *here = __builtin_return_address(0); const void *here = __builtin_return_address(0);
int ret; int ret;
...@@ -255,9 +254,9 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx, ...@@ -255,9 +254,9 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,
write_unlock(&rx->call_lock); write_unlock(&rx->call_lock);
write_lock(&rxrpc_call_lock); write_lock(&rxnet->call_lock);
list_add_tail(&call->link, &rxrpc_calls); list_add_tail(&call->link, &rxnet->calls);
write_unlock(&rxrpc_call_lock); write_unlock(&rxnet->call_lock);
/* From this point on, the call is protected by its own lock. */ /* From this point on, the call is protected by its own lock. */
release_sock(&rx->sk); release_sock(&rx->sk);
...@@ -508,6 +507,7 @@ void rxrpc_release_calls_on_socket(struct rxrpc_sock *rx) ...@@ -508,6 +507,7 @@ void rxrpc_release_calls_on_socket(struct rxrpc_sock *rx)
*/ */
void rxrpc_put_call(struct rxrpc_call *call, enum rxrpc_call_trace op) void rxrpc_put_call(struct rxrpc_call *call, enum rxrpc_call_trace op)
{ {
struct rxrpc_net *rxnet;
const void *here = __builtin_return_address(0); const void *here = __builtin_return_address(0);
int n; int n;
...@@ -520,9 +520,12 @@ void rxrpc_put_call(struct rxrpc_call *call, enum rxrpc_call_trace op) ...@@ -520,9 +520,12 @@ void rxrpc_put_call(struct rxrpc_call *call, enum rxrpc_call_trace op)
_debug("call %d dead", call->debug_id); _debug("call %d dead", call->debug_id);
ASSERTCMP(call->state, ==, RXRPC_CALL_COMPLETE); ASSERTCMP(call->state, ==, RXRPC_CALL_COMPLETE);
write_lock(&rxrpc_call_lock); if (!list_empty(&call->link)) {
rxnet = rxrpc_net(sock_net(&call->socket->sk));
write_lock(&rxnet->call_lock);
list_del_init(&call->link); list_del_init(&call->link);
write_unlock(&rxrpc_call_lock); write_unlock(&rxnet->call_lock);
}
rxrpc_cleanup_call(call); rxrpc_cleanup_call(call);
} }
...@@ -570,21 +573,23 @@ void rxrpc_cleanup_call(struct rxrpc_call *call) ...@@ -570,21 +573,23 @@ void rxrpc_cleanup_call(struct rxrpc_call *call)
} }
/* /*
* Make sure that all calls are gone. * Make sure that all calls are gone from a network namespace. To reach this
* point, any open UDP sockets in that namespace must have been closed, so any
* outstanding calls cannot be doing I/O.
*/ */
void __exit rxrpc_destroy_all_calls(void) void rxrpc_destroy_all_calls(struct rxrpc_net *rxnet)
{ {
struct rxrpc_call *call; struct rxrpc_call *call;
_enter(""); _enter("");
if (list_empty(&rxrpc_calls)) if (list_empty(&rxnet->calls))
return; return;
write_lock(&rxrpc_call_lock); write_lock(&rxnet->call_lock);
while (!list_empty(&rxrpc_calls)) { while (!list_empty(&rxnet->calls)) {
call = list_entry(rxrpc_calls.next, struct rxrpc_call, link); call = list_entry(rxnet->calls.next, struct rxrpc_call, link);
_debug("Zapping call %p", call); _debug("Zapping call %p", call);
rxrpc_see_call(call); rxrpc_see_call(call);
...@@ -595,10 +600,10 @@ void __exit rxrpc_destroy_all_calls(void) ...@@ -595,10 +600,10 @@ void __exit rxrpc_destroy_all_calls(void)
rxrpc_call_states[call->state], rxrpc_call_states[call->state],
call->flags, call->events); call->flags, call->events);
write_unlock(&rxrpc_call_lock); write_unlock(&rxnet->call_lock);
cond_resched(); cond_resched();
write_lock(&rxrpc_call_lock); write_lock(&rxnet->call_lock);
} }
write_unlock(&rxrpc_call_lock); write_unlock(&rxnet->call_lock);
} }
This diff is collapsed.
...@@ -22,13 +22,6 @@ ...@@ -22,13 +22,6 @@
*/ */
unsigned int rxrpc_connection_expiry = 10 * 60; unsigned int rxrpc_connection_expiry = 10 * 60;
static void rxrpc_connection_reaper(struct work_struct *work);
LIST_HEAD(rxrpc_connections);
LIST_HEAD(rxrpc_connection_proc_list);
DEFINE_RWLOCK(rxrpc_connection_lock);
static DECLARE_DELAYED_WORK(rxrpc_connection_reap, rxrpc_connection_reaper);
static void rxrpc_destroy_connection(struct rcu_head *); static void rxrpc_destroy_connection(struct rcu_head *);
/* /*
...@@ -222,15 +215,17 @@ void rxrpc_disconnect_call(struct rxrpc_call *call) ...@@ -222,15 +215,17 @@ void rxrpc_disconnect_call(struct rxrpc_call *call)
*/ */
void rxrpc_kill_connection(struct rxrpc_connection *conn) void rxrpc_kill_connection(struct rxrpc_connection *conn)
{ {
struct rxrpc_net *rxnet = conn->params.local->rxnet;
ASSERT(!rcu_access_pointer(conn->channels[0].call) && ASSERT(!rcu_access_pointer(conn->channels[0].call) &&
!rcu_access_pointer(conn->channels[1].call) && !rcu_access_pointer(conn->channels[1].call) &&
!rcu_access_pointer(conn->channels[2].call) && !rcu_access_pointer(conn->channels[2].call) &&
!rcu_access_pointer(conn->channels[3].call)); !rcu_access_pointer(conn->channels[3].call));
ASSERT(list_empty(&conn->cache_link)); ASSERT(list_empty(&conn->cache_link));
write_lock(&rxrpc_connection_lock); write_lock(&rxnet->conn_lock);
list_del_init(&conn->proc_link); list_del_init(&conn->proc_link);
write_unlock(&rxrpc_connection_lock); write_unlock(&rxnet->conn_lock);
/* Drain the Rx queue. Note that even though we've unpublished, an /* Drain the Rx queue. Note that even though we've unpublished, an
* incoming packet could still be being added to our Rx queue, so we * incoming packet could still be being added to our Rx queue, so we
...@@ -309,14 +304,17 @@ rxrpc_get_connection_maybe(struct rxrpc_connection *conn) ...@@ -309,14 +304,17 @@ rxrpc_get_connection_maybe(struct rxrpc_connection *conn)
*/ */
void rxrpc_put_service_conn(struct rxrpc_connection *conn) void rxrpc_put_service_conn(struct rxrpc_connection *conn)
{ {
struct rxrpc_net *rxnet;
const void *here = __builtin_return_address(0); const void *here = __builtin_return_address(0);
int n; int n;
n = atomic_dec_return(&conn->usage); n = atomic_dec_return(&conn->usage);
trace_rxrpc_conn(conn, rxrpc_conn_put_service, n, here); trace_rxrpc_conn(conn, rxrpc_conn_put_service, n, here);
ASSERTCMP(n, >=, 0); ASSERTCMP(n, >=, 0);
if (n == 0) if (n == 0) {
rxrpc_queue_delayed_work(&rxrpc_connection_reap, 0); rxnet = conn->params.local->rxnet;
rxrpc_queue_delayed_work(&rxnet->service_conn_reaper, 0);
}
} }
/* /*
...@@ -348,9 +346,12 @@ static void rxrpc_destroy_connection(struct rcu_head *rcu) ...@@ -348,9 +346,12 @@ static void rxrpc_destroy_connection(struct rcu_head *rcu)
/* /*
* reap dead service connections * reap dead service connections
*/ */
static void rxrpc_connection_reaper(struct work_struct *work) void rxrpc_service_connection_reaper(struct work_struct *work)
{ {
struct rxrpc_connection *conn, *_p; struct rxrpc_connection *conn, *_p;
struct rxrpc_net *rxnet =
container_of(to_delayed_work(work),
struct rxrpc_net, service_conn_reaper);
unsigned long reap_older_than, earliest, idle_timestamp, now; unsigned long reap_older_than, earliest, idle_timestamp, now;
LIST_HEAD(graveyard); LIST_HEAD(graveyard);
...@@ -361,8 +362,8 @@ static void rxrpc_connection_reaper(struct work_struct *work) ...@@ -361,8 +362,8 @@ static void rxrpc_connection_reaper(struct work_struct *work)
reap_older_than = now - rxrpc_connection_expiry * HZ; reap_older_than = now - rxrpc_connection_expiry * HZ;
earliest = ULONG_MAX; earliest = ULONG_MAX;
write_lock(&rxrpc_connection_lock); write_lock(&rxnet->conn_lock);
list_for_each_entry_safe(conn, _p, &rxrpc_connections, link) { list_for_each_entry_safe(conn, _p, &rxnet->service_conns, link) {
ASSERTCMP(atomic_read(&conn->usage), >, 0); ASSERTCMP(atomic_read(&conn->usage), >, 0);
if (likely(atomic_read(&conn->usage) > 1)) if (likely(atomic_read(&conn->usage) > 1))
continue; continue;
...@@ -393,12 +394,12 @@ static void rxrpc_connection_reaper(struct work_struct *work) ...@@ -393,12 +394,12 @@ static void rxrpc_connection_reaper(struct work_struct *work)
list_move_tail(&conn->link, &graveyard); list_move_tail(&conn->link, &graveyard);
} }
write_unlock(&rxrpc_connection_lock); write_unlock(&rxnet->conn_lock);
if (earliest != ULONG_MAX) { if (earliest != ULONG_MAX) {
_debug("reschedule reaper %ld", (long) earliest - now); _debug("reschedule reaper %ld", (long) earliest - now);
ASSERT(time_after(earliest, now)); ASSERT(time_after(earliest, now));
rxrpc_queue_delayed_work(&rxrpc_connection_reap, rxrpc_queue_delayed_work(&rxnet->client_conn_reaper,
earliest - now); earliest - now);
} }
...@@ -418,36 +419,30 @@ static void rxrpc_connection_reaper(struct work_struct *work) ...@@ -418,36 +419,30 @@ static void rxrpc_connection_reaper(struct work_struct *work)
* preemptively destroy all the service connection records rather than * preemptively destroy all the service connection records rather than
* waiting for them to time out * waiting for them to time out
*/ */
void __exit rxrpc_destroy_all_connections(void) void rxrpc_destroy_all_connections(struct rxrpc_net *rxnet)
{ {
struct rxrpc_connection *conn, *_p; struct rxrpc_connection *conn, *_p;
bool leak = false; bool leak = false;
_enter(""); _enter("");
rxrpc_destroy_all_client_connections(); rxrpc_destroy_all_client_connections(rxnet);
rxrpc_connection_expiry = 0; rxrpc_connection_expiry = 0;
cancel_delayed_work(&rxrpc_connection_reap); cancel_delayed_work(&rxnet->client_conn_reaper);
rxrpc_queue_delayed_work(&rxrpc_connection_reap, 0); rxrpc_queue_delayed_work(&rxnet->client_conn_reaper, 0);
flush_workqueue(rxrpc_workqueue); flush_workqueue(rxrpc_workqueue);
write_lock(&rxrpc_connection_lock); write_lock(&rxnet->conn_lock);
list_for_each_entry_safe(conn, _p, &rxrpc_connections, link) { list_for_each_entry_safe(conn, _p, &rxnet->service_conns, link) {
pr_err("AF_RXRPC: Leaked conn %p {%d}\n", pr_err("AF_RXRPC: Leaked conn %p {%d}\n",
conn, atomic_read(&conn->usage)); conn, atomic_read(&conn->usage));
leak = true; leak = true;
} }
write_unlock(&rxrpc_connection_lock); write_unlock(&rxnet->conn_lock);
BUG_ON(leak); BUG_ON(leak);
ASSERT(list_empty(&rxrpc_connection_proc_list)); ASSERT(list_empty(&rxnet->conn_proc_list));
/* Make sure the local and peer records pinned by any dying connections
* are released.
*/
rcu_barrier();
rxrpc_destroy_client_conn_ids();
_leave(""); _leave("");
} }
...@@ -121,7 +121,8 @@ static void rxrpc_publish_service_conn(struct rxrpc_peer *peer, ...@@ -121,7 +121,8 @@ static void rxrpc_publish_service_conn(struct rxrpc_peer *peer,
* Preallocate a service connection. The connection is placed on the proc and * Preallocate a service connection. The connection is placed on the proc and
* reap lists so that we don't have to get the lock from BH context. * reap lists so that we don't have to get the lock from BH context.
*/ */
struct rxrpc_connection *rxrpc_prealloc_service_connection(gfp_t gfp) struct rxrpc_connection *rxrpc_prealloc_service_connection(struct rxrpc_net *rxnet,
gfp_t gfp)
{ {
struct rxrpc_connection *conn = rxrpc_alloc_connection(gfp); struct rxrpc_connection *conn = rxrpc_alloc_connection(gfp);
...@@ -132,10 +133,10 @@ struct rxrpc_connection *rxrpc_prealloc_service_connection(gfp_t gfp) ...@@ -132,10 +133,10 @@ struct rxrpc_connection *rxrpc_prealloc_service_connection(gfp_t gfp)
conn->state = RXRPC_CONN_SERVICE_PREALLOC; conn->state = RXRPC_CONN_SERVICE_PREALLOC;
atomic_set(&conn->usage, 2); atomic_set(&conn->usage, 2);
write_lock(&rxrpc_connection_lock); write_lock(&rxnet->conn_lock);
list_add_tail(&conn->link, &rxrpc_connections); list_add_tail(&conn->link, &rxnet->service_conns);
list_add_tail(&conn->proc_link, &rxrpc_connection_proc_list); list_add_tail(&conn->proc_link, &rxnet->conn_proc_list);
write_unlock(&rxrpc_connection_lock); write_unlock(&rxnet->conn_lock);
trace_rxrpc_conn(conn, rxrpc_conn_new_service, trace_rxrpc_conn(conn, rxrpc_conn_new_service,
atomic_read(&conn->usage), atomic_read(&conn->usage),
......
...@@ -25,9 +25,6 @@ ...@@ -25,9 +25,6 @@
static void rxrpc_local_processor(struct work_struct *); static void rxrpc_local_processor(struct work_struct *);
static void rxrpc_local_rcu(struct rcu_head *); static void rxrpc_local_rcu(struct rcu_head *);
static DEFINE_MUTEX(rxrpc_local_mutex);
static LIST_HEAD(rxrpc_local_endpoints);
/* /*
* Compare a local to an address. Return -ve, 0 or +ve to indicate less than, * Compare a local to an address. Return -ve, 0 or +ve to indicate less than,
* same or greater than. * same or greater than.
...@@ -77,13 +74,15 @@ static long rxrpc_local_cmp_key(const struct rxrpc_local *local, ...@@ -77,13 +74,15 @@ static long rxrpc_local_cmp_key(const struct rxrpc_local *local,
/* /*
* Allocate a new local endpoint. * Allocate a new local endpoint.
*/ */
static struct rxrpc_local *rxrpc_alloc_local(const struct sockaddr_rxrpc *srx) static struct rxrpc_local *rxrpc_alloc_local(struct rxrpc_net *rxnet,
const struct sockaddr_rxrpc *srx)
{ {
struct rxrpc_local *local; struct rxrpc_local *local;
local = kzalloc(sizeof(struct rxrpc_local), GFP_KERNEL); local = kzalloc(sizeof(struct rxrpc_local), GFP_KERNEL);
if (local) { if (local) {
atomic_set(&local->usage, 1); atomic_set(&local->usage, 1);
local->rxnet = rxnet;
INIT_LIST_HEAD(&local->link); INIT_LIST_HEAD(&local->link);
INIT_WORK(&local->processor, rxrpc_local_processor); INIT_WORK(&local->processor, rxrpc_local_processor);
init_rwsem(&local->defrag_sem); init_rwsem(&local->defrag_sem);
...@@ -105,7 +104,7 @@ static struct rxrpc_local *rxrpc_alloc_local(const struct sockaddr_rxrpc *srx) ...@@ -105,7 +104,7 @@ static struct rxrpc_local *rxrpc_alloc_local(const struct sockaddr_rxrpc *srx)
* create the local socket * create the local socket
* - must be called with rxrpc_local_mutex locked * - must be called with rxrpc_local_mutex locked
*/ */
static int rxrpc_open_socket(struct rxrpc_local *local) static int rxrpc_open_socket(struct rxrpc_local *local, struct net *net)
{ {
struct sock *sock; struct sock *sock;
int ret, opt; int ret, opt;
...@@ -114,7 +113,7 @@ static int rxrpc_open_socket(struct rxrpc_local *local) ...@@ -114,7 +113,7 @@ static int rxrpc_open_socket(struct rxrpc_local *local)
local, local->srx.transport_type, local->srx.transport.family); local, local->srx.transport_type, local->srx.transport.family);
/* create a socket to represent the local endpoint */ /* create a socket to represent the local endpoint */
ret = sock_create_kern(&init_net, local->srx.transport.family, ret = sock_create_kern(net, local->srx.transport.family,
local->srx.transport_type, 0, &local->socket); local->srx.transport_type, 0, &local->socket);
if (ret < 0) { if (ret < 0) {
_leave(" = %d [socket]", ret); _leave(" = %d [socket]", ret);
...@@ -172,9 +171,11 @@ static int rxrpc_open_socket(struct rxrpc_local *local) ...@@ -172,9 +171,11 @@ static int rxrpc_open_socket(struct rxrpc_local *local)
/* /*
* Look up or create a new local endpoint using the specified local address. * Look up or create a new local endpoint using the specified local address.
*/ */
struct rxrpc_local *rxrpc_lookup_local(const struct sockaddr_rxrpc *srx) struct rxrpc_local *rxrpc_lookup_local(struct net *net,
const struct sockaddr_rxrpc *srx)
{ {
struct rxrpc_local *local; struct rxrpc_local *local;
struct rxrpc_net *rxnet = rxrpc_net(net);
struct list_head *cursor; struct list_head *cursor;
const char *age; const char *age;
long diff; long diff;
...@@ -183,10 +184,10 @@ struct rxrpc_local *rxrpc_lookup_local(const struct sockaddr_rxrpc *srx) ...@@ -183,10 +184,10 @@ struct rxrpc_local *rxrpc_lookup_local(const struct sockaddr_rxrpc *srx)
_enter("{%d,%d,%pISp}", _enter("{%d,%d,%pISp}",
srx->transport_type, srx->transport.family, &srx->transport); srx->transport_type, srx->transport.family, &srx->transport);
mutex_lock(&rxrpc_local_mutex); mutex_lock(&rxnet->local_mutex);
for (cursor = rxrpc_local_endpoints.next; for (cursor = rxnet->local_endpoints.next;
cursor != &rxrpc_local_endpoints; cursor != &rxnet->local_endpoints;
cursor = cursor->next) { cursor = cursor->next) {
local = list_entry(cursor, struct rxrpc_local, link); local = list_entry(cursor, struct rxrpc_local, link);
...@@ -220,11 +221,11 @@ struct rxrpc_local *rxrpc_lookup_local(const struct sockaddr_rxrpc *srx) ...@@ -220,11 +221,11 @@ struct rxrpc_local *rxrpc_lookup_local(const struct sockaddr_rxrpc *srx)
goto found; goto found;
} }
local = rxrpc_alloc_local(srx); local = rxrpc_alloc_local(rxnet, srx);
if (!local) if (!local)
goto nomem; goto nomem;
ret = rxrpc_open_socket(local); ret = rxrpc_open_socket(local, net);
if (ret < 0) if (ret < 0)
goto sock_error; goto sock_error;
...@@ -232,7 +233,7 @@ struct rxrpc_local *rxrpc_lookup_local(const struct sockaddr_rxrpc *srx) ...@@ -232,7 +233,7 @@ struct rxrpc_local *rxrpc_lookup_local(const struct sockaddr_rxrpc *srx)
age = "new"; age = "new";
found: found:
mutex_unlock(&rxrpc_local_mutex); mutex_unlock(&rxnet->local_mutex);
_net("LOCAL %s %d {%pISp}", _net("LOCAL %s %d {%pISp}",
age, local->debug_id, &local->srx.transport); age, local->debug_id, &local->srx.transport);
...@@ -243,13 +244,13 @@ struct rxrpc_local *rxrpc_lookup_local(const struct sockaddr_rxrpc *srx) ...@@ -243,13 +244,13 @@ struct rxrpc_local *rxrpc_lookup_local(const struct sockaddr_rxrpc *srx)
nomem: nomem:
ret = -ENOMEM; ret = -ENOMEM;
sock_error: sock_error:
mutex_unlock(&rxrpc_local_mutex); mutex_unlock(&rxnet->local_mutex);
kfree(local); kfree(local);
_leave(" = %d", ret); _leave(" = %d", ret);
return ERR_PTR(ret); return ERR_PTR(ret);
addr_in_use: addr_in_use:
mutex_unlock(&rxrpc_local_mutex); mutex_unlock(&rxnet->local_mutex);
_leave(" = -EADDRINUSE"); _leave(" = -EADDRINUSE");
return ERR_PTR(-EADDRINUSE); return ERR_PTR(-EADDRINUSE);
} }
...@@ -273,6 +274,7 @@ void __rxrpc_put_local(struct rxrpc_local *local) ...@@ -273,6 +274,7 @@ void __rxrpc_put_local(struct rxrpc_local *local)
static void rxrpc_local_destroyer(struct rxrpc_local *local) static void rxrpc_local_destroyer(struct rxrpc_local *local)
{ {
struct socket *socket = local->socket; struct socket *socket = local->socket;
struct rxrpc_net *rxnet = local->rxnet;
_enter("%d", local->debug_id); _enter("%d", local->debug_id);
...@@ -286,9 +288,9 @@ static void rxrpc_local_destroyer(struct rxrpc_local *local) ...@@ -286,9 +288,9 @@ static void rxrpc_local_destroyer(struct rxrpc_local *local)
} }
local->dead = true; local->dead = true;
mutex_lock(&rxrpc_local_mutex); mutex_lock(&rxnet->local_mutex);
list_del_init(&local->link); list_del_init(&local->link);
mutex_unlock(&rxrpc_local_mutex); mutex_unlock(&rxnet->local_mutex);
ASSERT(RB_EMPTY_ROOT(&local->client_conns)); ASSERT(RB_EMPTY_ROOT(&local->client_conns));
ASSERT(!local->service); ASSERT(!local->service);
...@@ -357,7 +359,7 @@ static void rxrpc_local_rcu(struct rcu_head *rcu) ...@@ -357,7 +359,7 @@ static void rxrpc_local_rcu(struct rcu_head *rcu)
/* /*
* Verify the local endpoint list is empty by this point. * Verify the local endpoint list is empty by this point.
*/ */
void __exit rxrpc_destroy_all_locals(void) void rxrpc_destroy_all_locals(struct rxrpc_net *rxnet)
{ {
struct rxrpc_local *local; struct rxrpc_local *local;
...@@ -365,15 +367,13 @@ void __exit rxrpc_destroy_all_locals(void) ...@@ -365,15 +367,13 @@ void __exit rxrpc_destroy_all_locals(void)
flush_workqueue(rxrpc_workqueue); flush_workqueue(rxrpc_workqueue);
if (!list_empty(&rxrpc_local_endpoints)) { if (!list_empty(&rxnet->local_endpoints)) {
mutex_lock(&rxrpc_local_mutex); mutex_lock(&rxnet->local_mutex);
list_for_each_entry(local, &rxrpc_local_endpoints, link) { list_for_each_entry(local, &rxnet->local_endpoints, link) {
pr_err("AF_RXRPC: Leaked local %p {%d}\n", pr_err("AF_RXRPC: Leaked local %p {%d}\n",
local, atomic_read(&local->usage)); local, atomic_read(&local->usage));
} }
mutex_unlock(&rxrpc_local_mutex); mutex_unlock(&rxnet->local_mutex);
BUG(); BUG();
} }
rcu_barrier();
} }
/* rxrpc network namespace handling.
*
* Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#include <linux/proc_fs.h>
#include "ar-internal.h"
unsigned int rxrpc_net_id;
/*
* Initialise a per-network namespace record.
*/
static __net_init int rxrpc_init_net(struct net *net)
{
struct rxrpc_net *rxnet = rxrpc_net(net);
int ret;
get_random_bytes(&rxnet->epoch, sizeof(rxnet->epoch));
rxnet->epoch |= RXRPC_RANDOM_EPOCH;
INIT_LIST_HEAD(&rxnet->calls);
rwlock_init(&rxnet->call_lock);
INIT_LIST_HEAD(&rxnet->conn_proc_list);
INIT_LIST_HEAD(&rxnet->service_conns);
rwlock_init(&rxnet->conn_lock);
INIT_DELAYED_WORK(&rxnet->service_conn_reaper,
rxrpc_service_connection_reaper);
rxnet->nr_client_conns = 0;
rxnet->nr_active_client_conns = 0;
rxnet->kill_all_client_conns = false;
spin_lock_init(&rxnet->client_conn_cache_lock);
spin_lock_init(&rxnet->client_conn_discard_lock);
INIT_LIST_HEAD(&rxnet->waiting_client_conns);
INIT_LIST_HEAD(&rxnet->active_client_conns);
INIT_LIST_HEAD(&rxnet->idle_client_conns);
INIT_DELAYED_WORK(&rxnet->client_conn_reaper,
rxrpc_discard_expired_client_conns);
INIT_LIST_HEAD(&rxnet->local_endpoints);
mutex_init(&rxnet->local_mutex);
hash_init(rxnet->peer_hash);
spin_lock_init(&rxnet->peer_hash_lock);
ret = -ENOMEM;
rxnet->proc_net = proc_net_mkdir(net, "rxrpc", net->proc_net);
if (!rxnet->proc_net)
goto err_proc;
proc_create("calls", 0444, rxnet->proc_net, &rxrpc_call_seq_fops);
proc_create("conns", 0444, rxnet->proc_net, &rxrpc_connection_seq_fops);
return 0;
proc_remove(rxnet->proc_net);
err_proc:
return ret;
}
/*
* Clean up a per-network namespace record.
*/
static __net_exit void rxrpc_exit_net(struct net *net)
{
struct rxrpc_net *rxnet = rxrpc_net(net);
rxrpc_destroy_all_calls(rxnet);
rxrpc_destroy_all_connections(rxnet);
rxrpc_destroy_all_locals(rxnet);
proc_remove(rxnet->proc_net);
}
struct pernet_operations rxrpc_net_ops = {
.init = rxrpc_init_net,
.exit = rxrpc_exit_net,
.id = &rxrpc_net_id,
.size = sizeof(struct rxrpc_net),
};
...@@ -26,9 +26,6 @@ ...@@ -26,9 +26,6 @@
#include <net/ip6_route.h> #include <net/ip6_route.h>
#include "ar-internal.h" #include "ar-internal.h"
static DEFINE_HASHTABLE(rxrpc_peer_hash, 10);
static DEFINE_SPINLOCK(rxrpc_peer_hash_lock);
/* /*
* Hash a peer key. * Hash a peer key.
*/ */
...@@ -124,8 +121,9 @@ static struct rxrpc_peer *__rxrpc_lookup_peer_rcu( ...@@ -124,8 +121,9 @@ static struct rxrpc_peer *__rxrpc_lookup_peer_rcu(
unsigned long hash_key) unsigned long hash_key)
{ {
struct rxrpc_peer *peer; struct rxrpc_peer *peer;
struct rxrpc_net *rxnet = local->rxnet;
hash_for_each_possible_rcu(rxrpc_peer_hash, peer, hash_link, hash_key) { hash_for_each_possible_rcu(rxnet->peer_hash, peer, hash_link, hash_key) {
if (rxrpc_peer_cmp_key(peer, local, srx, hash_key) == 0) { if (rxrpc_peer_cmp_key(peer, local, srx, hash_key) == 0) {
if (atomic_read(&peer->usage) == 0) if (atomic_read(&peer->usage) == 0)
return NULL; return NULL;
...@@ -301,13 +299,14 @@ struct rxrpc_peer *rxrpc_lookup_incoming_peer(struct rxrpc_local *local, ...@@ -301,13 +299,14 @@ struct rxrpc_peer *rxrpc_lookup_incoming_peer(struct rxrpc_local *local,
struct rxrpc_peer *prealloc) struct rxrpc_peer *prealloc)
{ {
struct rxrpc_peer *peer; struct rxrpc_peer *peer;
struct rxrpc_net *rxnet = local->rxnet;
unsigned long hash_key; unsigned long hash_key;
hash_key = rxrpc_peer_hash_key(local, &prealloc->srx); hash_key = rxrpc_peer_hash_key(local, &prealloc->srx);
prealloc->local = local; prealloc->local = local;
rxrpc_init_peer(prealloc, hash_key); rxrpc_init_peer(prealloc, hash_key);
spin_lock(&rxrpc_peer_hash_lock); spin_lock(&rxnet->peer_hash_lock);
/* Need to check that we aren't racing with someone else */ /* Need to check that we aren't racing with someone else */
peer = __rxrpc_lookup_peer_rcu(local, &prealloc->srx, hash_key); peer = __rxrpc_lookup_peer_rcu(local, &prealloc->srx, hash_key);
...@@ -315,10 +314,10 @@ struct rxrpc_peer *rxrpc_lookup_incoming_peer(struct rxrpc_local *local, ...@@ -315,10 +314,10 @@ struct rxrpc_peer *rxrpc_lookup_incoming_peer(struct rxrpc_local *local,
peer = NULL; peer = NULL;
if (!peer) { if (!peer) {
peer = prealloc; peer = prealloc;
hash_add_rcu(rxrpc_peer_hash, &peer->hash_link, hash_key); hash_add_rcu(rxnet->peer_hash, &peer->hash_link, hash_key);
} }
spin_unlock(&rxrpc_peer_hash_lock); spin_unlock(&rxnet->peer_hash_lock);
return peer; return peer;
} }
...@@ -329,6 +328,7 @@ struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *local, ...@@ -329,6 +328,7 @@ struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *local,
struct sockaddr_rxrpc *srx, gfp_t gfp) struct sockaddr_rxrpc *srx, gfp_t gfp)
{ {
struct rxrpc_peer *peer, *candidate; struct rxrpc_peer *peer, *candidate;
struct rxrpc_net *rxnet = local->rxnet;
unsigned long hash_key = rxrpc_peer_hash_key(local, srx); unsigned long hash_key = rxrpc_peer_hash_key(local, srx);
_enter("{%pISp}", &srx->transport); _enter("{%pISp}", &srx->transport);
...@@ -350,17 +350,17 @@ struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *local, ...@@ -350,17 +350,17 @@ struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *local,
return NULL; return NULL;
} }
spin_lock_bh(&rxrpc_peer_hash_lock); spin_lock_bh(&rxnet->peer_hash_lock);
/* Need to check that we aren't racing with someone else */ /* Need to check that we aren't racing with someone else */
peer = __rxrpc_lookup_peer_rcu(local, srx, hash_key); peer = __rxrpc_lookup_peer_rcu(local, srx, hash_key);
if (peer && !rxrpc_get_peer_maybe(peer)) if (peer && !rxrpc_get_peer_maybe(peer))
peer = NULL; peer = NULL;
if (!peer) if (!peer)
hash_add_rcu(rxrpc_peer_hash, hash_add_rcu(rxnet->peer_hash,
&candidate->hash_link, hash_key); &candidate->hash_link, hash_key);
spin_unlock_bh(&rxrpc_peer_hash_lock); spin_unlock_bh(&rxnet->peer_hash_lock);
if (peer) if (peer)
kfree(candidate); kfree(candidate);
...@@ -379,11 +379,13 @@ struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *local, ...@@ -379,11 +379,13 @@ struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *local,
*/ */
void __rxrpc_put_peer(struct rxrpc_peer *peer) void __rxrpc_put_peer(struct rxrpc_peer *peer)
{ {
struct rxrpc_net *rxnet = peer->local->rxnet;
ASSERT(hlist_empty(&peer->error_targets)); ASSERT(hlist_empty(&peer->error_targets));
spin_lock_bh(&rxrpc_peer_hash_lock); spin_lock_bh(&rxnet->peer_hash_lock);
hash_del_rcu(&peer->hash_link); hash_del_rcu(&peer->hash_link);
spin_unlock_bh(&rxrpc_peer_hash_lock); spin_unlock_bh(&rxnet->peer_hash_lock);
kfree_rcu(peer, rcu); kfree_rcu(peer, rcu);
} }
......
...@@ -30,19 +30,25 @@ static const char *const rxrpc_conn_states[RXRPC_CONN__NR_STATES] = { ...@@ -30,19 +30,25 @@ static const char *const rxrpc_conn_states[RXRPC_CONN__NR_STATES] = {
*/ */
static void *rxrpc_call_seq_start(struct seq_file *seq, loff_t *_pos) static void *rxrpc_call_seq_start(struct seq_file *seq, loff_t *_pos)
{ {
struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
rcu_read_lock(); rcu_read_lock();
read_lock(&rxrpc_call_lock); read_lock(&rxnet->call_lock);
return seq_list_start_head(&rxrpc_calls, *_pos); return seq_list_start_head(&rxnet->calls, *_pos);
} }
static void *rxrpc_call_seq_next(struct seq_file *seq, void *v, loff_t *pos) static void *rxrpc_call_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{ {
return seq_list_next(v, &rxrpc_calls, pos); struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
return seq_list_next(v, &rxnet->calls, pos);
} }
static void rxrpc_call_seq_stop(struct seq_file *seq, void *v) static void rxrpc_call_seq_stop(struct seq_file *seq, void *v)
{ {
read_unlock(&rxrpc_call_lock); struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
read_unlock(&rxnet->call_lock);
rcu_read_unlock(); rcu_read_unlock();
} }
...@@ -52,10 +58,11 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v) ...@@ -52,10 +58,11 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
struct rxrpc_sock *rx; struct rxrpc_sock *rx;
struct rxrpc_peer *peer; struct rxrpc_peer *peer;
struct rxrpc_call *call; struct rxrpc_call *call;
struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
rxrpc_seq_t tx_hard_ack, rx_hard_ack; rxrpc_seq_t tx_hard_ack, rx_hard_ack;
char lbuff[50], rbuff[50]; char lbuff[50], rbuff[50];
if (v == &rxrpc_calls) { if (v == &rxnet->calls) {
seq_puts(seq, seq_puts(seq,
"Proto Local " "Proto Local "
" Remote " " Remote "
...@@ -113,7 +120,8 @@ static const struct seq_operations rxrpc_call_seq_ops = { ...@@ -113,7 +120,8 @@ static const struct seq_operations rxrpc_call_seq_ops = {
static int rxrpc_call_seq_open(struct inode *inode, struct file *file) static int rxrpc_call_seq_open(struct inode *inode, struct file *file)
{ {
return seq_open(file, &rxrpc_call_seq_ops); return seq_open_net(inode, file, &rxrpc_call_seq_ops,
sizeof(struct seq_net_private));
} }
const struct file_operations rxrpc_call_seq_fops = { const struct file_operations rxrpc_call_seq_fops = {
...@@ -129,27 +137,34 @@ const struct file_operations rxrpc_call_seq_fops = { ...@@ -129,27 +137,34 @@ const struct file_operations rxrpc_call_seq_fops = {
*/ */
static void *rxrpc_connection_seq_start(struct seq_file *seq, loff_t *_pos) static void *rxrpc_connection_seq_start(struct seq_file *seq, loff_t *_pos)
{ {
read_lock(&rxrpc_connection_lock); struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
return seq_list_start_head(&rxrpc_connection_proc_list, *_pos);
read_lock(&rxnet->conn_lock);
return seq_list_start_head(&rxnet->conn_proc_list, *_pos);
} }
static void *rxrpc_connection_seq_next(struct seq_file *seq, void *v, static void *rxrpc_connection_seq_next(struct seq_file *seq, void *v,
loff_t *pos) loff_t *pos)
{ {
return seq_list_next(v, &rxrpc_connection_proc_list, pos); struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
return seq_list_next(v, &rxnet->conn_proc_list, pos);
} }
static void rxrpc_connection_seq_stop(struct seq_file *seq, void *v) static void rxrpc_connection_seq_stop(struct seq_file *seq, void *v)
{ {
read_unlock(&rxrpc_connection_lock); struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
read_unlock(&rxnet->conn_lock);
} }
static int rxrpc_connection_seq_show(struct seq_file *seq, void *v) static int rxrpc_connection_seq_show(struct seq_file *seq, void *v)
{ {
struct rxrpc_connection *conn; struct rxrpc_connection *conn;
struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
char lbuff[50], rbuff[50]; char lbuff[50], rbuff[50];
if (v == &rxrpc_connection_proc_list) { if (v == &rxnet->conn_proc_list) {
seq_puts(seq, seq_puts(seq,
"Proto Local " "Proto Local "
" Remote " " Remote "
...@@ -197,7 +212,8 @@ static const struct seq_operations rxrpc_connection_seq_ops = { ...@@ -197,7 +212,8 @@ static const struct seq_operations rxrpc_connection_seq_ops = {
static int rxrpc_connection_seq_open(struct inode *inode, struct file *file) static int rxrpc_connection_seq_open(struct inode *inode, struct file *file)
{ {
return seq_open(file, &rxrpc_connection_seq_ops); return seq_open_net(inode, file, &rxrpc_connection_seq_ops,
sizeof(struct seq_net_private));
} }
const struct file_operations rxrpc_connection_seq_fops = { const struct file_operations rxrpc_connection_seq_fops = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment