Skip to content

Commit

Permalink
Merge tag 'rxrpc-next-20200908' of git://git.kernel.org/pub/scm/linux…
Browse files Browse the repository at this point in the history
…/kernel/git/dhowells/linux-fs

David Howells says:

====================
rxrpc: Allow more calls to same peer

Here are some development patches for AF_RXRPC that allow more simultaneous
calls to be made to the same peer with the same security parameters.  The
current code allows a maximum of 4 simultaneous calls, which limits the afs
filesystem to that many simultaneous threads.  This increases the limit to
16.

To make this work, the way client connections are limited has to be changed
(incoming call/connection limits are unaffected) as the current code
depends on queuing calls on a connection and then pushing the connection
through a queue.  The limit is on the number of available connections.

This is changed such that there's a limit[*] on the total number of calls
systemwide across all namespaces, but the limit on the number of client
connections is removed.

Once a call is allowed to proceed, it finds a bundle of connections and
tries to grab a call slot.  If there's a spare call slot, fine, otherwise
it will wait.  If there's already a waiter, it will try to create another
connection in the bundle, unless the limit of 4 is reached (4 calls per
connection, giving 16).

A number of things throttle someone trying to set up endless connections:

 - Calls that fail immediately have their conns deleted immediately,

 - Calls that don't fail immediately have to wait for a timeout,

 - Connections normally get automatically reaped if they haven't been used
   for 2m, but this is sped up to 2s if the number of connections rises
   over 900.  This number is tunable by sysctl.

[*] Technically two limits - kernel sockets and userspace rxrpc sockets are
    accounted separately.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Sep 9, 2020
2 parents cdd84a9 + 288827d commit 56bbc22
Show file tree
Hide file tree
Showing 14 changed files with 614 additions and 694 deletions.
33 changes: 4 additions & 29 deletions include/trace/events/rxrpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,21 +68,14 @@ enum rxrpc_client_trace {
rxrpc_client_chan_activate,
rxrpc_client_chan_disconnect,
rxrpc_client_chan_pass,
rxrpc_client_chan_unstarted,
rxrpc_client_chan_wait_failed,
rxrpc_client_cleanup,
rxrpc_client_count,
rxrpc_client_discard,
rxrpc_client_duplicate,
rxrpc_client_exposed,
rxrpc_client_replace,
rxrpc_client_to_active,
rxrpc_client_to_culled,
rxrpc_client_to_idle,
rxrpc_client_to_inactive,
rxrpc_client_to_upgrade,
rxrpc_client_to_waiting,
rxrpc_client_uncount,
};

enum rxrpc_call_trace {
Expand Down Expand Up @@ -271,29 +264,14 @@ enum rxrpc_tx_point {
EM(rxrpc_client_chan_activate, "ChActv") \
EM(rxrpc_client_chan_disconnect, "ChDisc") \
EM(rxrpc_client_chan_pass, "ChPass") \
EM(rxrpc_client_chan_unstarted, "ChUnst") \
EM(rxrpc_client_chan_wait_failed, "ChWtFl") \
EM(rxrpc_client_cleanup, "Clean ") \
EM(rxrpc_client_count, "Count ") \
EM(rxrpc_client_discard, "Discar") \
EM(rxrpc_client_duplicate, "Duplic") \
EM(rxrpc_client_exposed, "Expose") \
EM(rxrpc_client_replace, "Replac") \
EM(rxrpc_client_to_active, "->Actv") \
EM(rxrpc_client_to_culled, "->Cull") \
EM(rxrpc_client_to_idle, "->Idle") \
EM(rxrpc_client_to_inactive, "->Inac") \
EM(rxrpc_client_to_upgrade, "->Upgd") \
EM(rxrpc_client_to_waiting, "->Wait") \
E_(rxrpc_client_uncount, "Uncoun")

#define rxrpc_conn_cache_states \
EM(RXRPC_CONN_CLIENT_INACTIVE, "Inac") \
EM(RXRPC_CONN_CLIENT_WAITING, "Wait") \
EM(RXRPC_CONN_CLIENT_ACTIVE, "Actv") \
EM(RXRPC_CONN_CLIENT_UPGRADE, "Upgd") \
EM(RXRPC_CONN_CLIENT_CULLED, "Cull") \
E_(RXRPC_CONN_CLIENT_IDLE, "Idle") \
E_(rxrpc_client_to_idle, "->Idle")

#define rxrpc_call_traces \
EM(rxrpc_call_connected, "CON") \
Expand Down Expand Up @@ -594,23 +572,20 @@ TRACE_EVENT(rxrpc_client,
__field(int, channel )
__field(int, usage )
__field(enum rxrpc_client_trace, op )
__field(enum rxrpc_conn_cache_state, cs )
),

TP_fast_assign(
__entry->conn = conn->debug_id;
__entry->conn = conn ? conn->debug_id : 0;
__entry->channel = channel;
__entry->usage = atomic_read(&conn->usage);
__entry->usage = conn ? atomic_read(&conn->usage) : -2;
__entry->op = op;
__entry->cid = conn->proto.cid;
__entry->cs = conn->cache_state;
),

TP_printk("C=%08x h=%2d %s %s i=%08x u=%d",
TP_printk("C=%08x h=%2d %s i=%08x u=%d",
__entry->conn,
__entry->channel,
__print_symbolic(__entry->op, rxrpc_client_traces),
__print_symbolic(__entry->cs, rxrpc_conn_cache_states),
__entry->cid,
__entry->usage)
);
Expand Down
7 changes: 4 additions & 3 deletions net/rxrpc/af_rxrpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -308,9 +308,10 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
key = NULL; /* a no-security key */

memset(&p, 0, sizeof(p));
p.user_call_ID = user_call_ID;
p.tx_total_len = tx_total_len;
p.interruptibility = interruptibility;
p.user_call_ID = user_call_ID;
p.tx_total_len = tx_total_len;
p.interruptibility = interruptibility;
p.kernel = true;

memset(&cp, 0, sizeof(cp));
cp.local = rx->local;
Expand Down
70 changes: 34 additions & 36 deletions net/rxrpc/ar-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,12 @@ struct rxrpc_net {
struct work_struct service_conn_reaper;
struct timer_list service_conn_reap_timer;

unsigned int nr_client_conns;
unsigned int nr_active_client_conns;
bool kill_all_client_conns;
bool live;

bool kill_all_client_conns;
atomic_t nr_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 work_struct client_conn_reaper;
struct timer_list client_conn_reap_timer;
Expand Down Expand Up @@ -275,8 +273,8 @@ struct rxrpc_local {
struct rw_semaphore defrag_sem; /* control re-enablement of IP DF bit */
struct sk_buff_head reject_queue; /* packets awaiting rejection */
struct sk_buff_head event_queue; /* endpoint event packets awaiting processing */
struct rb_root client_conns; /* Client connections by socket params */
spinlock_t client_conns_lock; /* Lock for client_conns */
struct rb_root client_bundles; /* Client connection bundles by socket params */
spinlock_t client_bundles_lock; /* Lock for client_bundles */
spinlock_t lock; /* access lock */
rwlock_t services_lock; /* lock for services list */
int debug_id; /* debug ID for printks */
Expand Down Expand Up @@ -353,10 +351,7 @@ struct rxrpc_conn_parameters {
enum rxrpc_conn_flag {
RXRPC_CONN_HAS_IDR, /* Has a client conn ID assigned */
RXRPC_CONN_IN_SERVICE_CONNS, /* Conn is in peer->service_conns */
RXRPC_CONN_IN_CLIENT_CONNS, /* Conn is in local->client_conns */
RXRPC_CONN_EXPOSED, /* Conn has extra ref for exposure */
RXRPC_CONN_DONT_REUSE, /* Don't reuse this connection */
RXRPC_CONN_COUNTED, /* Counted by rxrpc_nr_client_conns */
RXRPC_CONN_PROBING_FOR_UPGRADE, /* Probing for service upgrade */
RXRPC_CONN_FINAL_ACK_0, /* Need final ACK for channel 0 */
RXRPC_CONN_FINAL_ACK_1, /* Need final ACK for channel 1 */
Expand All @@ -376,19 +371,6 @@ enum rxrpc_conn_event {
RXRPC_CONN_EV_CHALLENGE, /* Send challenge packet */
};

/*
* The connection cache state.
*/
enum rxrpc_conn_cache_state {
RXRPC_CONN_CLIENT_INACTIVE, /* Conn is not yet listed */
RXRPC_CONN_CLIENT_WAITING, /* Conn is on wait list, waiting for capacity */
RXRPC_CONN_CLIENT_ACTIVE, /* Conn is on active list, doing calls */
RXRPC_CONN_CLIENT_UPGRADE, /* Conn is on active list, probing for upgrade */
RXRPC_CONN_CLIENT_CULLED, /* Conn is culled and delisted, doing calls */
RXRPC_CONN_CLIENT_IDLE, /* Conn is on idle list, doing mostly nothing */
RXRPC_CONN__NR_CACHE_STATES
};

/*
* The connection protocol state.
*/
Expand All @@ -404,6 +386,23 @@ enum rxrpc_conn_proto_state {
RXRPC_CONN__NR_STATES
};

/*
* RxRPC client connection bundle.
*/
struct rxrpc_bundle {
struct rxrpc_conn_parameters params;
atomic_t usage;
unsigned int debug_id;
bool try_upgrade; /* True if the bundle is attempting upgrade */
bool alloc_conn; /* True if someone's getting a conn */
unsigned short alloc_error; /* Error from last conn allocation */
spinlock_t channel_lock;
struct rb_node local_node; /* Node in local->client_conns */
struct list_head waiting_calls; /* Calls waiting for channels */
unsigned long avail_chans; /* Mask of available channels */
struct rxrpc_connection *conns[4]; /* The connections in the bundle (max 4) */
};

/*
* RxRPC connection definition
* - matched by { local, peer, epoch, conn_id, direction }
Expand All @@ -417,10 +416,7 @@ struct rxrpc_connection {
struct rcu_head rcu;
struct list_head cache_link;

spinlock_t channel_lock;
unsigned char active_chans; /* Mask of active channels */
#define RXRPC_ACTIVE_CHANS_MASK ((1 << RXRPC_MAXCALLS) - 1)
struct list_head waiting_calls; /* Calls waiting for channels */
unsigned char act_chans; /* Mask of active channels */
struct rxrpc_channel {
unsigned long final_ack_at; /* Time at which to issue final ACK */
struct rxrpc_call __rcu *call; /* Active call */
Expand All @@ -437,10 +433,8 @@ struct rxrpc_connection {

struct timer_list timer; /* Conn event timer */
struct work_struct processor; /* connection event processor */
union {
struct rb_node client_node; /* Node in local->client_conns */
struct rb_node service_node; /* Node in peer->service_conns */
};
struct rxrpc_bundle *bundle; /* Client connection bundle */
struct rb_node service_node; /* Node in peer->service_conns */
struct list_head proc_link; /* link in procfs list */
struct list_head link; /* link in master connection list */
struct sk_buff_head rx_queue; /* received conn-level packets */
Expand All @@ -452,7 +446,6 @@ struct rxrpc_connection {
unsigned long events;
unsigned long idle_timestamp; /* Time at which last became idle */
spinlock_t state_lock; /* state-change lock */
enum rxrpc_conn_cache_state cache_state;
enum rxrpc_conn_proto_state state; /* current state of connection */
u32 abort_code; /* Abort code of connection abort */
int debug_id; /* debug ID for printks */
Expand All @@ -464,6 +457,7 @@ struct rxrpc_connection {
u8 security_size; /* security header size */
u8 security_ix; /* security type */
u8 out_clientflag; /* RXRPC_CLIENT_INITIATED if we are client */
u8 bundle_shift; /* Index into bundle->avail_chans */
short error; /* Local error code */
};

Expand Down Expand Up @@ -493,6 +487,8 @@ enum rxrpc_call_flag {
RXRPC_CALL_RX_HEARD, /* The peer responded at least once to this call */
RXRPC_CALL_RX_UNDERRUN, /* Got data underrun */
RXRPC_CALL_DISCONNECTED, /* The call has been disconnected */
RXRPC_CALL_KERNEL, /* The call was made by the kernel */
RXRPC_CALL_UPGRADE, /* Service upgrade was requested for the call */
};

/*
Expand Down Expand Up @@ -577,7 +573,7 @@ struct rxrpc_call {
struct work_struct processor; /* Event processor */
rxrpc_notify_rx_t notify_rx; /* kernel service Rx notification function */
struct list_head link; /* link in master call list */
struct list_head chan_wait_link; /* Link in conn->waiting_calls */
struct list_head chan_wait_link; /* Link in conn->bundle->waiting_calls */
struct hlist_node error_link; /* link in error distribution list */
struct list_head accept_link; /* Link in rx->acceptq */
struct list_head recvmsg_link; /* Link in rx->recvmsg_q */
Expand Down Expand Up @@ -727,6 +723,7 @@ struct rxrpc_call_params {
u32 normal; /* Max time since last call packet (msec) */
} timeouts;
u8 nr_timeouts; /* Number of timeouts specified */
bool kernel; /* T if kernel is making the call */
enum rxrpc_interruptibility interruptibility; /* How is interruptible is the call? */
};

Expand Down Expand Up @@ -815,18 +812,19 @@ static inline bool rxrpc_is_client_call(const struct rxrpc_call *call)
/*
* conn_client.c
*/
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;

void rxrpc_destroy_client_conn_ids(void);
struct rxrpc_bundle *rxrpc_get_bundle(struct rxrpc_bundle *);
void rxrpc_put_bundle(struct rxrpc_bundle *);
int rxrpc_connect_call(struct rxrpc_sock *, struct rxrpc_call *,
struct rxrpc_conn_parameters *, struct sockaddr_rxrpc *,
gfp_t);
void rxrpc_expose_client_call(struct rxrpc_call *);
void rxrpc_disconnect_client_call(struct rxrpc_call *);
void rxrpc_disconnect_client_call(struct rxrpc_bundle *, struct rxrpc_call *);
void rxrpc_put_client_conn(struct rxrpc_connection *);
void rxrpc_discard_expired_client_conns(struct work_struct *);
void rxrpc_destroy_all_client_connections(struct rxrpc_net *);
Expand All @@ -852,7 +850,7 @@ void rxrpc_disconnect_call(struct rxrpc_call *);
void rxrpc_kill_connection(struct rxrpc_connection *);
bool rxrpc_queue_conn(struct rxrpc_connection *);
void rxrpc_see_connection(struct rxrpc_connection *);
void rxrpc_get_connection(struct rxrpc_connection *);
struct rxrpc_connection *rxrpc_get_connection(struct rxrpc_connection *);
struct rxrpc_connection *rxrpc_get_connection_maybe(struct rxrpc_connection *);
void rxrpc_put_service_conn(struct rxrpc_connection *);
void rxrpc_service_connection_reaper(struct work_struct *);
Expand Down
43 changes: 43 additions & 0 deletions net/rxrpc/call_object.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ const char *const rxrpc_call_completions[NR__RXRPC_CALL_COMPLETIONS] = {

struct kmem_cache *rxrpc_call_jar;

static struct semaphore rxrpc_call_limiter =
__SEMAPHORE_INITIALIZER(rxrpc_call_limiter, 1000);
static struct semaphore rxrpc_kernel_call_limiter =
__SEMAPHORE_INITIALIZER(rxrpc_kernel_call_limiter, 1000);

static void rxrpc_call_timer_expired(struct timer_list *t)
{
struct rxrpc_call *call = from_timer(call, t, timer);
Expand Down Expand Up @@ -209,6 +214,34 @@ static void rxrpc_start_call_timer(struct rxrpc_call *call)
call->timer.expires = now;
}

/*
* Wait for a call slot to become available.
*/
static struct semaphore *rxrpc_get_call_slot(struct rxrpc_call_params *p, gfp_t gfp)
{
struct semaphore *limiter = &rxrpc_call_limiter;

if (p->kernel)
limiter = &rxrpc_kernel_call_limiter;
if (p->interruptibility == RXRPC_UNINTERRUPTIBLE) {
down(limiter);
return limiter;
}
return down_interruptible(limiter) < 0 ? NULL : limiter;
}

/*
* Release a call slot.
*/
static void rxrpc_put_call_slot(struct rxrpc_call *call)
{
struct semaphore *limiter = &rxrpc_call_limiter;

if (test_bit(RXRPC_CALL_KERNEL, &call->flags))
limiter = &rxrpc_kernel_call_limiter;
up(limiter);
}

/*
* Set up a call for the given parameters.
* - Called with the socket lock held, which it must release.
Expand All @@ -225,15 +258,21 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,
{
struct rxrpc_call *call, *xcall;
struct rxrpc_net *rxnet;
struct semaphore *limiter;
struct rb_node *parent, **pp;
const void *here = __builtin_return_address(0);
int ret;

_enter("%p,%lx", rx, p->user_call_ID);

limiter = rxrpc_get_call_slot(p, gfp);
if (!limiter)
return ERR_PTR(-ERESTARTSYS);

call = rxrpc_alloc_client_call(rx, srx, gfp, debug_id);
if (IS_ERR(call)) {
release_sock(&rx->sk);
up(limiter);
_leave(" = %ld", PTR_ERR(call));
return call;
}
Expand All @@ -243,6 +282,8 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,
trace_rxrpc_call(call->debug_id, rxrpc_call_new_client,
atomic_read(&call->usage),
here, (const void *)p->user_call_ID);
if (p->kernel)
__set_bit(RXRPC_CALL_KERNEL, &call->flags);

/* We need to protect a partially set up call against the user as we
* will be acting outside the socket lock.
Expand Down Expand Up @@ -471,6 +512,8 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call)
BUG();
spin_unlock_bh(&call->lock);

rxrpc_put_call_slot(call);

del_timer_sync(&call->timer);

/* Make sure we don't get any more notifications */
Expand Down
Loading

0 comments on commit 56bbc22

Please sign in to comment.