if (bundle) {
id = bundle->debug_id;
dead = __refcount_dec_and_test(&bundle->ref, &r);
trace_rxrpc_bundle(id, r - 1, why); if (dead)
rxrpc_free_bundle(bundle);
}
}
/* The IDR tree gets very expensive on memory if the connection IDs are *widelyscatteredthroughoutthenumberspace,soweshallwantto *killoffconnectionsthat,say,haveanIDmorethanaboutfour *timesthemaximumnumberofclientconnsawayfromthecurrent *allocationpointtotryandkeeptheIDsconcentrated.
*/
id_cursor = idr_get_cursor(&conn->local->conn_ids);
id = conn->proto.cid >> RXRPC_CIDSHIFT;
distance = id - id_cursor; if (distance < 0)
distance = -distance;
limit = umax(atomic_read(&rxnet->nr_conns) * 4, 1024); if (distance > limit) goto mark_dont_reuse;
/* First, see if the bundle is already there. */
_debug("search 1");
spin_lock(&local->client_bundles_lock);
p = local->client_bundles.rb_node; while (p) {
bundle = rb_entry(p, struct rxrpc_bundle, local_node);
rxrpc_activate_bundle(bundle);
conn->bundle_shift = shift;
bundle->conns[slot] = conn;
bundle->conn_ids[slot] = conn->debug_id; for (i = 0; i < RXRPC_MAXCALLS; i++)
set_bit(shift + i, &bundle->avail_chans); returntrue;
}
/* *Addaconnectiontoabundleiftherearenousableconnectionsorwehave *connectionswaitingforextracapacity.
*/ staticbool rxrpc_bundle_has_space(struct rxrpc_bundle *bundle)
{ int slot = -1, i, usable;
_enter("");
bundle->alloc_error = 0;
/* See if there are any usable connections. */
usable = 0; for (i = 0; i < ARRAY_SIZE(bundle->conns); i++) { if (rxrpc_may_reuse_conn(bundle->conns[i]))
usable++; elseif (slot == -1)
slot = i;
}
if (!usable && bundle->upgrade)
bundle->try_upgrade = true;
if (!usable) goto alloc_conn;
if (!bundle->avail_chans &&
!bundle->try_upgrade &&
usable < ARRAY_SIZE(bundle->conns)) goto alloc_conn;
/* Cancel the final ACK on the previous call if it hasn't been sent yet *astheDATApacketwillimplicitlyACKit.
*/
clear_bit(RXRPC_CONN_FINAL_ACK_0 + channel, &conn->flags);
clear_bit(conn->bundle_shift + channel, &bundle->avail_chans);
if (!test_and_set_bit(RXRPC_CALL_EXPOSED, &call->flags)) { /* Mark the call ID as being used. If the callNumber counter *exceeds~2billion,wekilltheconnectionafterits *outstandingcallshavefinishedsothatthecounterdoesn't *wrap.
*/
chan->call_counter++; if (chan->call_counter >= INT_MAX)
set_bit(RXRPC_CONN_DONT_REUSE, &conn->flags);
trace_rxrpc_client(conn, channel, rxrpc_client_exposed);
/* Calls that have never actually been assigned a channel can simply be *discarded.
*/
conn = call->conn; if (!conn) {
_debug("call is waiting");
ASSERTCMP(call->call_id, ==, 0);
ASSERT(!test_bit(RXRPC_CALL_EXPOSED, &call->flags)); /* May still be on ->new_client_calls. */
spin_lock_irq(&local->client_call_lock);
list_del_init(&call->wait_link);
spin_unlock_irq(&local->client_call_lock); return;
}
/* If a client call was exposed to the world, we save the result for *retransmission. * *Weuseabarrierheresothatthecallnumberandabortcodecanbe *readwithoutneedingtotakealock. * *TODO:Maketheincomingpackethandlercheckthisandhandle *terminalretransmissionwithoutrequiringaccesstothecall.
*/ if (test_bit(RXRPC_CALL_EXPOSED, &call->flags)) {
_debug("exposed %u,%u", call->call_id, call->abort_code);
__rxrpc_disconnect_call(conn, call);
if (test_and_clear_bit(RXRPC_CONN_PROBING_FOR_UPGRADE, &conn->flags)) {
trace_rxrpc_client(conn, channel, rxrpc_client_to_active);
bundle->try_upgrade = false; if (may_reuse)
rxrpc_activate_channels(bundle);
}
}
/* See if we can pass the channel directly to another call. */ if (may_reuse && !list_empty(&bundle->waiting_calls)) {
trace_rxrpc_client(conn, channel, rxrpc_client_chan_pass);
rxrpc_activate_one_channel(conn, channel); return;
}
/* Schedule the final ACK to be transmitted in a short while so that it *canbeskippedifwefindafollow-oncall.ThefirstDATApacket *ofthefollowoncallwillimplicitlyACKthiscall.
*/ if (call->completion == RXRPC_CALL_SUCCEEDED &&
test_bit(RXRPC_CALL_EXPOSED, &call->flags)) { unsignedlong final_ack_at = jiffies + 2;
/* If no channels remain active, then put the connection on the idle *listforashortwhile.Giveitareftostopitgoingawayifit *becomesunbundled.
*/ if (!conn->act_chans) {
trace_rxrpc_client(conn, channel, rxrpc_client_to_idle);
conn->idle_timestamp = jiffies;
/* We keep an estimate of what the number of conns ought to be after *we'vediscardedsomesothatwedon'toverdothediscarding.
*/
nr_conns = atomic_read(&local->rxnet->nr_client_conns);
next:
conn = list_first_entry_or_null(&local->idle_client_conns, struct rxrpc_connection, cache_link); if (!conn) return;
if (!local->kill_all_client_conns) { /* If the number of connections is over the reap limit, we *expeditediscardbyreducingtheexpirytimeout.Wemust, *however,haveatleastashortgraceperiodtobeabletodo *final-ACKorABORTretransmission.
*/
expiry = rxrpc_conn_idle_client_expiry; if (nr_conns > rxrpc_reap_client_connections)
expiry = rxrpc_conn_idle_client_fast_expiry; if (conn->local->service_closed)
expiry = rxrpc_closed_conn_expiry * HZ;
conn_expires_at = conn->idle_timestamp + expiry;
now = jiffies; if (time_after(conn_expires_at, now)) goto not_yet_expired;
}
rxrpc_unbundle_conn(conn); /* Drop the ->cache_link ref */
rxrpc_put_connection(conn, rxrpc_conn_put_discard_idle);
nr_conns--; goto next;
not_yet_expired: /* The connection at the front of the queue hasn't yet expired, so *scheduletheworkitemforthatpointifwediscardedsomething. * *Wedon'tworryiftheworkitemisalreadyscheduled-itcanlook *afterreschedulingitselfatalatertime.Wecouldcancelit,but *thenthingsgetmessier.
*/
_debug("not yet"); if (!local->kill_all_client_conns)
timer_reduce(&local->client_conn_reap_timer, conn_expires_at);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.