mirror of
https://github.com/coredns/coredns.git
synced 2026-04-18 01:45:35 -04:00
Fix data race in xfr.go (#8039)
Signed-off-by: Ryan Brewster <rpb@anthropic.com>
This commit is contained in:
@@ -19,8 +19,12 @@ func (f File) Transfer(zone string, serial uint32) (<-chan []dns.RR, error) {
|
|||||||
// Transfer transfers a zone with serial in the returned channel and implements IXFR fallback, by just
|
// Transfer transfers a zone with serial in the returned channel and implements IXFR fallback, by just
|
||||||
// sending a single SOA record.
|
// sending a single SOA record.
|
||||||
func (z *Zone) Transfer(serial uint32) (<-chan []dns.RR, error) {
|
func (z *Zone) Transfer(serial uint32) (<-chan []dns.RR, error) {
|
||||||
// get soa and apex
|
// Snapshot apex and tree under one read lock so the goroutine walks the
|
||||||
apex, err := z.ApexIfDefined()
|
// same generation the SOA came from, even if TransferIn swaps them mid-AXFR.
|
||||||
|
z.RLock()
|
||||||
|
apex, err := z.apexIfDefinedLocked()
|
||||||
|
t := z.Tree
|
||||||
|
z.RUnlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -35,7 +39,7 @@ func (z *Zone) Transfer(serial uint32) (<-chan []dns.RR, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ch <- apex
|
ch <- apex
|
||||||
z.Walk(func(e *tree.Elem, _ map[uint16][]dns.RR) error { ch <- e.All(); return nil })
|
t.Walk(func(e *tree.Elem, _ map[uint16][]dns.RR) error { ch <- e.All(); return nil })
|
||||||
ch <- []dns.RR{apex[0]}
|
ch <- []dns.RR{apex[0]}
|
||||||
|
|
||||||
close(ch)
|
close(ch)
|
||||||
|
|||||||
@@ -146,6 +146,11 @@ func (z *Zone) SetFile(path string) {
|
|||||||
func (z *Zone) ApexIfDefined() ([]dns.RR, error) {
|
func (z *Zone) ApexIfDefined() ([]dns.RR, error) {
|
||||||
z.RLock()
|
z.RLock()
|
||||||
defer z.RUnlock()
|
defer z.RUnlock()
|
||||||
|
return z.apexIfDefinedLocked()
|
||||||
|
}
|
||||||
|
|
||||||
|
// apexIfDefinedLocked is ApexIfDefined without locking; caller must hold z's read lock.
|
||||||
|
func (z *Zone) apexIfDefinedLocked() ([]dns.RR, error) {
|
||||||
if z.SOA == nil {
|
if z.SOA == nil {
|
||||||
return nil, fmt.Errorf("no SOA")
|
return nil, fmt.Errorf("no SOA")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ func TestSecondaryZoneNotify(t *testing.T) {
|
|||||||
if len(r.Answer) != 0 {
|
if len(r.Answer) != 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
time.Sleep(1000 * time.Microsecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
}
|
}
|
||||||
if len(r.Answer) == 0 {
|
if len(r.Answer) == 0 {
|
||||||
t.Fatalf("Expected answer section")
|
t.Fatalf("Expected answer section")
|
||||||
@@ -323,7 +323,7 @@ www IN A 127.0.0.1
|
|||||||
if len(r.Answer) != 0 {
|
if len(r.Answer) != 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
time.Sleep(1000 * time.Microsecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
}
|
}
|
||||||
if len(r.Answer) != 1 {
|
if len(r.Answer) != 1 {
|
||||||
t.Fatalf("Expected one RR in answer section got %d", len(r.Answer))
|
t.Fatalf("Expected one RR in answer section got %d", len(r.Answer))
|
||||||
|
|||||||
Reference in New Issue
Block a user