Read lock when getting connections

We should avoid taking the write lock to avoid contention when looking
for a packet's tracked connection.

No need to reap timed out connections when looking for connections
as the reaper (which runs periodically) will handle that.

PiperOrigin-RevId: 400322514
This commit is contained in:
Ghanan Gowripalan 2021-10-01 17:00:24 -07:00 committed by gVisor bot
parent 51c4fbb840
commit 3bab5e5667
1 changed files with 8 additions and 15 deletions

View File

@ -113,7 +113,7 @@ type conn struct {
// TODO(gvisor.dev/issue/5696): Support updating manipulation type. // TODO(gvisor.dev/issue/5696): Support updating manipulation type.
manip manipType manip manipType
mu sync.Mutex `state:"nosave"` mu sync.RWMutex `state:"nosave"`
// tcb is TCB control block. It is used to keep track of states // tcb is TCB control block. It is used to keep track of states
// of tcp connection. // of tcp connection.
// //
@ -143,8 +143,8 @@ func newConn(orig, reply tupleID, manip manipType) *conn {
func (cn *conn) timedOut(now time.Time) bool { func (cn *conn) timedOut(now time.Time) bool {
const establishedTimeout = 5 * 24 * time.Hour const establishedTimeout = 5 * 24 * time.Hour
const defaultTimeout = 120 * time.Second const defaultTimeout = 120 * time.Second
cn.mu.Lock() cn.mu.RLock()
defer cn.mu.Unlock() defer cn.mu.RUnlock()
if cn.tcb.State() == tcpconntrack.ResultAlive { if cn.tcb.State() == tcpconntrack.ResultAlive {
// Use the same default as Linux, which doesn't delete // Use the same default as Linux, which doesn't delete
// established connections for 5(!) days. // established connections for 5(!) days.
@ -215,7 +215,7 @@ type ConnTrack struct {
// +stateify savable // +stateify savable
type bucket struct { type bucket struct {
mu sync.Mutex `state:"nosave"` mu sync.RWMutex `state:"nosave"`
// +checklocks:mu // +checklocks:mu
tuples tupleList tuples tupleList
} }
@ -279,20 +279,13 @@ func (ct *ConnTrack) connForTID(tid tupleID) (*conn, direction) {
now := time.Now() now := time.Now()
ct.mu.RLock() ct.mu.RLock()
defer ct.mu.RUnlock()
bkt := &ct.buckets[bktID] bkt := &ct.buckets[bktID]
bkt.mu.Lock() ct.mu.RUnlock()
defer bkt.mu.Unlock()
// Iterate over the tuples in a bucket, cleaning up any unused bkt.mu.RLock()
// connections we find. defer bkt.mu.RUnlock()
for other := bkt.tuples.Front(); other != nil; other = other.Next() { for other := bkt.tuples.Front(); other != nil; other = other.Next() {
// Clean up any timed-out connections we happen to find. if tid == other.tupleID && !other.conn.timedOut(now) {
if ct.reapTupleLocked(other, bktID, bkt, now) {
// The tuple expired.
continue
}
if tid == other.tupleID {
return other.conn, other.direction return other.conn, other.direction
} }
} }