diff --git a/pkg/abi/linux/signal.go b/pkg/abi/linux/signal.go index 06a4c6401..9aa0263e8 100644 --- a/pkg/abi/linux/signal.go +++ b/pkg/abi/linux/signal.go @@ -411,8 +411,8 @@ type SignalInfo struct { // // The si_code we get from Linux may contain the kernel-specific code in the // top 16 bits if it's positive (e.g., from ptrace). Linux's -// copy_siginfo_to_user does -// err |= __put_user((short)from->si_code, &to->si_code); +// copy_siginfo_to_user does: +// err |= __put_user((short)from->si_code, &to->si_code); // to mask out those bits and we need to do the same. func (s *SignalInfo) FixSignalCodeForUser() { if s.Code > 0 { diff --git a/pkg/abi/linux/time.go b/pkg/abi/linux/time.go index 206f5af7e..45a739b24 100644 --- a/pkg/abi/linux/time.go +++ b/pkg/abi/linux/time.go @@ -206,10 +206,11 @@ type Itimerspec struct { } // ItimerVal mimics the following struct in -// struct itimerval { -// struct timeval it_interval; /* next value */ -// struct timeval it_value; /* current value */ -// }; +// +// struct itimerval { +// struct timeval it_interval; /* next value */ +// struct timeval it_value; /* current value */ +// }; // // +marshal type ItimerVal struct { diff --git a/pkg/atomicbitops/32b_32bit.go b/pkg/atomicbitops/32b_32bit.go index 51853403f..c44610dbf 100644 --- a/pkg/atomicbitops/32b_32bit.go +++ b/pkg/atomicbitops/32b_32bit.go @@ -42,12 +42,14 @@ type Int32 struct { } // FromInt32 returns an Int32 initialized to value v. +// //go:nosplit func FromInt32(v int32) Int32 { return Int32{value: v} } // Load is analogous to atomic.LoadInt32. +// //go:nosplit func (i *Int32) Load() int32 { return atomic.LoadInt32(&i.value) @@ -64,6 +66,7 @@ func (i *Int32) RacyLoad() int32 { } // Store is analogous to atomic.StoreInt32. +// //go:nosplit func (i *Int32) Store(v int32) { atomic.StoreInt32(&i.value, v) @@ -83,6 +86,7 @@ func (i *Int32) RacyStore(v int32) { } // Add is analogous to atomic.AddInt32. +// //go:nosplit func (i *Int32) Add(v int32) int32 { return atomic.AddInt32(&i.value, v) @@ -100,12 +104,14 @@ func (i *Int32) RacyAdd(v int32) int32 { } // Swap is analogous to atomic.SwapInt32. +// //go:nosplit func (i *Int32) Swap(v int32) int32 { return atomic.SwapInt32(&i.value, v) } // CompareAndSwap is analogous to atomic.CompareAndSwapInt32. +// //go:nosplit func (i *Int32) CompareAndSwap(oldVal, newVal int32) bool { return atomic.CompareAndSwapInt32(&i.value, oldVal, newVal) @@ -127,12 +133,14 @@ type Uint32 struct { } // FromUint32 returns an Uint32 initialized to value v. +// //go:nosplit func FromUint32(v uint32) Uint32 { return Uint32{value: v} } // Load is analogous to atomic.LoadUint32. +// //go:nosplit func (u *Uint32) Load() uint32 { return atomic.LoadUint32(&u.value) @@ -149,6 +157,7 @@ func (u *Uint32) RacyLoad() uint32 { } // Store is analogous to atomic.StoreUint32. +// //go:nosplit func (u *Uint32) Store(v uint32) { atomic.StoreUint32(&u.value, v) @@ -165,6 +174,7 @@ func (u *Uint32) RacyStore(v uint32) { } // Add is analogous to atomic.AddUint32. +// //go:nosplit func (u *Uint32) Add(v uint32) uint32 { return atomic.AddUint32(&u.value, v) @@ -182,12 +192,14 @@ func (u *Uint32) RacyAdd(v uint32) uint32 { } // Swap is analogous to atomic.SwapUint32. +// //go:nosplit func (u *Uint32) Swap(v uint32) uint32 { return atomic.SwapUint32(&u.value, v) } // CompareAndSwap is analogous to atomic.CompareAndSwapUint32. +// //go:nosplit func (u *Uint32) CompareAndSwap(oldVal, newVal uint32) bool { return atomic.CompareAndSwapUint32(&u.value, oldVal, newVal) diff --git a/pkg/atomicbitops/32b_64bit.go b/pkg/atomicbitops/32b_64bit.go index 92878c334..18aa96303 100644 --- a/pkg/atomicbitops/32b_64bit.go +++ b/pkg/atomicbitops/32b_64bit.go @@ -42,12 +42,14 @@ type Int32 struct { } // FromInt32 returns an Int32 initialized to value v. +// //go:nosplit func FromInt32(v int32) Int32 { return Int32{value: v} } // Load is analogous to atomic.LoadInt32. +// //go:nosplit func (i *Int32) Load() int32 { return atomic.LoadInt32(&i.value) @@ -64,6 +66,7 @@ func (i *Int32) RacyLoad() int32 { } // Store is analogous to atomic.StoreInt32. +// //go:nosplit func (i *Int32) Store(v int32) { atomic.StoreInt32(&i.value, v) @@ -83,6 +86,7 @@ func (i *Int32) RacyStore(v int32) { } // Add is analogous to atomic.AddInt32. +// //go:nosplit func (i *Int32) Add(v int32) int32 { return atomic.AddInt32(&i.value, v) @@ -100,12 +104,14 @@ func (i *Int32) RacyAdd(v int32) int32 { } // Swap is analogous to atomic.SwapInt32. +// //go:nosplit func (i *Int32) Swap(v int32) int32 { return atomic.SwapInt32(&i.value, v) } // CompareAndSwap is analogous to atomic.CompareAndSwapInt32. +// //go:nosplit func (i *Int32) CompareAndSwap(oldVal, newVal int32) bool { return atomic.CompareAndSwapInt32(&i.value, oldVal, newVal) @@ -127,12 +133,14 @@ type Uint32 struct { } // FromUint32 returns an Uint32 initialized to value v. +// //go:nosplit func FromUint32(v uint32) Uint32 { return Uint32{value: v} } // Load is analogous to atomic.LoadUint32. +// //go:nosplit func (u *Uint32) Load() uint32 { return atomic.LoadUint32(&u.value) @@ -149,6 +157,7 @@ func (u *Uint32) RacyLoad() uint32 { } // Store is analogous to atomic.StoreUint32. +// //go:nosplit func (u *Uint32) Store(v uint32) { atomic.StoreUint32(&u.value, v) @@ -165,6 +174,7 @@ func (u *Uint32) RacyStore(v uint32) { } // Add is analogous to atomic.AddUint32. +// //go:nosplit func (u *Uint32) Add(v uint32) uint32 { return atomic.AddUint32(&u.value, v) @@ -182,12 +192,14 @@ func (u *Uint32) RacyAdd(v uint32) uint32 { } // Swap is analogous to atomic.SwapUint32. +// //go:nosplit func (u *Uint32) Swap(v uint32) uint32 { return atomic.SwapUint32(&u.value, v) } // CompareAndSwap is analogous to atomic.CompareAndSwapUint32. +// //go:nosplit func (u *Uint32) CompareAndSwap(oldVal, newVal uint32) bool { return atomic.CompareAndSwapUint32(&u.value, oldVal, newVal) diff --git a/pkg/atomicbitops/aligned_32bit_unsafe.go b/pkg/atomicbitops/aligned_32bit_unsafe.go index 60063fc1a..a76c6ed30 100644 --- a/pkg/atomicbitops/aligned_32bit_unsafe.go +++ b/pkg/atomicbitops/aligned_32bit_unsafe.go @@ -53,6 +53,7 @@ func (i *Int64) ptr() *int64 { } // FromInt64 returns an Int64 initialized to value v. +// //go:nosplit func FromInt64(v int64) Int64 { var i Int64 @@ -61,6 +62,7 @@ func FromInt64(v int64) Int64 { } // Load is analogous to atomic.LoadInt64. +// //go:nosplit func (i *Int64) Load() int64 { return atomic.LoadInt64(i.ptr()) @@ -77,6 +79,7 @@ func (i *Int64) RacyLoad() int64 { } // Store is analogous to atomic.StoreInt64. +// //go:nosplit func (i *Int64) Store(v int64) { atomic.StoreInt64(i.ptr(), v) @@ -93,6 +96,7 @@ func (i *Int64) RacyStore(v int64) { } // Add is analogous to atomic.AddInt64. +// //go:nosplit func (i *Int64) Add(v int64) int64 { return atomic.AddInt64(i.ptr(), v) @@ -110,12 +114,14 @@ func (i *Int64) RacyAdd(v int64) int64 { } // Swap is analogous to atomic.SwapInt64. +// //go:nosplit func (i *Int64) Swap(v int64) int64 { return atomic.SwapInt64(i.ptr(), v) } // CompareAndSwap is analogous to atomic.CompareAndSwapInt64. +// //go:nosplit func (i *Int64) CompareAndSwap(oldVal, newVal int64) bool { return atomic.CompareAndSwapInt64(&i.value, oldVal, newVal) @@ -150,6 +156,7 @@ func (u *Uint64) ptr() *uint64 { } // FromUint64 returns an Uint64 initialized to value v. +// //go:nosplit func FromUint64(v uint64) Uint64 { var u Uint64 @@ -158,6 +165,7 @@ func FromUint64(v uint64) Uint64 { } // Load is analogous to atomic.LoadUint64. +// //go:nosplit func (u *Uint64) Load() uint64 { return atomic.LoadUint64(u.ptr()) @@ -174,6 +182,7 @@ func (u *Uint64) RacyLoad() uint64 { } // Store is analogous to atomic.StoreUint64. +// //go:nosplit func (u *Uint64) Store(v uint64) { atomic.StoreUint64(u.ptr(), v) @@ -190,6 +199,7 @@ func (u *Uint64) RacyStore(v uint64) { } // Add is analogous to atomic.AddUint64. +// //go:nosplit func (u *Uint64) Add(v uint64) uint64 { return atomic.AddUint64(u.ptr(), v) @@ -207,12 +217,14 @@ func (u *Uint64) RacyAdd(v uint64) uint64 { } // Swap is analogous to atomic.SwapUint64. +// //go:nosplit func (u *Uint64) Swap(v uint64) uint64 { return atomic.SwapUint64(u.ptr(), v) } // CompareAndSwap is analogous to atomic.CompareAndSwapUint64. +// //go:nosplit func (u *Uint64) CompareAndSwap(oldVal, newVal uint64) bool { return atomic.CompareAndSwapUint64(u.ptr(), oldVal, newVal) diff --git a/pkg/atomicbitops/aligned_64bit.go b/pkg/atomicbitops/aligned_64bit.go index f3754bce8..ecb37e6bb 100644 --- a/pkg/atomicbitops/aligned_64bit.go +++ b/pkg/atomicbitops/aligned_64bit.go @@ -41,12 +41,14 @@ type Int64 struct { } // FromInt64 returns an Int64 initialized to value v. +// //go:nosplit func FromInt64(v int64) Int64 { return Int64{value: v} } // Load is analogous to atomic.LoadInt64. +// //go:nosplit func (i *Int64) Load() int64 { return atomic.LoadInt64(&i.value) @@ -63,6 +65,7 @@ func (i *Int64) RacyLoad() int64 { } // Store is analogous to atomic.StoreInt64. +// //go:nosplit func (i *Int64) Store(v int64) { atomic.StoreInt64(&i.value, v) @@ -79,6 +82,7 @@ func (i *Int64) RacyStore(v int64) { } // Add is analogous to atomic.AddInt64. +// //go:nosplit func (i *Int64) Add(v int64) int64 { return atomic.AddInt64(&i.value, v) @@ -96,12 +100,14 @@ func (i *Int64) RacyAdd(v int64) int64 { } // Swap is analogous to atomic.SwapInt64. +// //go:nosplit func (i *Int64) Swap(v int64) int64 { return atomic.SwapInt64(&i.value, v) } // CompareAndSwap is analogous to atomic.CompareAndSwapInt64. +// //go:nosplit func (i *Int64) CompareAndSwap(oldVal, newVal int64) bool { return atomic.CompareAndSwapInt64(&i.value, oldVal, newVal) @@ -128,12 +134,14 @@ type Uint64 struct { } // FromUint64 returns an Uint64 initialized to value v. +// //go:nosplit func FromUint64(v uint64) Uint64 { return Uint64{value: v} } // Load is analogous to atomic.LoadUint64. +// //go:nosplit func (u *Uint64) Load() uint64 { return atomic.LoadUint64(&u.value) @@ -150,6 +158,7 @@ func (u *Uint64) RacyLoad() uint64 { } // Store is analogous to atomic.StoreUint64. +// //go:nosplit func (u *Uint64) Store(v uint64) { atomic.StoreUint64(&u.value, v) @@ -166,6 +175,7 @@ func (u *Uint64) RacyStore(v uint64) { } // Add is analogous to atomic.AddUint64. +// //go:nosplit func (u *Uint64) Add(v uint64) uint64 { return atomic.AddUint64(&u.value, v) @@ -183,12 +193,14 @@ func (u *Uint64) RacyAdd(v uint64) uint64 { } // Swap is analogous to atomic.SwapUint64. +// //go:nosplit func (u *Uint64) Swap(v uint64) uint64 { return atomic.SwapUint64(&u.value, v) } // CompareAndSwap is analogous to atomic.CompareAndSwapUint64. +// //go:nosplit func (u *Uint64) CompareAndSwap(oldVal, newVal uint64) bool { return atomic.CompareAndSwapUint64(&u.value, oldVal, newVal) diff --git a/pkg/bpf/bpf.go b/pkg/bpf/bpf.go index b8b8ad372..505b24413 100644 --- a/pkg/bpf/bpf.go +++ b/pkg/bpf/bpf.go @@ -34,11 +34,11 @@ const ( // // In the comments below: // -// - A, X, and M[] are BPF virtual machine registers. +// - A, X, and M[] are BPF virtual machine registers. // -// - K refers to the instruction field linux.BPFInstruction.K. +// - K refers to the instruction field linux.BPFInstruction.K. // -// - Bits are counted from the LSB position. +// - Bits are counted from the LSB position. const ( // Instruction class, stored in bits 0-2. Ld = 0x00 // load into A diff --git a/pkg/bpf/interpreter.go b/pkg/bpf/interpreter.go index ed27abb9b..c81f2d99f 100644 --- a/pkg/bpf/interpreter.go +++ b/pkg/bpf/interpreter.go @@ -225,15 +225,15 @@ func Compile(insns []linux.BPFInstruction) (Program, error) { // // For all of Input's Load methods: // -// - The second (bool) return value is true if the load succeeded and false -// otherwise. +// - The second (bool) return value is true if the load succeeded and false +// otherwise. // -// - Inputs should not assume that the loaded range falls within the input -// data's length. Inputs should return false if the load falls outside of the -// input data. +// - Inputs should not assume that the loaded range falls within the input +// data's length. Inputs should return false if the load falls outside of the +// input data. // -// - Inputs should not assume that the offset is correctly aligned. Inputs may -// choose to service or reject loads to unaligned addresses. +// - Inputs should not assume that the offset is correctly aligned. Inputs may +// choose to service or reject loads to unaligned addresses. type Input interface { // Load32 reads 32 bits from the input starting at the given byte offset. Load32(off uint32) (uint32, bool) diff --git a/pkg/cleanup/cleanup.go b/pkg/cleanup/cleanup.go index 14a05f076..f963ed30d 100644 --- a/pkg/cleanup/cleanup.go +++ b/pkg/cleanup/cleanup.go @@ -17,13 +17,14 @@ package cleanup // Cleanup allows defers to be aborted when cleanup needs to happen // conditionally. Usage: -// cu := cleanup.Make(func() { f.Close() }) -// defer cu.Clean() // failure before release is called will close the file. -// ... -// cu.Add(func() { f2.Close() }) // Adds another cleanup function -// ... -// cu.Release() // on success, aborts closing the file. -// return f +// +// cu := cleanup.Make(func() { f.Close() }) +// defer cu.Clean() // failure before release is called will close the file. +// ... +// cu.Add(func() { f2.Close() }) // Adds another cleanup function +// ... +// cu.Release() // on success, aborts closing the file. +// return f type Cleanup struct { cleaners []func() } diff --git a/pkg/compressio/compressio.go b/pkg/compressio/compressio.go index 615d7f134..b6cfeb377 100644 --- a/pkg/compressio/compressio.go +++ b/pkg/compressio/compressio.go @@ -35,9 +35,9 @@ // // where each subsequent hash is calculated from the following items in order // -// compressed data -// compressed data size -// previous hash +// compressed data +// compressed data size +// previous hash // // so the stream integrity cannot be compromised by switching and mixing // compressed chunks. diff --git a/pkg/context/context.go b/pkg/context/context.go index 83f081b93..d1e179877 100644 --- a/pkg/context/context.go +++ b/pkg/context/context.go @@ -140,12 +140,12 @@ func (*NoTask) UninterruptibleSleepFinish(bool) {} // context.Context, the standard type represents the state of an operation // rather than that of a goroutine. This is a critical distinction: // -// - Unlike context.Context, which "may be passed to functions running in -// different goroutines", it is *not safe* to use the same Context in multiple -// concurrent goroutines. +// - Unlike context.Context, which "may be passed to functions running in +// different goroutines", it is *not safe* to use the same Context in multiple +// concurrent goroutines. // -// - It is *not safe* to retain a Context passed to a function beyond the scope -// of that function call. +// - It is *not safe* to retain a Context passed to a function beyond the scope +// of that function call. // // In both cases, values extracted from the Context should be used instead. type Context interface { diff --git a/pkg/cpuid/cpuid.go b/pkg/cpuid/cpuid.go index f7fa74a3a..6da806643 100644 --- a/pkg/cpuid/cpuid.go +++ b/pkg/cpuid/cpuid.go @@ -60,8 +60,8 @@ func FromContext(ctx context) FeatureSet { // On x86, features are numbered according to "blocks". Each block is 32 bits, and // feature bits from the same source (cpuid leaf/level) are in the same block. // -// On arm64, features are numbered according to the ELF HWCAP definition, from: -// arch/arm64/include/uapi/asm/hwcap.h +// On arm64, features are numbered according to the ELF HWCAP definition, from +// arch/arm64/include/uapi/asm/hwcap.h. type Feature int // allFeatureInfo is the value for allFeatures. diff --git a/pkg/cpuid/cpuid_amd64.go b/pkg/cpuid/cpuid_amd64.go index 51beeee2d..b315107ac 100644 --- a/pkg/cpuid/cpuid_amd64.go +++ b/pkg/cpuid/cpuid_amd64.go @@ -27,11 +27,11 @@ import ( // Common references: // // Intel: -// * Intel SDM Volume 2, Chapter 3.2 "CPUID" (more up-to-date) -// * Intel Application Note 485 (more detailed) +// - Intel SDM Volume 2, Chapter 3.2 "CPUID" (more up-to-date) +// - Intel Application Note 485 (more detailed) // // AMD: -// * AMD64 APM Volume 3, Appendix 3 "Obtaining Processor Information ..." +// - AMD64 APM Volume 3, Appendix 3 "Obtaining Processor Information ..." // // +stateify savable type FeatureSet struct { diff --git a/pkg/cpuid/native_arm64.go b/pkg/cpuid/native_arm64.go index 44ad5db37..5ddd43bd4 100644 --- a/pkg/cpuid/native_arm64.go +++ b/pkg/cpuid/native_arm64.go @@ -150,26 +150,27 @@ func initCPUInfo() { // decimal key-value pairs on the 64-bit system. // // $ od -t d8 /proc/self/auxv -// 0000000 33 140734615224320 -// 0000020 16 3219913727 -// 0000040 6 4096 -// 0000060 17 100 -// 0000100 3 94665627353152 -// 0000120 4 56 -// 0000140 5 9 -// 0000160 7 140425502162944 -// 0000200 8 0 -// 0000220 9 94665627365760 -// 0000240 11 1000 -// 0000260 12 1000 -// 0000300 13 1000 -// 0000320 14 1000 -// 0000340 23 0 -// 0000360 25 140734614619513 -// 0000400 26 0 -// 0000420 31 140734614626284 -// 0000440 15 140734614619529 -// 0000460 0 0 +// +// 0000000 33 140734615224320 +// 0000020 16 3219913727 +// 0000040 6 4096 +// 0000060 17 100 +// 0000100 3 94665627353152 +// 0000120 4 56 +// 0000140 5 9 +// 0000160 7 140425502162944 +// 0000200 8 0 +// 0000220 9 94665627365760 +// 0000240 11 1000 +// 0000260 12 1000 +// 0000300 13 1000 +// 0000320 14 1000 +// 0000340 23 0 +// 0000360 25 140734614619513 +// 0000400 26 0 +// 0000420 31 140734614626284 +// 0000440 15 140734614619529 +// 0000460 0 0 func initHwCap() { auxv, err := ioutil.ReadFile("/proc/self/auxv") if err != nil { diff --git a/pkg/flipcall/flipcall.go b/pkg/flipcall/flipcall.go index 55787d572..a7184e3db 100644 --- a/pkg/flipcall/flipcall.go +++ b/pkg/flipcall/flipcall.go @@ -181,9 +181,9 @@ const ( // Connect blocks until the peer Endpoint has called Endpoint.RecvFirst(). // // Preconditions: -// * ep is a client Endpoint. -// * ep.Connect(), ep.RecvFirst(), ep.SendRecv(), and ep.SendLast() have never -// been called. +// - ep is a client Endpoint. +// - ep.Connect(), ep.RecvFirst(), ep.SendRecv(), and ep.SendLast() have never +// been called. func (ep *Endpoint) Connect() error { err := ep.ctrlConnect() if err == nil { @@ -196,8 +196,8 @@ func (ep *Endpoint) Connect() error { // returns the datagram length specified by that call. // // Preconditions: -// * ep is a server Endpoint. -// * ep.SendRecv(), ep.RecvFirst(), and ep.SendLast() have never been called. +// - ep is a server Endpoint. +// - ep.SendRecv(), ep.RecvFirst(), and ep.SendLast() have never been called. func (ep *Endpoint) RecvFirst() (uint32, error) { if err := ep.ctrlWaitFirst(); err != nil { return 0, err @@ -216,11 +216,11 @@ func (ep *Endpoint) RecvFirst() (uint32, error) { // Endpoint.SendRecv() or Endpoint.SendLast(). // // Preconditions: -// * dataLen <= ep.DataCap(). -// * No previous call to ep.SendRecv() or ep.RecvFirst() has returned an error. -// * ep.SendLast() has never been called. -// * If ep is a client Endpoint, ep.Connect() has previously been called and -// returned nil. +// - dataLen <= ep.DataCap(). +// - No previous call to ep.SendRecv() or ep.RecvFirst() has returned an error. +// - ep.SendLast() has never been called. +// - If ep is a client Endpoint, ep.Connect() has previously been called and +// returned nil. func (ep *Endpoint) SendRecv(dataLen uint32) (uint32, error) { return ep.sendRecv(dataLen, false /* mayRetainP */) } @@ -264,11 +264,11 @@ func (ep *Endpoint) sendRecv(dataLen uint32, mayRetainP bool) (uint32, error) { // Endpoint.RecvFirst() to return with the given datagram length. // // Preconditions: -// * dataLen <= ep.DataCap(). -// * No previous call to ep.SendRecv() or ep.RecvFirst() has returned an error. -// * ep.SendLast() has never been called. -// * If ep is a client Endpoint, ep.Connect() has previously been called and -// returned nil. +// - dataLen <= ep.DataCap(). +// - No previous call to ep.SendRecv() or ep.RecvFirst() has returned an error. +// - ep.SendLast() has never been called. +// - If ep is a client Endpoint, ep.Connect() has previously been called and +// returned nil. func (ep *Endpoint) SendLast(dataLen uint32) error { if dataLen > ep.dataCap { panic(fmt.Sprintf("attempting to send packet with datagram length %d (maximum %d)", dataLen, ep.dataCap)) diff --git a/pkg/flipcall/flipcall_unsafe.go b/pkg/flipcall/flipcall_unsafe.go index 547fda618..cfd96bfa1 100644 --- a/pkg/flipcall/flipcall_unsafe.go +++ b/pkg/flipcall/flipcall_unsafe.go @@ -25,11 +25,11 @@ import ( // Packets consist of a 16-byte header followed by an arbitrarily-sized // datagram. The header consists of: // -// - A 4-byte native-endian connection state. +// - A 4-byte native-endian connection state. // -// - A 4-byte native-endian datagram length in bytes. +// - A 4-byte native-endian datagram length in bytes. // -// - 8 reserved bytes. +// - 8 reserved bytes. const ( // PacketHeaderBytes is the size of a flipcall packet header in bytes. The // maximum datagram size supported by a flipcall connection is equal to the @@ -55,13 +55,13 @@ func (ep *Endpoint) dataLen() *atomicbitops.Uint32 { // Endpoint, which may concurrently mutate the contents of the packet window. // Thus: // -// - Readers must not assume that two reads of the same byte in Data() will -// return the same result. In other words, readers should read any given byte -// in Data() at most once. +// - Readers must not assume that two reads of the same byte in Data() will +// return the same result. In other words, readers should read any given byte +// in Data() at most once. // -// - Writers must not assume that they will read back the same data that they -// have written. In other words, writers should avoid reading from Data() at -// all. +// - Writers must not assume that they will read back the same data that they +// have written. In other words, writers should avoid reading from Data() at +// all. func (ep *Endpoint) Data() (bs []byte) { bshdr := (*reflect.SliceHeader)(unsafe.Pointer(&bs)) bshdr.Data = ep.packet + PacketHeaderBytes diff --git a/pkg/hostarch/addr_range_seq_unsafe.go b/pkg/hostarch/addr_range_seq_unsafe.go index ecc17d595..31b0452c1 100644 --- a/pkg/hostarch/addr_range_seq_unsafe.go +++ b/pkg/hostarch/addr_range_seq_unsafe.go @@ -83,9 +83,9 @@ func AddrRangeSeqFromSlice(slice []AddrRange) AddrRangeSeq { } // Preconditions: -// * The combined length of all AddrRanges in slice <= limit. -// * limit >= 0. -// * If len(slice) != 0, then limit > 0. +// - The combined length of all AddrRanges in slice <= limit. +// - limit >= 0. +// - If len(slice) != 0, then limit > 0. func addrRangeSeqFromSliceLimited(slice []AddrRange, limit int64) AddrRangeSeq { switch len(slice) { case 0: @@ -179,13 +179,13 @@ func (ars AddrRangeSeq) externalTail() AddrRangeSeq { // at least ars.Head(), even if n == 0. This guarantees that the basic pattern // of: // -// for !ars.IsEmpty() { -// n, err = doIOWith(ars.Head()) -// if err != nil { -// return err -// } -// ars = ars.DropFirst(n) -// } +// for !ars.IsEmpty() { +// n, err = doIOWith(ars.Head()) +// if err != nil { +// return err +// } +// ars = ars.DropFirst(n) +// } // // works even in the presence of zero-length AddrRanges. // diff --git a/pkg/ilist/list.go b/pkg/ilist/list.go index 7405ed6cb..0d6e14481 100644 --- a/pkg/ilist/list.go +++ b/pkg/ilist/list.go @@ -55,9 +55,10 @@ func (ElementMapper) linkerFor(elem Element) Linker { return elem } // The zero value for List is an empty list ready to use. // // To iterate over a list (where l is a List): -// for e := l.Front(); e != nil; e = e.Next() { -// // do something with e. -// } +// +// for e := l.Front(); e != nil; e = e.Next() { +// // do something with e. +// } // // +stateify savable type List struct { diff --git a/pkg/lisafs/client.go b/pkg/lisafs/client.go index 52e44d884..21c2d9e7a 100644 --- a/pkg/lisafs/client.go +++ b/pkg/lisafs/client.go @@ -402,10 +402,10 @@ func debugf(action string, comm Communicator, debugMsg debugStringer) { // Postcondition: releaseCommunicator() must be called on the returned value. func (c *Client) acquireCommunicator() Communicator { // Prefer using channel over socket because: - // - Channel uses a shared memory region for passing messages. IO from shared - // memory is faster and does not involve making a syscall. - // - No intermediate buffer allocation needed. With a channel, the message - // can be directly pasted into the shared memory region. + // - Channel uses a shared memory region for passing messages. IO from shared + // memory is faster and does not involve making a syscall. + // - No intermediate buffer allocation needed. With a channel, the message + // can be directly pasted into the shared memory region. if ch := c.getChannel(); ch != nil { return ch } diff --git a/pkg/lisafs/connection.go b/pkg/lisafs/connection.go index a85264462..c81ef98fb 100644 --- a/pkg/lisafs/connection.go +++ b/pkg/lisafs/connection.go @@ -37,10 +37,10 @@ import ( // RPC concurrency. // // Reference model: -// * When any FD is created, the connection takes a ref on it which represents -// the client's ref on the FD. -// * The client can drop its ref via the Close RPC which will in turn make the -// connection drop its ref. +// - When any FD is created, the connection takes a ref on it which represents +// the client's ref on the FD. +// - The client can drop its ref via the Close RPC which will in turn make the +// connection drop its ref. type Connection struct { // server is the server on which this connection was created. It is immutably // associated with it for its entire lifetime. @@ -343,8 +343,8 @@ func (c *Connection) removeFD(id FDID) { // removeControlFDLocked is the same as removeFD with added preconditions. // // Preconditions: -// * server's rename mutex must at least be read locked. -// * id must be pointing to a control FD. +// - server's rename mutex must at least be read locked. +// - id must be pointing to a control FD. func (c *Connection) removeControlFDLocked(id FDID) { c.fdsMu.Lock() fd := c.stopTrackingFD(id) diff --git a/pkg/lisafs/fd.go b/pkg/lisafs/fd.go index e94e74cd5..32b811085 100644 --- a/pkg/lisafs/fd.go +++ b/pkg/lisafs/fd.go @@ -53,7 +53,7 @@ type genericFD interface { // being performed. // // Reference Model: -// * Each control FD holds a ref on its Node for its entire lifetime. +// - Each control FD holds a ref on its Node for its entire lifetime. type ControlFD struct { controlFDRefs controlFDEntry @@ -120,8 +120,8 @@ func (fd *ControlFD) destroyLocked() { // filesystem tree. // // Preconditions: -// * server's rename mutex must be at least read locked. -// * The caller must take a ref on node which is transferred to fd. +// - server's rename mutex must be at least read locked. +// - The caller must take a ref on node which is transferred to fd. func (fd *ControlFD) Init(c *Connection, node *Node, mode linux.FileMode, impl ControlFDImpl) { fd.conn = c fd.node = node @@ -172,9 +172,9 @@ func (fd *ControlFD) Node() *Node { // RemoveFromConn removes this control FD from its owning connection. // // Preconditions: -// * fd should not have been returned to the client. Otherwise the client can -// still refer to it. -// * server's rename mutex must at least be read locked. +// - fd should not have been returned to the client. Otherwise the client can +// still refer to it. +// - server's rename mutex must at least be read locked. func (fd *ControlFD) RemoveFromConn() { fd.conn.removeControlFDLocked(fd.id) } @@ -224,7 +224,7 @@ func (fd *ControlFD) forEachOpenFD(fn func(ofd *OpenFD)) { // tree. See OpenFDImpl for the supported operations. // // Reference Model: -// * An OpenFD takes a reference on the control FD it was opened on. +// - An OpenFD takes a reference on the control FD it was opened on. type OpenFD struct { openFDRefs openFDEntry @@ -286,7 +286,7 @@ func (fd *OpenFD) Init(cfd *ControlFD, flags uint32, impl OpenFDImpl) { // BoundSocketFD represents a bound socket on the server. // // Reference Model: -// * A BoundSocketFD takes a reference on the control FD it is bound to. +// - A BoundSocketFD takes a reference on the control FD it is bound to. type BoundSocketFD struct { boundSocketFDRefs diff --git a/pkg/lisafs/handlers.go b/pkg/lisafs/handlers.go index 868c47c45..adf5773b3 100644 --- a/pkg/lisafs/handlers.go +++ b/pkg/lisafs/handlers.go @@ -39,10 +39,10 @@ const ( // RPCHandler defines a handler that is invoked when the associated message is // received. The handler is responsible for: // -// * Unmarshalling the request from the passed payload and interpreting it. -// * Marshalling the response into the communicator's payload buffer. -// * Return the number of payload bytes written. -// * Donate any FDs (if needed) to comm which will in turn donate it to client. +// - Unmarshalling the request from the passed payload and interpreting it. +// - Marshalling the response into the communicator's payload buffer. +// - Return the number of payload bytes written. +// - Donate any FDs (if needed) to comm which will in turn donate it to client. type RPCHandler func(c *Connection, comm Communicator, payloadLen uint32) (uint32, error) var handlers = [...]RPCHandler{ diff --git a/pkg/lisafs/lisafs.go b/pkg/lisafs/lisafs.go index 44ec50d08..363f88735 100644 --- a/pkg/lisafs/lisafs.go +++ b/pkg/lisafs/lisafs.go @@ -17,20 +17,21 @@ // filesystem server. // // Lock ordering: -// Server.renameMu -// Node.opMu -// Node.childrenMu -// Node.controlFDsMu +// +// Server.renameMu +// Node.opMu +// Node.childrenMu +// Node.controlFDsMu // // Locking rules: -// * Node.childrenMu can be simultaneously held on multiple nodes, ancestors -// before descendants. -// * Node.opMu can be simultaneously held on multiple nodes, ancestors before -// descendants. -// * Node.opMu can be simultaneously held on two nodes that do not have an -// ancestor-descendant relationship. One node must be an internal (directory) -// node and the other a leaf (non-directory) node. Directory must be locked -// before non-directories. -// * "Ancestors before descendants" requires that Server.renameMu is locked to -// ensure that this ordering remains satisfied. +// - Node.childrenMu can be simultaneously held on multiple nodes, ancestors +// before descendants. +// - Node.opMu can be simultaneously held on multiple nodes, ancestors before +// descendants. +// - Node.opMu can be simultaneously held on two nodes that do not have an +// ancestor-descendant relationship. One node must be an internal (directory) +// node and the other a leaf (non-directory) node. Directory must be locked +// before non-directories. +// - "Ancestors before descendants" requires that Server.renameMu is locked to +// ensure that this ordering remains satisfied. package lisafs diff --git a/pkg/lisafs/message.go b/pkg/lisafs/message.go index 38d2cc437..f0a732dee 100644 --- a/pkg/lisafs/message.go +++ b/pkg/lisafs/message.go @@ -31,10 +31,10 @@ import ( // "dataLen" refers to the size of both combined. // // All messages must implement the following functions: -// * marshal.Marshallable.SizeBytes -// * marshal.Marshallable.Marshal{Unsafe/Bytes} -// * marshal.CheckedMarshallable.CheckedUnmarshal -// * fmt.Stringer.String +// * marshal.Marshallable.SizeBytes +// * marshal.Marshallable.Marshal{Unsafe/Bytes} +// * marshal.CheckedMarshallable.CheckedUnmarshal +// * fmt.Stringer.String // // There is no explicit interface definition for this because that definition // will not be used anywhere. If a concrete type is passed into a function diff --git a/pkg/lisafs/node.go b/pkg/lisafs/node.go index 0bf5c8ebd..2282d3a12 100644 --- a/pkg/lisafs/node.go +++ b/pkg/lisafs/node.go @@ -34,7 +34,7 @@ const numStaticChildren = 5 // one Node for a given filesystem position. // // Reference Model: -// * Each node holds a ref on its parent for its entire lifetime. +// - Each node holds a ref on its parent for its entire lifetime. type Node struct { // node's ref count is protected by its parent's childrenMu. nodeRefs @@ -42,7 +42,7 @@ type Node struct { // opMu synchronizes high level operations on this path. // // It is used to ensure the following which are important for security: - // * This node's data is protected by opMu. So all operations that change its + // * This node's data is protected by opMu. So all operations that change its // data should hold opMu for writing. For example: write, setstat, setxattr, // etc. This entails that if this node represents a directory, creation and // deletion operations happening directly under this directory must lock @@ -50,7 +50,7 @@ type Node struct { // reading. This is to avoid the can of worms that open when creation and // deletion are allowed to race. This prevents any walks from occurring // during creation or deletion. - // * When this node is being deleted, the deletion handler must hold opMu for + // * When this node is being deleted, the deletion handler must hold opMu for // writing. This ensures that there are no concurrent operations going on // this node while it is being deleted and potentially being replaced with // something hazardous. @@ -169,8 +169,8 @@ func (n *Node) WithChildrenMu(fn func()) { // because all internal (non-leaf) nodes are directories. // // Precondition: -// * server's rename mutex must be at least read locked. Calling handlers must -// at least have read concurrency guarantee from the server. +// - server's rename mutex must be at least read locked. Calling handlers must +// at least have read concurrency guarantee from the server. func (n *Node) FilePath() string { // Walk upwards and prepend name to res. var res fspath.Builder diff --git a/pkg/log/glog.go b/pkg/log/glog.go index f57c4427b..47e22614b 100644 --- a/pkg/log/glog.go +++ b/pkg/log/glog.go @@ -34,18 +34,19 @@ var pid = os.Getpid() // Emit emits the message, google-style. // // Log lines have this form: -// Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg... +// +// Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg... // // where the fields are defined as follows: -// L A single character, representing the log level (eg 'I' for INFO) -// mm The month (zero padded; ie May is '05') -// dd The day (zero padded) -// hh:mm:ss.uuuuuu Time in hours, minutes and fractional seconds -// threadid The space-padded thread ID as returned by GetTID() -// file The file name -// line The line number -// msg The user-supplied message // +// L A single character, representing the log level (eg 'I' for INFO) +// mm The month (zero padded; ie May is '05') +// dd The day (zero padded) +// hh:mm:ss.uuuuuu Time in hours, minutes and fractional seconds +// threadid The space-padded thread ID as returned by GetTID() +// file The file name +// line The line number +// msg The user-supplied message func (g GoogleEmitter) Emit(depth int, level Level, timestamp time.Time, format string, args ...interface{}) { // Log level. prefix := byte('?') diff --git a/pkg/metric/metric.go b/pkg/metric/metric.go index d038f95d6..e988360ff 100644 --- a/pkg/metric/metric.go +++ b/pkg/metric/metric.go @@ -115,8 +115,8 @@ var ( // Initialize sends a metric registration event over the event channel. // // Precondition: -// * All metrics are registered. -// * Initialize/Disable has not been called. +// - All metrics are registered. +// - Initialize/Disable has not been called. func Initialize() error { if initialized { return errors.New("metric.Initialize called after metric.Initialize or metric.Disable") @@ -145,8 +145,8 @@ func Initialize() error { // disabling metric collection. // // Precondition: -// * All metrics are registered. -// * Initialize/Disable has not been called. +// - All metrics are registered. +// - Initialize/Disable has not been called. func Disable() error { if initialized { return errors.New("metric.Disable called after metric.Initialize or metric.Disable") @@ -240,6 +240,7 @@ func newFieldMapper(fields ...Field) (fieldMapper, error) { // makeMap(). // This *must* be called with the correct number of fields, or it will panic. // +checkescape:all +// //go:nosplit func (m fieldMapper) lookupConcat(fields1, fields2 []string) int { if (len(fields1) + len(fields2)) != len(m.fields) { @@ -282,6 +283,7 @@ IdxLookup2: // makeMap(). // This *must* be called with the correct number of fields, or it will panic. // +checkescape:all +// //go:nosplit func (m fieldMapper) lookup(fields ...string) int { return m.lookupConcat(fields, nil) @@ -295,10 +297,10 @@ func (m fieldMapper) numKeys() int { } // makeDistributionSampleMap creates a two dimensional array, where: -// - The first level corresponds to unique field value combinations and is -// accessed using index "keys" made by fieldMapper. -// - The second level corresponds to buckets within a metric. The number of -// buckets is specified by numBuckets. +// - The first level corresponds to unique field value combinations and is +// accessed using index "keys" made by fieldMapper. +// - The second level corresponds to buckets within a metric. The number of +// buckets is specified by numBuckets. func (m fieldMapper) makeDistributionSampleMap(numBuckets int) [][]atomicbitops.Uint64 { samples := make([][]atomicbitops.Uint64, m.numKeys()) for i := range samples { @@ -331,9 +333,9 @@ func (m fieldMapper) keyToMultiField(key int) []string { // after Initialized. // // Preconditions: -// * name must be globally unique. -// * Initialize/Disable have not been called. -// * value is expected to accept exactly len(fields) arguments. +// - name must be globally unique. +// - Initialize/Disable have not been called. +// - value is expected to accept exactly len(fields) arguments. func RegisterCustomUint64Metric(name string, cumulative, sync bool, units pb.MetricMetadata_Units, description string, value func(...string) uint64, fields ...Field) error { if initialized { return ErrInitializationDone @@ -415,6 +417,7 @@ func MustCreateNewUint64NanosecondsMetric(name string, sync bool, description st // Value returns the current value of the metric for the given set of fields. // This must be called with the correct number of field values or it will panic. +// //go:nosplit func (m *Uint64Metric) Value(fieldValues ...string) uint64 { key := m.fieldMapper.lookupConcat(fieldValues, nil) @@ -423,6 +426,7 @@ func (m *Uint64Metric) Value(fieldValues ...string) uint64 { // Increment increments the metric field by 1. // This must be called with the correct number of field values or it will panic. +// //go:nosplit func (m *Uint64Metric) Increment(fieldValues ...string) { key := m.fieldMapper.lookupConcat(fieldValues, nil) @@ -431,6 +435,7 @@ func (m *Uint64Metric) Increment(fieldValues ...string) { // IncrementBy increments the metric by v. // This must be called with the correct number of field values or it will panic. +// //go:nosplit func (m *Uint64Metric) IncrementBy(v uint64, fieldValues ...string) { key := m.fieldMapper.lookupConcat(fieldValues, nil) @@ -547,6 +552,7 @@ func (b *ExponentialBucketer) LowerBound(bucketIndex int) int64 { // BucketIndex implements Bucketer.BucketIndex. // +checkescape:all +// //go:nosplit func (b *ExponentialBucketer) BucketIndex(sample int64) int { if sample < 0 { @@ -677,6 +683,7 @@ func MustRegisterDistributionMetric(name string, sync bool, bucketer Bucketer, u // AddSample adds a sample to the distribution. // This *must* be called with the correct number of fields, or it will panic. // +checkescape:all +// //go:nosplit func (d *DistributionMetric) AddSample(sample int64, fields ...string) { d.addSampleByKey(sample, d.fieldsToKey.lookup(fields...)) @@ -684,6 +691,7 @@ func (d *DistributionMetric) AddSample(sample int64, fields ...string) { // addSampleByKey works like AddSample, with the field key already known. // +checkescape:all +// //go:nosplit func (d *DistributionMetric) addSampleByKey(sample int64, key int) { bucket := d.exponentialBucketer.BucketIndex(sample) @@ -717,9 +725,9 @@ type TimerMetric struct { // NewTimerMetric provides a convenient way to measure latencies. // The arguments are the same as `NewDistributionMetric`, except: -// - `nanoBucketer`: Same as `NewDistribution`'s `bucketer`, expected to hold -// durations in nanoseconds. Adjust parameters accordingly. -// NewDurationBucketer may be helpful here. +// - `nanoBucketer`: Same as `NewDistribution`'s `bucketer`, expected to hold +// durations in nanoseconds. Adjust parameters accordingly. +// NewDurationBucketer may be helpful here. func NewTimerMetric(name string, nanoBucketer Bucketer, description string, fields ...Field) (*TimerMetric, error) { distrib, err := NewDistributionMetric(name, false, nanoBucketer, pb.MetricMetadata_UNITS_NANOSECONDS, description, fields...) if err != nil { @@ -763,6 +771,7 @@ type TimedOperation struct { // where which path an operation took is only known after it happens. This // path can be part of the fields passed to Finish. // +checkescape:all +// //go:nosplit func (t *TimerMetric) Start(fields ...string) TimedOperation { return TimedOperation{ @@ -777,6 +786,7 @@ func (t *TimerMetric) Start(fields ...string) TimedOperation { // `TimerMetric.Start`. The concatenation of these two must be the exact // number of fields that the underlying metric has. // +checkescape:all +// //go:nosplit func (o TimedOperation) Finish(extraFields ...string) { ended := CheapNowNano() @@ -924,7 +934,7 @@ var ( // EmitMetricUpdate is thread-safe. // // Preconditions: -// * Initialize has been called. +// - Initialize has been called. func EmitMetricUpdate() { emitMu.Lock() defer emitMu.Unlock() diff --git a/pkg/metric/metric_unsafe.go b/pkg/metric/metric_unsafe.go index 59c7146a6..a9efce085 100644 --- a/pkg/metric/metric_unsafe.go +++ b/pkg/metric/metric_unsafe.go @@ -49,6 +49,7 @@ func snapshotDistribution(samples []atomicbitops.Uint64) []uint64 { } // CheapNowNano returns the current unix timestamp in nanoseconds. +// //go:nosplit func CheapNowNano() int64 { return gohacks.Nanotime() diff --git a/pkg/p9/client.go b/pkg/p9/client.go index d618da820..45ee59a92 100644 --- a/pkg/p9/client.go +++ b/pkg/p9/client.go @@ -103,7 +103,7 @@ type Client struct { // efficient, and does not require tags). sendRecv func(message, message) error - // -- below corresponds to sendRecvChannel -- + // -- below corresponds to sendRecvChannel -- // channelsMu protects channels. channelsMu sync.Mutex @@ -118,7 +118,7 @@ type Client struct { // availableChannels is a LIFO of inactive channels. availableChannels []*channel - // -- below corresponds to sendRecvLegacy -- + // -- below corresponds to sendRecvLegacy -- // pending is the set of pending messages. pending map[Tag]*response diff --git a/pkg/p9/p9test/client_test.go b/pkg/p9/p9test/client_test.go index e7ed08c06..84a1fc7b0 100644 --- a/pkg/p9/p9test/client_test.go +++ b/pkg/p9/p9test/client_test.go @@ -130,25 +130,27 @@ func newTypeMap(h *Harness) map[string]Generator { // This is set up in a deterministic way for testing most operations. // // The represented file system looks like: -// - file -// - symlink -// - directory +// - file +// - symlink +// - directory +// // ... // + one // - file // - symlink // - directory -// ... -// + two -// - file -// - symlink -// - directory // ... +// - two +// - file +// - symlink +// - directory +// ... +// // + three // - file // - symlink // - directory -// ... +// ... func newRoot(h *Harness, c *p9.Client) (*Mock, p9.File) { root := newTypeMap(h) one := newTypeMap(h) @@ -257,9 +259,9 @@ func TestWalkInvalid(t *testing.T) { // fileGenerator is a function to generate files via walk or create. // // Examples are: -// - walkHelper -// - walkAndOpenHelper -// - createHelper +// - walkHelper +// - walkAndOpenHelper +// - createHelper type fileGenerator func(*Harness, string, p9.File) (*Mock, *Mock, p9.File) // walkHelper walks to the given file. @@ -1151,8 +1153,8 @@ func TestOpen(t *testing.T) { } // Open(flags OpenFlags) (*fd.FD, QID, uint32, error) - // - only works on Regular, NamedPipe, BLockDevice, CharacterDevice - // - returning a file works as expected + // - only works on Regular, NamedPipe, BLockDevice, CharacterDevice + // - returning a file works as expected for name := range newTypeMap(nil) { for _, tc := range cases { t.Run(fmt.Sprintf("%s-%s", tc.name, name), func(t *testing.T) { diff --git a/pkg/p9/p9test/p9test.go b/pkg/p9/p9test/p9test.go index d145cff36..f0122ac20 100644 --- a/pkg/p9/p9test/p9test.go +++ b/pkg/p9/p9test/p9test.go @@ -290,7 +290,6 @@ func (h *Harness) Finish() { // // h, c := NewHarness(t) // defer h.Finish() -// func NewHarness(t *testing.T) (*Harness, *p9.Client) { // Create the mock. mockCtrl := gomock.NewController(t) diff --git a/pkg/p9/path_tree.go b/pkg/p9/path_tree.go index e514440c5..c7d01a68d 100644 --- a/pkg/p9/path_tree.go +++ b/pkg/p9/path_tree.go @@ -26,11 +26,12 @@ import ( // These are shared by all fidRefs that point to the same path. // // Lock ordering: -// opMu -// childMu // -// Two different pathNodes may only be locked if Server.renameMu is held for -// write, in which case they can be acquired in any order. +// opMu +// childMu +// +// Two different pathNodes may only be locked if Server.renameMu is held for +// write, in which case they can be acquired in any order. type pathNode struct { // opMu synchronizes high-level, sematic operations, such as the // simultaneous creation and deletion of a file. diff --git a/pkg/p9/server.go b/pkg/p9/server.go index 4d3463d74..ae9b1df1b 100644 --- a/pkg/p9/server.go +++ b/pkg/p9/server.go @@ -92,7 +92,7 @@ type connState struct { // reqGate counts requests that are still being handled. reqGate sync.Gate - // -- below relates to the legacy handler -- + // -- below relates to the legacy handler -- // recvMu serializes receiving from conn. recvMu sync.Mutex @@ -113,7 +113,7 @@ type connState struct { // conn is the connection used by the legacy transport. conn *unet.Socket - // -- below relates to the flipcall handler -- + // -- below relates to the flipcall handler -- // channelMu protects below. channelMu sync.Mutex diff --git a/pkg/p9/transport_flipcall.go b/pkg/p9/transport_flipcall.go index 69a9f2537..bc5dc51ab 100644 --- a/pkg/p9/transport_flipcall.go +++ b/pkg/p9/transport_flipcall.go @@ -58,11 +58,11 @@ type channel struct { fds fdchannel.Endpoint buf buffer - // -- client only -- + // -- client only -- connected bool active bool - // -- server only -- + // -- server only -- client *fd.FD done chan struct{} } diff --git a/pkg/p9/version.go b/pkg/p9/version.go index cbb50cb88..67f285201 100644 --- a/pkg/p9/version.go +++ b/pkg/p9/version.go @@ -65,9 +65,10 @@ func HighestVersionString() string { // predicate must be commented and should take the format: // // // VersionSupportsX returns true if version v supports X and must be checked when ... -// func VersionSupportsX(v int32) bool { -// ... -// ) +// +// func VersionSupportsX(v int32) bool { +// ... +// } func parseVersion(str string) (uint32, bool) { // Special case the base version which lacks the ".Google.X" suffix. This // version always means version 0. diff --git a/pkg/refs/refcounter.go b/pkg/refs/refcounter.go index 2bdf6a10c..a15b218fb 100644 --- a/pkg/refs/refcounter.go +++ b/pkg/refs/refcounter.go @@ -189,7 +189,7 @@ func (w *WeakRef) zap() { // favor of the refsvfs2 package. // // N.B. To allow the zero-object to be initialized, the count is offset by -// 1, that is, when refCount is n, there are really n+1 references. +// 1, that is, when refCount is n, there are really n+1 references. // // +stateify savable type AtomicRefCount struct { diff --git a/pkg/ring0/defs_arm64.go b/pkg/ring0/defs_arm64.go index 2a296c588..7d281cf98 100644 --- a/pkg/ring0/defs_arm64.go +++ b/pkg/ring0/defs_arm64.go @@ -124,6 +124,7 @@ func (c *CPU) SetAppAddr(value uintptr) { } // GetLazyVFP returns the value of cpacr_el1. +// //go:nosplit func (c *CPU) GetLazyVFP() (value uintptr) { return c.lazyVFP diff --git a/pkg/ring0/entry_amd64.go b/pkg/ring0/entry_amd64.go index 13ad4e4df..399d72d95 100644 --- a/pkg/ring0/entry_amd64.go +++ b/pkg/ring0/entry_amd64.go @@ -25,8 +25,8 @@ import ( // // The sysenter function is invoked in two situations: // -// (1) The guest kernel has executed a system call. -// (2) The guest application has executed a system call. +// (1) The guest kernel has executed a system call. +// (2) The guest application has executed a system call. // // The interrupt flag is examined to determine whether the system call was // executed from kernel mode or not and the appropriate stub is called. @@ -54,7 +54,7 @@ func sysret(cpu *CPU, regs *arch.Registers, userCR3 uintptr) Vector // "iret is the cadillac of CPL switching." // -// -- Neel Natu +// -- Neel Natu // // iret is nearly identical to sysret, except an iret is used to fully restore // all user state. This must be called in cases where all registers need to be @@ -80,13 +80,13 @@ func start() // // The following start conditions must be satisfied: // -// * AX should contain the CPU pointer. -// * c.GDT() should be loaded as the GDT. -// * c.IDT() should be loaded as the IDT. -// * c.CR0() should be the current CR0 value. -// * c.CR3() should be set to the kernel PageTables. -// * c.CR4() should be the current CR4 value. -// * c.EFER() should be the current EFER value. +// - AX should contain the CPU pointer. +// - c.GDT() should be loaded as the GDT. +// - c.IDT() should be loaded as the IDT. +// - c.CR0() should be the current CR0 value. +// - c.CR3() should be set to the kernel PageTables. +// - c.CR4() should be the current CR4 value. +// - c.EFER() should be the current EFER value. // // The CPU state will be set to c.Registers(). // diff --git a/pkg/ring0/kernel_amd64.go b/pkg/ring0/kernel_amd64.go index 0f90d3a2d..a8195508b 100644 --- a/pkg/ring0/kernel_amd64.go +++ b/pkg/ring0/kernel_amd64.go @@ -273,11 +273,11 @@ func doSwitchToUser( // registers in c.registers will be restored (not segments). // // Note that any code written in Go should adhere to Go expected environment: -// * Initialized floating point state (required for optimizations using -// floating point instructions). -// * Go TLS in FS_BASE (this is required by splittable functions, calls into -// the runtime, calls to assembly functions (Go 1.17+ ABI wrappers access -// TLS)). +// - Initialized floating point state (required for optimizations using +// floating point instructions). +// - Go TLS in FS_BASE (this is required by splittable functions, calls into +// the runtime, calls to assembly functions (Go 1.17+ ABI wrappers access +// TLS)). // //go:nosplit func startGo(c *CPU) { diff --git a/pkg/ring0/kernel_arm64.go b/pkg/ring0/kernel_arm64.go index 889150589..187b244ee 100644 --- a/pkg/ring0/kernel_arm64.go +++ b/pkg/ring0/kernel_arm64.go @@ -18,14 +18,17 @@ package ring0 // HaltAndResume halts execution and point the pointer to the resume function. +// //go:nosplit func HaltAndResume() // HaltEl1SvcAndResume calls Hooks.KernelSyscall and resume. +// //go:nosplit func HaltEl1SvcAndResume() // HaltEl1ExceptionAndResume calls Hooks.KernelException and resume. +// //go:nosplit func HaltEl1ExceptionAndResume() diff --git a/pkg/ring0/pagetables/pagetables.go b/pkg/ring0/pagetables/pagetables.go index 3f17fba49..4f751dd7d 100644 --- a/pkg/ring0/pagetables/pagetables.go +++ b/pkg/ring0/pagetables/pagetables.go @@ -61,6 +61,7 @@ type PageTables struct { // Init initializes a set of PageTables. // // +checkescape:hard,stack +// //go:nosplit func (p *PageTables) Init(allocator Allocator) { p.Allocator = allocator @@ -141,6 +142,7 @@ func (*mapVisitor) requiresSplit() bool { return true } // Precondition: addr & length must be page-aligned, their sum must not overflow. // // +checkescape:hard,stack +// //go:nosplit func (p *PageTables) Map(addr hostarch.Addr, length uintptr, opts MapOpts, physical uintptr) bool { if p.readOnlyShared { @@ -197,6 +199,7 @@ func (v *unmapVisitor) visit(start uintptr, pte *PTE, align uintptr) bool { // Precondition: addr & length must be page-aligned, their sum must not overflow. // // +checkescape:hard,stack +// //go:nosplit func (p *PageTables) Unmap(addr hostarch.Addr, length uintptr) bool { if p.readOnlyShared { @@ -248,6 +251,7 @@ func (v *emptyVisitor) visit(start uintptr, pte *PTE, align uintptr) bool { // Precondition: addr & length must be page-aligned. // // +checkescape:hard,stack +// //go:nosplit func (p *PageTables) IsEmpty(addr hostarch.Addr, length uintptr) bool { w := emptyWalker{ @@ -297,6 +301,7 @@ func (*lookupVisitor) requiresSplit() bool { return false } // Note that if size is zero, then no matching entry was found. // // +checkescape:hard,stack +// //go:nosplit func (p *PageTables) Lookup(addr hostarch.Addr, findFirst bool) (virtual hostarch.Addr, physical, size uintptr, opts MapOpts) { mask := uintptr(hostarch.PageSize - 1) diff --git a/pkg/ring0/pagetables/pagetables_amd64.go b/pkg/ring0/pagetables/pagetables_amd64.go index a217f404c..4639bd48a 100644 --- a/pkg/ring0/pagetables/pagetables_amd64.go +++ b/pkg/ring0/pagetables/pagetables_amd64.go @@ -44,6 +44,7 @@ const ( // InitArch does some additional initialization related to the architecture. // // +checkescape:hard,stack +// //go:nosplit func (p *PageTables) InitArch(allocator Allocator) { if p.upperSharedPageTables != nil { diff --git a/pkg/ring0/pagetables/pagetables_arm64.go b/pkg/ring0/pagetables/pagetables_arm64.go index fef7a0fd1..0613659a3 100644 --- a/pkg/ring0/pagetables/pagetables_arm64.go +++ b/pkg/ring0/pagetables/pagetables_arm64.go @@ -45,6 +45,7 @@ const ( // InitArch does some additional initialization related to the architecture. // // +checkescape:hard,stack +// //go:nosplit func (p *PageTables) InitArch(allocator Allocator) { if p.upperSharedPageTables != nil { diff --git a/pkg/safemem/block_unsafe.go b/pkg/safemem/block_unsafe.go index 4af534385..7d4c53f0d 100644 --- a/pkg/safemem/block_unsafe.go +++ b/pkg/safemem/block_unsafe.go @@ -26,10 +26,10 @@ import ( // A Block is a range of contiguous bytes, similar to []byte but with the // following differences: // -// - The memory represented by a Block may require the use of safecopy to -// access. +// - The memory represented by a Block may require the use of safecopy to +// access. // -// - Block does not carry a capacity and cannot be expanded. +// - Block does not carry a capacity and cannot be expanded. // // Blocks are immutable and may be copied by value. The zero value of Block // represents an empty range, analogous to a nil []byte. diff --git a/pkg/safemem/seq_unsafe.go b/pkg/safemem/seq_unsafe.go index bbf8740a5..027f6c65d 100644 --- a/pkg/safemem/seq_unsafe.go +++ b/pkg/safemem/seq_unsafe.go @@ -93,9 +93,9 @@ func BlockSeqFromSlice(slice []Block) BlockSeq { } // Preconditions: -// * The combined length of all Blocks in slice <= limit. -// * If len(slice) != 0, the first Block in slice has non-zero length and -// limit > 0. +// - The combined length of all Blocks in slice <= limit. +// - If len(slice) != 0, the first Block in slice has non-zero length and +// limit > 0. func blockSeqFromSliceLimited(slice []Block, limit uint64) BlockSeq { switch len(slice) { case 0: diff --git a/pkg/seccomp/seccomp.go b/pkg/seccomp/seccomp.go index da5a861a2..cb85d46c1 100644 --- a/pkg/seccomp/seccomp.go +++ b/pkg/seccomp/seccomp.go @@ -407,19 +407,22 @@ func addSyscallArgsCheck(p *bpf.ProgramBuilder, rules []Rule, action linux.BPFAc // is as follows: // // // SYS_PIPE(22), root -// (A == 22) ? goto argument check : continue -// (A > 22) ? goto index_35 : goto index_9 +// +// (A == 22) ? goto argument check : continue +// (A > 22) ? goto index_35 : goto index_9 // // index_9: // SYS_MMAP(9), leaf -// A == 9) ? goto argument check : defaultLabel +// +// A == 9) ? goto argument check : defaultLabel // // index_35: // SYS_NANOSLEEP(35), single child -// (A == 35) ? goto argument check : continue -// (A > 35) ? goto index_50 : goto defaultLabel +// +// (A == 35) ? goto argument check : continue +// (A > 35) ? goto index_50 : goto defaultLabel // // index_50: // SYS_LISTEN(50), leaf -// (A == 50) ? goto argument check : goto defaultLabel // +// (A == 50) ? goto argument check : goto defaultLabel func buildBSTProgram(n *node, rules []RuleSet, program *bpf.ProgramBuilder) error { // Root node is never referenced by label, skip it. if !n.root { diff --git a/pkg/seccomp/seccomp_rules.go b/pkg/seccomp/seccomp_rules.go index 8967c51c9..5863b7092 100644 --- a/pkg/seccomp/seccomp_rules.go +++ b/pkg/seccomp/seccomp_rules.go @@ -21,12 +21,13 @@ import ( ) // The offsets are based on the following struct in include/linux/seccomp.h. -// struct seccomp_data { -// int nr; -// __u32 arch; -// __u64 instruction_pointer; -// __u64 args[6]; -// }; +// +// struct seccomp_data { +// int nr; +// __u32 arch; +// __u64 instruction_pointer; +// __u64 args[6]; +// }; const ( seccompDataOffsetNR = 0 seccompDataOffsetArch = 4 @@ -114,9 +115,10 @@ func MaskedEqual(mask, value uintptr) interface{} { // Rule stores the allowed syscall arguments. // // For example: -// rule := Rule { -// EqualTo(linux.ARCH_GET_FS | linux.ARCH_SET_FS), // arg0 -// } +// +// rule := Rule { +// EqualTo(linux.ARCH_GET_FS | linux.ARCH_SET_FS), // arg0 +// } type Rule [7]interface{} // 6 arguments + RIP // RuleIP indicates what rules in the Rule array have to be applied to @@ -141,18 +143,20 @@ func (r Rule) String() (s string) { // If the 'Rules' is empty, we treat it as any argument is allowed. // // For example: -// rules := SyscallRules{ -// syscall.SYS_FUTEX: []Rule{ -// { -// MatchAny{}, -// EqualTo(linux.FUTEX_WAIT | linux.FUTEX_PRIVATE_FLAG), -// }, // OR -// { -// MatchAny{}, -// EqualTo(linux.FUTEX_WAKE | linux.FUTEX_PRIVATE_FLAG), -// }, -// }, -// syscall.SYS_GETPID: []Rule{}, +// +// rules := SyscallRules{ +// syscall.SYS_FUTEX: []Rule{ +// { +// MatchAny{}, +// EqualTo(linux.FUTEX_WAIT | linux.FUTEX_PRIVATE_FLAG), +// }, // OR +// { +// MatchAny{}, +// EqualTo(linux.FUTEX_WAKE | linux.FUTEX_PRIVATE_FLAG), +// }, +// }, +// syscall.SYS_GETPID: []Rule{}, +// // } type SyscallRules map[uintptr][]Rule diff --git a/pkg/seccomp/seccomp_unsafe.go b/pkg/seccomp/seccomp_unsafe.go index 6701b5542..d2e7ea8a6 100644 --- a/pkg/seccomp/seccomp_unsafe.go +++ b/pkg/seccomp/seccomp_unsafe.go @@ -59,17 +59,17 @@ func SetFilter(instrs []linux.BPFInstruction) error { // SetFilterInChild is equivalent to SetFilter, but: // -// - It is safe to call after runtime.syscall_runtime_AfterForkInChild. +// - It is safe to call after runtime.syscall_runtime_AfterForkInChild. // -// - It requires that the calling goroutine cannot be moved to another thread, -// which either requires that runtime.LockOSThread() is in effect or that the -// caller is in fact in a fork()ed child process. +// - It requires that the calling goroutine cannot be moved to another thread, +// which either requires that runtime.LockOSThread() is in effect or that the +// caller is in fact in a fork()ed child process. // -// - Since fork()ed child processes cannot perform heap allocation, it returns -// a unix.Errno rather than an error. +// - Since fork()ed child processes cannot perform heap allocation, it returns +// a unix.Errno rather than an error. // -// - The race instrumentation has to be disabled for all functions that are -// called in a forked child. +// - The race instrumentation has to be disabled for all functions that are +// called in a forked child. // //go:norace //go:nosplit diff --git a/pkg/secio/secio.go b/pkg/secio/secio.go index b43226035..29e9671a5 100644 --- a/pkg/secio/secio.go +++ b/pkg/secio/secio.go @@ -27,9 +27,9 @@ var ErrReachedLimit = errors.New("reached limit") // SectionReader implements io.Reader on a section of an underlying io.ReaderAt. // It is similar to io.SectionReader, but: // -// - Reading beyond the limit returns ErrReachedLimit, not io.EOF. +// - Reading beyond the limit returns ErrReachedLimit, not io.EOF. // -// - Limit overflow is handled correctly. +// - Limit overflow is handled correctly. type SectionReader struct { r io.ReaderAt off int64 diff --git a/pkg/segment/set.go b/pkg/segment/set.go index fae6c363d..aa2e33647 100644 --- a/pkg/segment/set.go +++ b/pkg/segment/set.go @@ -99,11 +99,11 @@ type Functions interface { const ( // minDegree is the minimum degree of an internal node in a Set B-tree. // - // - Any non-root node has at least minDegree-1 segments. + // - Any non-root node has at least minDegree-1 segments. // - // - Any non-root internal (non-leaf) node has at least minDegree children. + // - Any non-root internal (non-leaf) node has at least minDegree children. // - // - The root node may have fewer than minDegree-1 segments, but it may + // - The root node may have fewer than minDegree-1 segments, but it may // only have 0 segments if the tree is empty. // // Our implementation requires minDegree >= 3. Higher values of minDegree @@ -408,8 +408,8 @@ func (s *Set) InsertWithoutMerging(gap GapIterator, r Range, val Value) Iterator // (including gap, but not including the returned iterator) are invalidated. // // Preconditions: -// * r.Start >= gap.Start(). -// * r.End <= gap.End(). +// - r.Start >= gap.Start(). +// - r.End <= gap.End(). func (s *Set) InsertWithoutMergingUnchecked(gap GapIterator, r Range, val Value) Iterator { gap = gap.node.rebalanceBeforeInsert(gap) splitMaxGap := trackGaps != 0 && (gap.node.nrSegments == 0 || gap.Range().Length() == gap.node.maxGap.Get()) @@ -1167,10 +1167,10 @@ func (n *node) searchLastLargeEnoughGap(minSize Key) GapIterator { // A Iterator is conceptually one of: // -// - A pointer to a segment in a set; or +// - A pointer to a segment in a set; or // -// - A terminal iterator, which is a sentinel indicating that the end of -// iteration has been reached. +// - A terminal iterator, which is a sentinel indicating that the end of +// iteration has been reached. // // Iterators are copyable values and are meaningfully equality-comparable. The // zero value of Iterator is a terminal iterator. @@ -1213,10 +1213,10 @@ func (seg Iterator) End() Key { // does not invalidate any iterators. // // Preconditions: -// * r.Length() > 0. -// * The new range must not overlap an existing one: -// * If seg.NextSegment().Ok(), then r.end <= seg.NextSegment().Start(). -// * If seg.PrevSegment().Ok(), then r.start >= seg.PrevSegment().End(). +// - r.Length() > 0. +// - The new range must not overlap an existing one: +// - If seg.NextSegment().Ok(), then r.end <= seg.NextSegment().Start(). +// - If seg.PrevSegment().Ok(), then r.start >= seg.PrevSegment().End(). func (seg Iterator) SetRangeUnchecked(r Range) { seg.node.keys[seg.index] = r } @@ -1242,8 +1242,8 @@ func (seg Iterator) SetRange(r Range) { // not invalidate any iterators. // // Preconditions: The new start must be valid: -// * start < seg.End() -// * If seg.PrevSegment().Ok(), then start >= seg.PrevSegment().End(). +// - start < seg.End() +// - If seg.PrevSegment().Ok(), then start >= seg.PrevSegment().End(). func (seg Iterator) SetStartUnchecked(start Key) { seg.node.keys[seg.index].Start = start } @@ -1266,8 +1266,8 @@ func (seg Iterator) SetStart(start Key) { // invalidate any iterators. // // Preconditions: The new end must be valid: -// * end > seg.Start(). -// * If seg.NextSegment().Ok(), then end <= seg.NextSegment().Start(). +// - end > seg.Start(). +// - If seg.NextSegment().Ok(), then end <= seg.NextSegment().Start(). func (seg Iterator) SetEndUnchecked(end Key) { seg.node.keys[seg.index].End = end } @@ -1380,11 +1380,11 @@ func (seg Iterator) NextNonEmpty() (Iterator, GapIterator) { // A GapIterator is conceptually one of: // -// - A pointer to a position between two segments, before the first segment, or -// after the last segment in a set, called a *gap*; or +// - A pointer to a position between two segments, before the first segment, or +// after the last segment in a set, called a *gap*; or // -// - A terminal iterator, which is a sentinel indicating that the end of -// iteration has been reached. +// - A terminal iterator, which is a sentinel indicating that the end of +// iteration has been reached. // // Note that the gap between two adjacent segments exists (iterators to it are // non-terminal), but has a length of zero. GapIterator.IsEmpty returns true @@ -1698,10 +1698,10 @@ func (s *Set) ExportSortedSlices() *SegmentDataSlices { // ImportSortedSlices initializes the given set from the given slice. // // Preconditions: -// * s must be empty. -// * sds must represent a valid set (the segments in sds must have valid -// lengths that do not overlap). -// * The segments in sds must be sorted in ascending key order. +// - s must be empty. +// - sds must represent a valid set (the segments in sds must have valid +// lengths that do not overlap). +// - The segments in sds must be sorted in ascending key order. func (s *Set) ImportSortedSlices(sds *SegmentDataSlices) error { if !s.IsEmpty() { return fmt.Errorf("cannot import into non-empty set %v", s) diff --git a/pkg/sentry/arch/arch_x86.go b/pkg/sentry/arch/arch_x86.go index 7c1b1601c..4f50b5f33 100644 --- a/pkg/sentry/arch/arch_x86.go +++ b/pkg/sentry/arch/arch_x86.go @@ -373,11 +373,11 @@ func (s *State) PtraceSetRegSet(regset uintptr, src io.Reader, maxlen int, fs cp func (s *State) FullRestore() bool { // A fast system call return is possible only if // - // * RCX matches the instruction pointer. - // * R11 matches our flags value. - // * Usermode does not expect to set either the resume flag or the + // * RCX matches the instruction pointer. + // * R11 matches our flags value. + // * Usermode does not expect to set either the resume flag or the // virtual mode flags (unlikely.) - // * CS and SS are set to the standard selectors. + // * CS and SS are set to the standard selectors. // // That is, SYSRET results in the correct final state. fastRestore := s.Regs.Rcx == s.Regs.Rip && diff --git a/pkg/sentry/arch/fpu/fpu_arm64.go b/pkg/sentry/arch/fpu/fpu_arm64.go index 49e641722..55b6925bf 100644 --- a/pkg/sentry/arch/fpu/fpu_arm64.go +++ b/pkg/sentry/arch/fpu/fpu_arm64.go @@ -32,7 +32,6 @@ const ( // // Currently, aarch64FPState is only a space of 0x210 length for fpstate. // The fp head is useless in sentry/ptrace/kvm. -// func initAarch64FPState(data *State) { } diff --git a/pkg/sentry/control/proc.go b/pkg/sentry/control/proc.go index 6352ea71a..d1617f909 100644 --- a/pkg/sentry/control/proc.go +++ b/pkg/sentry/control/proc.go @@ -375,9 +375,9 @@ func Processes(k *kernel.Kernel, containerID string, out *[]*Process) error { } // formatStartTime formats startTime depending on the current time: -// - If startTime was today, HH:MM is used. -// - If startTime was not today but was this year, MonDD is used (e.g. Jan02) -// - If startTime was not this year, the year is used. +// - If startTime was today, HH:MM is used. +// - If startTime was not today but was this year, MonDD is used (e.g. Jan02) +// - If startTime was not this year, the year is used. func formatStartTime(now, startTime ktime.Time) string { nowS, nowNs := now.Unix() n := time.Unix(nowS, nowNs) diff --git a/pkg/sentry/fs/copy_up.go b/pkg/sentry/fs/copy_up.go index e48bd4dba..0e8e2aca6 100644 --- a/pkg/sentry/fs/copy_up.go +++ b/pkg/sentry/fs/copy_up.go @@ -32,35 +32,35 @@ import ( // upper filesytem so that the file can be modified in the upper // filesystem. Copying a file involves several steps: // -// - All parent directories of the file are created in the upper -// filesystem if they don't exist there. For instance: +// - All parent directories of the file are created in the upper +// filesystem if they don't exist there. For instance: // // upper /dir0 // lower /dir0/dir1/file // -// copyUp of /dir0/dir1/file creates /dir0/dir1 in order to create -// /dir0/dir1/file. +// copyUp of /dir0/dir1/file creates /dir0/dir1 in order to create +// /dir0/dir1/file. // -// - The file content is copied from the lower file to the upper -// file. For symlinks this is the symlink target. For directories, -// upper directory entries are merged with lower directory entries -// so there is no need to copy any entries. +// - The file content is copied from the lower file to the upper +// file. For symlinks this is the symlink target. For directories, +// upper directory entries are merged with lower directory entries +// so there is no need to copy any entries. // -// - A subset of file attributes of the lower file are set on the -// upper file. These are the file owner, the file timestamps, -// and all non-overlay extended attributes. copyUp will fail if -// the upper filesystem does not support the setting of these -// attributes. +// - A subset of file attributes of the lower file are set on the +// upper file. These are the file owner, the file timestamps, +// and all non-overlay extended attributes. copyUp will fail if +// the upper filesystem does not support the setting of these +// attributes. // -// The file's permissions are set when the file is created and its -// size will be brought up to date when its contents are copied. -// Notably no attempt is made to bring link count up to date because -// hard links are currently not preserved across overlay filesystems. +// The file's permissions are set when the file is created and its +// size will be brought up to date when its contents are copied. +// Notably no attempt is made to bring link count up to date because +// hard links are currently not preserved across overlay filesystems. // -// - Memory mappings of the lower file are invalidated and memory -// references are transferred to the upper file. From this point on, -// memory mappings of the file will be backed by content in the upper -// filesystem. +// - Memory mappings of the lower file are invalidated and memory +// references are transferred to the upper file. From this point on, +// memory mappings of the file will be backed by content in the upper +// filesystem. // // Synchronization: // @@ -71,13 +71,13 @@ import ( // // The following operations synchronize with copyUp using copyMu: // -// - InodeOperations, i.e. to ensure that looking up a directory takes -// into account new upper filesystem directories created by copy up, -// which subsequently can be modified. +// - InodeOperations, i.e. to ensure that looking up a directory takes +// into account new upper filesystem directories created by copy up, +// which subsequently can be modified. // -// - FileOperations, i.e. to ensure that reading from a file does not -// continue using a stale, lower filesystem handle when the file is -// written to. +// - FileOperations, i.e. to ensure that reading from a file does not +// continue using a stale, lower filesystem handle when the file is +// written to. // // Lock ordering: Dirent.mu -> Inode.overlay.copyMu -> Inode.mu. // @@ -183,12 +183,12 @@ func doCopyUp(ctx context.Context, d *Dirent) error { // Returns a generic error on failure. // // Preconditions: -// * parent.Inode.overlay.upper must be non-nil. -// * next.Inode.overlay.copyMu must be locked writable. -// * next.Inode.overlay.lower must be non-nil. -// * next.Inode.overlay.lower.StableAttr.Type must be RegularFile, Directory, -// or Symlink. -// * upper filesystem must support setting file ownership and timestamps. +// - parent.Inode.overlay.upper must be non-nil. +// - next.Inode.overlay.copyMu must be locked writable. +// - next.Inode.overlay.lower must be non-nil. +// - next.Inode.overlay.lower.StableAttr.Type must be RegularFile, Directory, +// or Symlink. +// - upper filesystem must support setting file ownership and timestamps. func copyUpLocked(ctx context.Context, parent *Dirent, next *Dirent) error { // Extract the attributes of the file we wish to copy. attrs, err := next.Inode.overlay.lower.UnstableAttr(ctx) diff --git a/pkg/sentry/fs/copy_up_test.go b/pkg/sentry/fs/copy_up_test.go index e04784db2..82b7610e2 100644 --- a/pkg/sentry/fs/copy_up_test.go +++ b/pkg/sentry/fs/copy_up_test.go @@ -42,11 +42,11 @@ const ( // It creates a 64-level deep directory tree in the lower filesystem and // populates the last subdirectory with 64 files containing random content: // -// /lower -// /sudir0/.../subdir63/ -// /file0 -// ... -// /file63 +// /lower +// /sudir0/.../subdir63/ +// /file0 +// ... +// /file63 // // The files are truncated concurrently by 4 goroutines per file. // These goroutines contend with copying up all parent 64 subdirectories diff --git a/pkg/sentry/fs/dirent.go b/pkg/sentry/fs/dirent.go index f94158347..8f8fc18c0 100644 --- a/pkg/sentry/fs/dirent.go +++ b/pkg/sentry/fs/dirent.go @@ -254,13 +254,13 @@ func (d *Dirent) IsNegative() bool { // Returns (*WeakRef, true) if hashing child caused a Dirent to be unhashed. The caller must // validate the returned unhashed weak reference. Common cases: // -// * Remove: hashing a negative Dirent unhashes a positive Dirent (unimplemented). -// * Create: hashing a positive Dirent unhashes a negative Dirent. -// * Lookup: hashing any Dirent should not unhash any other Dirent. +// - Remove: hashing a negative Dirent unhashes a positive Dirent (unimplemented). +// - Create: hashing a positive Dirent unhashes a negative Dirent. +// - Lookup: hashing any Dirent should not unhash any other Dirent. // // Preconditions: -// * d.mu must be held. -// * child must be a root Dirent. +// - d.mu must be held. +// - child must be a root Dirent. func (d *Dirent) hashChild(child *Dirent) (*refs.WeakRef, bool) { if !child.IsRoot() { panic("hashChild must be a root Dirent") @@ -413,9 +413,9 @@ func (d *Dirent) descendantOf(p *Dirent) bool { // Inode.Lookup, otherwise walk will keep d.mu locked. // // Preconditions: -// * renameMu must be held for reading. -// * d.mu must be held. -// * name must must not contain "/"s. +// - renameMu must be held for reading. +// - d.mu must be held. +// - name must must not contain "/"s. func (d *Dirent) walk(ctx context.Context, root *Dirent, name string, walkMayUnlock bool) (*Dirent, error) { if !IsDir(d.Inode.StableAttr) { return nil, unix.ENOTDIR @@ -577,9 +577,9 @@ func (d *Dirent) Walk(ctx context.Context, root *Dirent, name string) (*Dirent, // exists returns true if name exists in relation to d. // // Preconditions: -// * renameMu must be held for reading. -// * d.mu must be held. -// * name must must not contain "/"s. +// - renameMu must be held for reading. +// - d.mu must be held. +// - name must must not contain "/"s. func (d *Dirent) exists(ctx context.Context, root *Dirent, name string) bool { child, err := d.walk(ctx, root, name, false /* may unlock */) if err != nil { @@ -835,11 +835,11 @@ type DirIterator interface { // // Arguments: // -// * d: the Dirent of the directory being read; required to provide "." and "..". -// * it: the directory iterator; which represents an open directory handle. -// * root: fs root; if d is equal to the root, then '..' will refer to d. -// * ctx: context provided to file systems in order to select and serialize entries. -// * offset: the current directory offset. +// - d: the Dirent of the directory being read; required to provide "." and "..". +// - it: the directory iterator; which represents an open directory handle. +// - root: fs root; if d is equal to the root, then '..' will refer to d. +// - ctx: context provided to file systems in order to select and serialize entries. +// - offset: the current directory offset. // // Returns the offset of the *next* element which was not serialized. func DirentReaddir(ctx context.Context, d *Dirent, it DirIterator, root *Dirent, dirCtx *DirCtx, offset int64) (int64, error) { @@ -1277,14 +1277,13 @@ func lockForRename(oldParent *Dirent, oldName string, newParent *Dirent, newName // Renaming between directories is a bit subtle: // - // - A concurrent cross-directory Rename may try to lock in the opposite - // order; take renameMu to prevent this from happening. - // - // - If either directory is an ancestor of the other, then a concurrent - // Remove may lock the descendant (in DecRef -> closeAll) while holding a - // lock on the ancestor; to avoid this, ensure we take locks in the same - // ancestor-to-descendant order. (Holding renameMu prevents this - // relationship from changing.) + // - A concurrent cross-directory Rename may try to lock in the opposite + // order; take renameMu to prevent this from happening. + // - If either directory is an ancestor of the other, then a concurrent + // Remove may lock the descendant (in DecRef -> closeAll) while holding a + // lock on the ancestor; to avoid this, ensure we take locks in the same + // ancestor-to-descendant order. (Holding renameMu prevents this + // relationship from changing.) // First check if newParent is a descendant of oldParent. child := newParent diff --git a/pkg/sentry/fs/file_operations.go b/pkg/sentry/fs/file_operations.go index ce47c3907..2765a705f 100644 --- a/pkg/sentry/fs/file_operations.go +++ b/pkg/sentry/fs/file_operations.go @@ -60,11 +60,11 @@ type SpliceOpts struct { // // Operations that take a *File may use only the following interfaces: // -// - File.UniqueID: Operations may only read this value. -// - File.Dirent: Operations must not take or drop a reference. -// - File.Offset(): This value is guaranteed to not change for the -// duration of the operation. -// - File.Flags(): This value may change during the operation. +// - File.UniqueID: Operations may only read this value. +// - File.Dirent: Operations must not take or drop a reference. +// - File.Offset(): This value is guaranteed to not change for the +// duration of the operation. +// - File.Flags(): This value may change during the operation. type FileOperations interface { // Release release resources held by FileOperations. Release(ctx context.Context) @@ -160,8 +160,8 @@ type FileOperations interface { // refer. // // Preconditions: - // * The AddressSpace (if any) that io refers to is activated. - // * Must only be called from a task goroutine. + // * The AddressSpace (if any) that io refers to is activated. + // * Must only be called from a task goroutine. Ioctl(ctx context.Context, file *File, io usermem.IO, args arch.SyscallArguments) (uintptr, error) } diff --git a/pkg/sentry/fs/filesystems.go b/pkg/sentry/fs/filesystems.go index d41f30bbb..cd48f703c 100644 --- a/pkg/sentry/fs/filesystems.go +++ b/pkg/sentry/fs/filesystems.go @@ -135,7 +135,7 @@ type MountSourceFlags struct { // GenericMountSourceOptions splits a string containing comma separated tokens of the // format 'key=value' or 'key' into a map of keys and values. For example: // -// data = "key0=value0,key1,key2=value2" -> map{'key0':'value0','key1':'','key2':'value2'} +// data = "key0=value0,key1,key2=value2" -> map{'key0':'value0','key1':”,'key2':'value2'} // // If data contains duplicate keys, then the last token wins. func GenericMountSourceOptions(data string) map[string]string { diff --git a/pkg/sentry/fs/fs.go b/pkg/sentry/fs/fs.go index a346c316b..af9fddf3d 100644 --- a/pkg/sentry/fs/fs.go +++ b/pkg/sentry/fs/fs.go @@ -29,23 +29,26 @@ // in the following order. // // Either: -// File.mu -// Locks in FileOperations implementations -// goto Dirent-Locks +// +// File.mu +// Locks in FileOperations implementations +// goto Dirent-Locks // // Or: -// MountNamespace.mu -// goto Dirent-Locks +// +// MountNamespace.mu +// goto Dirent-Locks // // Dirent-Locks: -// renameMu -// Dirent.dirMu -// Dirent.mu -// DirentCache.mu -// Inode.Watches.mu (see `Inotify` for other lock ordering) -// MountSource.mu -// Inode.appendMu -// Locks in InodeOperations implementations or overlayEntry +// +// renameMu +// Dirent.dirMu +// Dirent.mu +// DirentCache.mu +// Inode.Watches.mu (see `Inotify` for other lock ordering) +// MountSource.mu +// Inode.appendMu +// Locks in InodeOperations implementations or overlayEntry // // If multiple Dirent or MountSource locks must be taken, locks in the parent must be // taken before locks in their children. diff --git a/pkg/sentry/fs/fsutil/file_range_set.go b/pkg/sentry/fs/fsutil/file_range_set.go index fdaceb1db..1631e10bd 100644 --- a/pkg/sentry/fs/fsutil/file_range_set.go +++ b/pkg/sentry/fs/fsutil/file_range_set.go @@ -71,8 +71,8 @@ func (seg FileRangeIterator) FileRange() memmap.FileRange { // FileRangeOf returns the FileRange mapped by mr. // // Preconditions: -// * seg.Range().IsSupersetOf(mr). -// * mr.Length() != 0. +// - seg.Range().IsSupersetOf(mr). +// - mr.Length() != 0. func (seg FileRangeIterator) FileRangeOf(mr memmap.MappableRange) memmap.FileRange { frstart := seg.Value() + (mr.Start - seg.Start()) return memmap.FileRange{frstart, frstart + mr.Length()} @@ -92,9 +92,9 @@ func (seg FileRangeIterator) FileRangeOf(mr memmap.MappableRange) memmap.FileRan // if the error only affects offsets in optional, but not in required. // // Preconditions: -// * required.Length() > 0. -// * optional.IsSupersetOf(required). -// * required and optional must be page-aligned. +// - required.Length() > 0. +// - optional.IsSupersetOf(required). +// - required and optional must be page-aligned. func (frs *FileRangeSet) Fill(ctx context.Context, required, optional memmap.MappableRange, fileSize uint64, mf *pgalloc.MemoryFile, kind usage.MemoryKind, readAt func(ctx context.Context, dsts safemem.BlockSeq, offset uint64) (uint64, error)) error { gap := frs.LowerBoundGap(required.Start) for gap.Ok() && gap.Start() < required.End { diff --git a/pkg/sentry/fs/fsutil/fsutil.go b/pkg/sentry/fs/fsutil/fsutil.go index c9587b1d9..f97a8b2f2 100644 --- a/pkg/sentry/fs/fsutil/fsutil.go +++ b/pkg/sentry/fs/fsutil/fsutil.go @@ -15,10 +15,10 @@ // Package fsutil provides utilities for implementing fs.InodeOperations // and fs.FileOperations: // -// - For embeddable utilities, see inode.go and file.go. +// - For embeddable utilities, see inode.go and file.go. // -// - For fs.Inodes that require a page cache to be memory mapped, see -// inode_cache.go. +// - For fs.Inodes that require a page cache to be memory mapped, see +// inode_cache.go. // -// - For anon fs.Inodes, see anon.go. +// - For anon fs.Inodes, see anon.go. package fsutil diff --git a/pkg/sentry/fs/fsutil/host_file_mapper.go b/pkg/sentry/fs/fsutil/host_file_mapper.go index 37ddb1a3c..7849069da 100644 --- a/pkg/sentry/fs/fsutil/host_file_mapper.go +++ b/pkg/sentry/fs/fsutil/host_file_mapper.go @@ -88,8 +88,8 @@ func NewHostFileMapper() *HostFileMapper { // IncRefOn increments the reference count on all offsets in mr. // // Preconditions: -// * mr.Length() != 0. -// * mr.Start and mr.End must be page-aligned. +// - mr.Length() != 0. +// - mr.Start and mr.End must be page-aligned. func (f *HostFileMapper) IncRefOn(mr memmap.MappableRange) { f.refsMu.Lock() defer f.refsMu.Unlock() @@ -112,8 +112,8 @@ func (f *HostFileMapper) IncRefOn(mr memmap.MappableRange) { // DecRefOn decrements the reference count on all offsets in mr. // // Preconditions: -// * mr.Length() != 0. -// * mr.Start and mr.End must be page-aligned. +// - mr.Length() != 0. +// - mr.Start and mr.End must be page-aligned. func (f *HostFileMapper) DecRefOn(mr memmap.MappableRange) { f.refsMu.Lock() defer f.refsMu.Unlock() @@ -231,8 +231,8 @@ func (f *HostFileMapper) UnmapAll() { } // Preconditions: -// * f.mapsMu must be locked. -// * f.mappings[chunkStart] == m. +// - f.mapsMu must be locked. +// - f.mappings[chunkStart] == m. func (f *HostFileMapper) unmapAndRemoveLocked(chunkStart uint64, m mapping) { if _, _, errno := unix.Syscall(unix.SYS_MUNMAP, m.addr, chunkSize, 0); errno != 0 { // This leaks address space and is unexpected, but is otherwise diff --git a/pkg/sentry/fs/fsutil/host_mappable.go b/pkg/sentry/fs/fsutil/host_mappable.go index 8ac3738e9..d737f2906 100644 --- a/pkg/sentry/fs/fsutil/host_mappable.go +++ b/pkg/sentry/fs/fsutil/host_mappable.go @@ -30,10 +30,11 @@ import ( // CachedFileObject. // // Lock order (compare the lock order model in mm/mm.go): -// truncateMu ("fs locks") -// mu ("memmap.Mappable locks not taken by Translate") -// ("memmap.File locks") -// backingFile ("CachedFileObject locks") +// +// truncateMu ("fs locks") +// mu ("memmap.Mappable locks not taken by Translate") +// ("memmap.File locks") +// backingFile ("CachedFileObject locks") // // +stateify savable type HostMappable struct { @@ -151,10 +152,11 @@ func (h *HostMappable) DecRef(fr memmap.FileRange) { // // Truncation and writes are synchronized to prevent races where writes make the // file grow between truncation and invalidation below: -// T1: Calls SetMaskedAttributes and stalls -// T2: Appends to file causing it to grow -// T2: Writes to mapped pages and COW happens -// T1: Continues and wronly invalidates the page mapped in step above. +// +// T1: Calls SetMaskedAttributes and stalls +// T2: Appends to file causing it to grow +// T2: Writes to mapped pages and COW happens +// T1: Continues and wronly invalidates the page mapped in step above. func (h *HostMappable) Truncate(ctx context.Context, newSize int64, uattr fs.UnstableAttr) error { h.truncateMu.Lock() defer h.truncateMu.Unlock() diff --git a/pkg/sentry/fs/fsutil/inode.go b/pkg/sentry/fs/fsutil/inode.go index 06a994193..b3d974f37 100644 --- a/pkg/sentry/fs/fsutil/inode.go +++ b/pkg/sentry/fs/fsutil/inode.go @@ -507,7 +507,7 @@ func (InodeDenyWriteChecker) Check(ctx context.Context, inode *fs.Inode, p fs.Pe return fs.ContextCanAccessFile(ctx, inode, p) } -//InodeNotAllocatable can be used by Inodes that do not support Allocate(). +// InodeNotAllocatable can be used by Inodes that do not support Allocate(). type InodeNotAllocatable struct{} // Allocate implements fs.InodeOperations.Allocate. diff --git a/pkg/sentry/fs/fsutil/inode_cached.go b/pkg/sentry/fs/fsutil/inode_cached.go index 855029b84..0a83c4190 100644 --- a/pkg/sentry/fs/fsutil/inode_cached.go +++ b/pkg/sentry/fs/fsutil/inode_cached.go @@ -45,11 +45,11 @@ import ( // // CachingInodeOperations implements Mappable for the CachedFileObject: // -// - If CachedFileObject.FD returns a value >= 0 then the file descriptor -// will be memory mapped on the host. +// - If CachedFileObject.FD returns a value >= 0 then the file descriptor +// will be memory mapped on the host. // -// - Otherwise, the contents of CachedFileObject are buffered into memory -// managed by the CachingInodeOperations. +// - Otherwise, the contents of CachedFileObject are buffered into memory +// managed by the CachingInodeOperations. // // Implementations of FileOperations for a CachedFileObject must read and // write through CachingInodeOperations using Read and Write respectively. @@ -696,8 +696,8 @@ func (rw *inodeReadWriter) ReadToBlocks(dsts safemem.BlockSeq) (uint64, error) { // bytes were written. // // Preconditions: -// * rw.c.attrMu must be locked. -// * rw.c.dataMu must be locked. +// - rw.c.attrMu must be locked. +// - rw.c.dataMu must be locked. func (rw *inodeReadWriter) maybeUpdateAttrs(nwritten uint64) { // If the write ends beyond the file's previous size, it causes the // file to grow. diff --git a/pkg/sentry/fs/gofer/inode.go b/pkg/sentry/fs/gofer/inode.go index c3856094f..e0aa3bef1 100644 --- a/pkg/sentry/fs/gofer/inode.go +++ b/pkg/sentry/fs/gofer/inode.go @@ -77,9 +77,9 @@ type inodeFileState struct { // MultiDeviceKey consists of: // - // * Device: file system device from a specific gofer. - // * SecondaryDevice: unique identifier of the attach point. - // * Inode: the inode of this resource, unique per Device.= + // * Device: file system device from a specific gofer. + // * SecondaryDevice: unique identifier of the attach point. + // * Inode: the inode of this resource, unique per Device.= // // These fields combined enable consistent hashing of virtual inodes // on goferDevice. @@ -109,7 +109,7 @@ type inodeFileState struct { // inodeFileState.FD() can't return a write-only FD, but can't be changed // if writeHandlesRW is true for the same reason. // - // * There is one notable exception in recreateReadHandles(), where it dup's + // * There is one notable exception in recreateReadHandles(), where it dup's // the FD and invalidates the page cache. readHandles *handles `state:"nosave"` writeHandles *handles `state:"nosave"` diff --git a/pkg/sentry/fs/gofer/session.go b/pkg/sentry/fs/gofer/session.go index b7debeecb..89db29dab 100644 --- a/pkg/sentry/fs/gofer/session.go +++ b/pkg/sentry/fs/gofer/session.go @@ -290,10 +290,10 @@ func newInodeOperations(ctx context.Context, s *session, file contextFile, qid p // Root returns the root of a 9p mount. This mount is bound to a 9p server // based on conn. Otherwise configuration parameters are: // -// * dev: connection id -// * filesystem: the filesystem backing the mount -// * superBlockFlags: the mount flags describing general mount options -// * opts: parsed 9p mount options +// - dev: connection id +// - filesystem: the filesystem backing the mount +// - superBlockFlags: the mount flags describing general mount options +// - opts: parsed 9p mount options func Root(ctx context.Context, dev string, filesystem fs.Filesystem, superBlockFlags fs.MountSourceFlags, o opts) (*fs.Inode, error) { // The mounting EUID/EGID will be cached by this file system. This will // be used to assign ownership to files that the Gofer owns. diff --git a/pkg/sentry/fs/host/inode.go b/pkg/sentry/fs/host/inode.go index 99c37291e..3c2c98527 100644 --- a/pkg/sentry/fs/host/inode.go +++ b/pkg/sentry/fs/host/inode.go @@ -92,9 +92,9 @@ func (i *inodeFileState) ReadToBlocksAt(ctx context.Context, dsts safemem.BlockS // TODO(jamieliu): Using safemem.FromIOReader here is wasteful for two // reasons: // - // - Using preadv instead of iterated preads saves on host system calls. + // - Using preadv instead of iterated preads saves on host system calls. // - // - Host system calls can handle destination memory that would fault in + // - Host system calls can handle destination memory that would fault in // gr3 (i.e. they can accept safemem.Blocks with NeedSafecopy() == true), // so the buffering performed by FromIOReader is unnecessary. // diff --git a/pkg/sentry/fs/inode.go b/pkg/sentry/fs/inode.go index 2c6b9e9db..f280a6395 100644 --- a/pkg/sentry/fs/inode.go +++ b/pkg/sentry/fs/inode.go @@ -293,8 +293,8 @@ func (i *Inode) RemoveXattr(ctx context.Context, d *Dirent, name string) error { // requested way for reading, writing, or executing. // // CheckPermission is like Linux's fs/namei.c:inode_permission. It -// - checks file system mount flags, -// - and utilizes InodeOperations.Check to check capabilities and modes. +// - checks file system mount flags, +// - and utilizes InodeOperations.Check to check capabilities and modes. func (i *Inode) CheckPermission(ctx context.Context, p PermMask) error { // First check the outer-most mounted filesystem. if p.Write && i.MountSource.Flags.ReadOnly { diff --git a/pkg/sentry/fs/inode_operations.go b/pkg/sentry/fs/inode_operations.go index 0f8022906..6d282e829 100644 --- a/pkg/sentry/fs/inode_operations.go +++ b/pkg/sentry/fs/inode_operations.go @@ -64,16 +64,16 @@ type InodeOperations interface { // // Lookup may return one of: // - // * A nil Dirent and a non-nil error. If the reason that Lookup failed + // * A nil Dirent and a non-nil error. If the reason that Lookup failed // was because the name does not exist under Inode, then must return // linuxerr.ENOENT. // - // * If name does not exist under dir and the file system wishes this + // * If name does not exist under dir and the file system wishes this // fact to be cached, a non-nil Dirent containing a nil Inode and a // nil error. This is a negative Dirent and must have exactly one // reference (at-construction reference). // - // * If name does exist under this dir, a non-nil Dirent containing a + // * If name does exist under this dir, a non-nil Dirent containing a // non-nil Inode, and a nil error. File systems that take extra // references on this Dirent should implement DirentOperations. Lookup(ctx context.Context, dir *Inode, name string) (*Dirent, error) @@ -82,9 +82,9 @@ type InodeOperations interface { // whose Dirent backs the new Inode. Implementations must ensure that // name does not already exist. Create may return one of: // - // * A nil File and a non-nil error. + // * A nil File and a non-nil error. // - // * A non-nil File and a nil error. File.Dirent will be a new Dirent, + // * A non-nil File and a nil error. File.Dirent will be a new Dirent, // with a single reference held by File. File systems that take extra // references on this Dirent should implement DirentOperations. // diff --git a/pkg/sentry/fs/inotify.go b/pkg/sentry/fs/inotify.go index 1b8a9a5fe..6cd94db3f 100644 --- a/pkg/sentry/fs/inotify.go +++ b/pkg/sentry/fs/inotify.go @@ -34,7 +34,8 @@ import ( // inotify_init1(2). Inotify implements the FileOperations interface. // // Lock ordering: -// Inotify.mu -> Inode.Watches.mu -> Watch.mu -> Inotify.evMu +// +// Inotify.mu -> Inode.Watches.mu -> Watch.mu -> Inotify.evMu // // +stateify savable type Inotify struct { diff --git a/pkg/sentry/fs/lock/lock.go b/pkg/sentry/fs/lock/lock.go index 43e20b9c6..6b522142e 100644 --- a/pkg/sentry/fs/lock/lock.go +++ b/pkg/sentry/fs/lock/lock.go @@ -39,11 +39,11 @@ // In special cases, a read lock may be upgraded to a write lock and a write lock // can be downgraded to a read lock. This can only happen if: // -// * read lock upgrade to write lock: There can be only one reader and the reader -// must be the same as the requested write lock holder. +// - read lock upgrade to write lock: There can be only one reader and the reader +// must be the same as the requested write lock holder. // -// * write lock downgrade to read lock: The writer must be the same as the requested -// read lock holder. +// - write lock downgrade to read lock: The writer must be the same as the requested +// read lock holder. // // UnlockRegion always succeeds. If LockRegion fails the caller should normally // interpret this as "try again later". diff --git a/pkg/sentry/fs/mounts_test.go b/pkg/sentry/fs/mounts_test.go index 975d6cbc9..b825b786a 100644 --- a/pkg/sentry/fs/mounts_test.go +++ b/pkg/sentry/fs/mounts_test.go @@ -25,9 +25,10 @@ import ( ) // Creates a new MountNamespace with filesystem: -// / (root dir) -// |-foo (dir) -// |-bar (file) +// +// / (root dir) +// |-foo (dir) +// |-bar (file) func createMountNamespace(ctx context.Context) (*fs.MountNamespace, error) { perms := fs.FilePermsFromMode(0777) m := fs.NewPseudoMountSource(ctx) diff --git a/pkg/sentry/fs/offset.go b/pkg/sentry/fs/offset.go index 3a8c97d8f..b7c97004b 100644 --- a/pkg/sentry/fs/offset.go +++ b/pkg/sentry/fs/offset.go @@ -35,9 +35,9 @@ func OffsetPageEnd(offset int64) uint64 { // so that the read does not overflow an int64 nor size. // // Parameters: -// - offset: the starting offset of the read. -// - length: the number of bytes to read. -// - size: the size of the file. +// - offset: the starting offset of the read. +// - length: the number of bytes to read. +// - size: the size of the file. // // Postconditions: The returned offset is >= offset. func ReadEndOffset(offset int64, length int64, size int64) int64 { @@ -56,8 +56,8 @@ func ReadEndOffset(offset int64, length int64, size int64) int64 { // so that the write does not overflow an int64. // // Parameters: -// - offset: the starting offset of the write. -// - length: the number of bytes to write. +// - offset: the starting offset of the write. +// - length: the number of bytes to write. // // Postconditions: The returned offset is >= offset. func WriteEndOffset(offset int64, length int64) int64 { diff --git a/pkg/sentry/fs/overlay.go b/pkg/sentry/fs/overlay.go index 7e72e47b5..9090263eb 100644 --- a/pkg/sentry/fs/overlay.go +++ b/pkg/sentry/fs/overlay.go @@ -39,21 +39,21 @@ import ( // // Known deficiencies: // -// - The device number of two files under the same overlay mount point may be +// - The device number of two files under the same overlay mount point may be // different. This can happen if a file is found in the lower filesystem (takes // the lower filesystem device) and another file is created in the upper // filesystem (takes the upper filesystem device). This may appear odd but // should not break applications. // -// - Registered events on files (i.e. for notification of read/write readiness) +// - Registered events on files (i.e. for notification of read/write readiness) // are not copied across copy up. This is fine in the common case of files that // do not block. For files that do block, like pipes and sockets, copy up is not // supported. // -// - Hardlinks in a lower filesystem are broken by copy up. For this reason, no +// - Hardlinks in a lower filesystem are broken by copy up. For this reason, no // attempt is made to preserve link count across copy up. // -// - The maximum length of an extended attribute name is the same as the maximum +// - The maximum length of an extended attribute name is the same as the maximum // length of a file path in Linux (XATTR_NAME_MAX == NAME_MAX). This means that // whiteout attributes, if set directly on the host, are limited additionally by // the extra whiteout prefix length (file paths must be strictly shorter than @@ -86,12 +86,12 @@ func isXattrOverlay(name string) bool { // NewOverlayRoot produces the root of an overlay. // // Preconditions: -// * upper and lower must be non-nil. -// * upper must not be an overlay. -// * lower should not expose character devices, pipes, or sockets, because -// copying up these types of files is not supported. -// * lower must not require that file objects be revalidated. -// * lower must not have dynamic file/directory content. +// - upper and lower must be non-nil. +// - upper must not be an overlay. +// - lower should not expose character devices, pipes, or sockets, because +// copying up these types of files is not supported. +// - lower must not require that file objects be revalidated. +// - lower must not have dynamic file/directory content. func NewOverlayRoot(ctx context.Context, upper *Inode, lower *Inode, flags MountSourceFlags) (*Inode, error) { if !IsDir(upper.StableAttr) { return nil, fmt.Errorf("upper Inode is a %v, not a directory", upper.StableAttr.Type) @@ -116,11 +116,11 @@ func NewOverlayRoot(ctx context.Context, upper *Inode, lower *Inode, flags Mount // NewOverlayRootFile produces the root of an overlay that points to a file. // // Preconditions: -// * lower must be non-nil. -// * lower should not expose character devices, pipes, or sockets, because -// copying up these types of files is not supported. Neither it can be a dir. -// * lower must not require that file objects be revalidated. -// * lower must not have dynamic file/directory content. +// - lower must be non-nil. +// - lower should not expose character devices, pipes, or sockets, because +// copying up these types of files is not supported. Neither it can be a dir. +// - lower must not require that file objects be revalidated. +// - lower must not have dynamic file/directory content. func NewOverlayRootFile(ctx context.Context, upperMS *MountSource, lower *Inode, flags MountSourceFlags) (*Inode, error) { if !IsRegular(lower.StableAttr) { return nil, fmt.Errorf("lower Inode is not a regular file") diff --git a/pkg/sentry/fs/proc/version.go b/pkg/sentry/fs/proc/version.go index 35e258ff6..cc22f1f9c 100644 --- a/pkg/sentry/fs/proc/version.go +++ b/pkg/sentry/fs/proc/version.go @@ -57,12 +57,12 @@ func (v *versionData) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) // (COMPILER_VERSION) VERSION" // // where: - // - SYSNAME, RELEASE, and VERSION are the same as returned by + // - SYSNAME, RELEASE, and VERSION are the same as returned by // sys_utsname - // - COMPILE_USER is the user that build the kernel - // - COMPILE_HOST is the hostname of the machine on which the kernel + // - COMPILE_USER is the user that build the kernel + // - COMPILE_HOST is the hostname of the machine on which the kernel // was built - // - COMPILER_VERSION is the version reported by the building compiler + // - COMPILER_VERSION is the version reported by the building compiler // // Since we don't really want to expose build information to // applications, those fields are omitted. diff --git a/pkg/sentry/fs/tty/line_discipline.go b/pkg/sentry/fs/tty/line_discipline.go index f2c9e9668..65f972530 100644 --- a/pkg/sentry/fs/tty/line_discipline.go +++ b/pkg/sentry/fs/tty/line_discipline.go @@ -48,8 +48,8 @@ const ( // modify control characters (e.g. Ctrl-C for SIGINT), etc. The following man // pages are good resources for how to affect the line discipline: // -// * termios(3) -// * tty_ioctl(4) +// - termios(3) +// - tty_ioctl(4) // // This file corresponds most closely to drivers/tty/n_tty.c. // @@ -60,22 +60,25 @@ const ( // discipline reads the bytes, modifies them or takes special action if // required, and enqueues them to be read by the other end of the pty: // -// input from terminal +-------------+ input to process (e.g. bash) -// +------------------------>| input queue |---------------------------+ -// | (inputQueueWrite) +-------------+ (inputQueueRead) | -// | | -// | v +// input from terminal +-------------+ input to process (e.g. bash) +// +------------------------>| input queue |---------------------------+ +// | (inputQueueWrite) +-------------+ (inputQueueRead) | +// | | +// | v +// // masterFD replicaFD -// ^ | -// | | -// | output to terminal +--------------+ output from process | -// +------------------------| output queue |<--------------------------+ -// (outputQueueRead) +--------------+ (outputQueueWrite) +// +// ^ | +// | | +// | output to terminal +--------------+ output from process | +// +------------------------| output queue |<--------------------------+ +// (outputQueueRead) +--------------+ (outputQueueWrite) // // Lock order: -// termiosMu -// inQueue.mu -// outQueue.mu +// +// termiosMu +// inQueue.mu +// outQueue.mu // // +stateify savable type lineDiscipline struct { @@ -261,8 +264,8 @@ type outputQueueTransformer struct{} // drivers/tty/n_tty.c:do_output_char for an analogous kernel function. // // Preconditions: -// * l.termiosMu must be held for reading. -// * q.mu must be held. +// - l.termiosMu must be held for reading. +// - q.mu must be held. func (*outputQueueTransformer) transform(l *lineDiscipline, q *queue, buf []byte) int { // transformOutput is effectively always in noncanonical mode, as the // master termios never has ICANON set. @@ -338,8 +341,8 @@ type inputQueueTransformer struct{} // function. // // Preconditions: -// * l.termiosMu must be held for reading. -// * q.mu must be held. +// - l.termiosMu must be held for reading. +// - q.mu must be held. func (*inputQueueTransformer) transform(l *lineDiscipline, q *queue, buf []byte) int { // If there's a line waiting to be read in canonical mode, don't write // anything else to the read buffer. @@ -422,8 +425,8 @@ func (*inputQueueTransformer) transform(l *lineDiscipline, q *queue, buf []byte) // we find a terminating character. Signal/echo processing still occurs. // // Precondition: -// * l.termiosMu must be held for reading. -// * q.mu must be held. +// - l.termiosMu must be held for reading. +// - q.mu must be held. func (l *lineDiscipline) shouldDiscard(q *queue, cBytes []byte) bool { return l.termios.LEnabled(linux.ICANON) && len(q.readBuf)+len(cBytes) >= canonMaxBytes && !l.termios.IsTerminating(cBytes) } diff --git a/pkg/sentry/fs/tty/queue.go b/pkg/sentry/fs/tty/queue.go index 25d3c887e..73d40a982 100644 --- a/pkg/sentry/fs/tty/queue.go +++ b/pkg/sentry/fs/tty/queue.go @@ -200,8 +200,8 @@ func (q *queue) writeBytes(b []byte, l *lineDiscipline) { // buffer. // // Preconditions: -// * l.termiosMu must be held for reading. -// * q.mu must be locked. +// - l.termiosMu must be held for reading. +// - q.mu must be locked. func (q *queue) pushWaitBufLocked(l *lineDiscipline) int { if q.waitBufLen == 0 { return 0 diff --git a/pkg/sentry/fs/user/user.go b/pkg/sentry/fs/user/user.go index 1f8684dc6..9847c5b82 100644 --- a/pkg/sentry/fs/user/user.go +++ b/pkg/sentry/fs/user/user.go @@ -206,13 +206,13 @@ func findHomeInPasswd(uid uint32, passwd io.Reader, defaultHome string) (string, // /etc/passwd contains one line for each user account, with seven // fields delimited by colons (“:”). These fields are: // - // - login name - // - optional encrypted password - // - numerical user ID - // - numerical group ID - // - user name or comment field - // - user home directory - // - optional user command interpreter + // - login name + // - optional encrypted password + // - numerical user ID + // - numerical group ID + // - user name or comment field + // - user home directory + // - optional user command interpreter parts := strings.Split(line, ":") found := false diff --git a/pkg/sentry/fsimpl/cgroupfs/cgroupfs.go b/pkg/sentry/fsimpl/cgroupfs/cgroupfs.go index d65c1fd49..addff8d66 100644 --- a/pkg/sentry/fsimpl/cgroupfs/cgroupfs.go +++ b/pkg/sentry/fsimpl/cgroupfs/cgroupfs.go @@ -48,12 +48,12 @@ // // Lock order: // -// kernel.CgroupRegistry.mu -// kernfs.filesystem.mu -// kernel.TaskSet.mu -// kernel.Task.mu -// cgroupfs.filesystem.tasksMu. -// cgroupfs.dir.OrderedChildren.mu +// kernel.CgroupRegistry.mu +// kernfs.filesystem.mu +// kernel.TaskSet.mu +// kernel.Task.mu +// cgroupfs.filesystem.tasksMu. +// cgroupfs.dir.OrderedChildren.mu package cgroupfs import ( diff --git a/pkg/sentry/fsimpl/cgroupfs/pids.go b/pkg/sentry/fsimpl/cgroupfs/pids.go index 37a5defd7..2e2ace7ff 100644 --- a/pkg/sentry/fsimpl/cgroupfs/pids.go +++ b/pkg/sentry/fsimpl/cgroupfs/pids.go @@ -43,14 +43,14 @@ const pidLimitUnlimited = pidMaxLimit + 1 // // A task can charge a PIDs cgroup in two ways: // -// 1) A task created prior to the PIDs controller being enabled, or created -// through kernel.CreateProcess (i.e. not from userspace) directly add -// committed charges via the Enter method. +// 1. A task created prior to the PIDs controller being enabled, or created +// through kernel.CreateProcess (i.e. not from userspace) directly add +// committed charges via the Enter method. // -// 2) A task created through Task.Clone (i.e. userspace fork/clone) first add a -// pending charge through the Charge method. This is a temporary reservation -// which ensures the cgroup has enough space to allow the task to start. Once -// the task startup succeeds, it calls Enter and consumes the reservation. +// 2. A task created through Task.Clone (i.e. userspace fork/clone) first add a +// pending charge through the Charge method. This is a temporary reservation +// which ensures the cgroup has enough space to allow the task to start. Once +// the task startup succeeds, it calls Enter and consumes the reservation. // // +stateify savable type pidsController struct { diff --git a/pkg/sentry/fsimpl/devpts/line_discipline.go b/pkg/sentry/fsimpl/devpts/line_discipline.go index 609623f9f..4b0f3fd3b 100644 --- a/pkg/sentry/fsimpl/devpts/line_discipline.go +++ b/pkg/sentry/fsimpl/devpts/line_discipline.go @@ -46,8 +46,8 @@ const ( // modify control characters (e.g. Ctrl-C for SIGINT), etc. The following man // pages are good resources for how to affect the line discipline: // -// * termios(3) -// * tty_ioctl(4) +// - termios(3) +// - tty_ioctl(4) // // This file corresponds most closely to drivers/tty/n_tty.c. // @@ -58,26 +58,29 @@ const ( // discipline reads the bytes, modifies them or takes special action if // required, and enqueues them to be read by the other end of the pty: // -// input from terminal +-------------+ input to process (e.g. bash) -// +------------------------>| input queue |---------------------------+ -// | (inputQueueWrite) +-------------+ (inputQueueRead) | -// | | -// | v +// input from terminal +-------------+ input to process (e.g. bash) +// +------------------------>| input queue |---------------------------+ +// | (inputQueueWrite) +-------------+ (inputQueueRead) | +// | | +// | v +// // masterFD replicaFD -// ^ | -// | | -// | output to terminal +--------------+ output from process | -// +------------------------| output queue |<--------------------------+ -// (outputQueueRead) +--------------+ (outputQueueWrite) +// +// ^ | +// | | +// | output to terminal +--------------+ output from process | +// +------------------------| output queue |<--------------------------+ +// (outputQueueRead) +--------------+ (outputQueueWrite) // // There is special handling for the ECHO option, where bytes written to the // input queue are also output back to the terminal by being written to // l.outQueue by the input queue transformer. // // Lock order: -// termiosMu -// inQueue.mu -// outQueue.mu +// +// termiosMu +// inQueue.mu +// outQueue.mu // // +stateify savable type lineDiscipline struct { @@ -277,8 +280,8 @@ type outputQueueTransformer struct{} // drivers/tty/n_tty.c:do_output_char for an analogous kernel function. // // Preconditions: -// * l.termiosMu must be held for reading. -// * q.mu must be held. +// - l.termiosMu must be held for reading. +// - q.mu must be held. func (*outputQueueTransformer) transform(l *lineDiscipline, q *queue, buf []byte) (int, bool) { // transformOutput is effectively always in noncanonical mode, as the // master termios never has ICANON set. @@ -356,8 +359,8 @@ type inputQueueTransformer struct{} // echoed, in which case we need to notify readers. // // Preconditions: -// * l.termiosMu must be held for reading. -// * q.mu must be held. +// - l.termiosMu must be held for reading. +// - q.mu must be held. func (*inputQueueTransformer) transform(l *lineDiscipline, q *queue, buf []byte) (int, bool) { // If there's a line waiting to be read in canonical mode, don't write // anything else to the read buffer. @@ -441,8 +444,8 @@ func (*inputQueueTransformer) transform(l *lineDiscipline, q *queue, buf []byte) // we find a terminating character. Signal/echo processing still occurs. // // Precondition: -// * l.termiosMu must be held for reading. -// * q.mu must be held. +// - l.termiosMu must be held for reading. +// - q.mu must be held. func (l *lineDiscipline) shouldDiscard(q *queue, cBytes []byte) bool { return l.termios.LEnabled(linux.ICANON) && len(q.readBuf)+len(cBytes) >= canonMaxBytes && !l.termios.IsTerminating(cBytes) } diff --git a/pkg/sentry/fsimpl/devpts/queue.go b/pkg/sentry/fsimpl/devpts/queue.go index 85aeefa43..01119a673 100644 --- a/pkg/sentry/fsimpl/devpts/queue.go +++ b/pkg/sentry/fsimpl/devpts/queue.go @@ -99,10 +99,10 @@ func (q *queue) readableSize(t *kernel.Task, io usermem.IO, args arch.SyscallArg } // read reads from q to userspace. It returns: -// - The number of bytes read -// - Whether the read caused more readable data to become available (whether -// data was pushed from the wait buffer to the read buffer). -// - Whether any data was echoed back (need to notify readers). +// - The number of bytes read +// - Whether the read caused more readable data to become available (whether +// data was pushed from the wait buffer to the read buffer). +// - Whether any data was echoed back (need to notify readers). // // Preconditions: l.termiosMu must be held for reading. func (q *queue) read(ctx context.Context, dst usermem.IOSequence, l *lineDiscipline) (int64, bool, bool, error) { @@ -204,8 +204,8 @@ func (q *queue) writeBytes(b []byte, l *lineDiscipline) bool { // The returned boolean indicates whether any data was echoed back. // // Preconditions: -// * l.termiosMu must be held for reading. -// * q.mu must be locked. +// - l.termiosMu must be held for reading. +// - q.mu must be locked. func (q *queue) pushWaitBufLocked(l *lineDiscipline) (int, bool) { if q.waitBufLen == 0 { return 0, false diff --git a/pkg/sentry/fsimpl/fuse/connection.go b/pkg/sentry/fsimpl/fuse/connection.go index 240fdf5aa..b9990afa6 100644 --- a/pkg/sentry/fsimpl/fuse/connection.go +++ b/pkg/sentry/fsimpl/fuse/connection.go @@ -41,9 +41,9 @@ const ( // connection is the struct by which the sentry communicates with the FUSE server daemon. // // Lock order: -// - conn.fd.mu -// - conn.mu -// - conn.asyncMu +// - conn.fd.mu +// - conn.mu +// - conn.asyncMu // // +stateify savable type connection struct { @@ -57,20 +57,20 @@ type connection struct { // We target FUSE 7.23. // The following FUSE_INIT flags are currently unsupported by this implementation: - // - FUSE_EXPORT_SUPPORT - // - FUSE_POSIX_LOCKS: requires POSIX locks - // - FUSE_FLOCK_LOCKS: requires POSIX locks - // - FUSE_AUTO_INVAL_DATA: requires page caching eviction - // - FUSE_DO_READDIRPLUS/FUSE_READDIRPLUS_AUTO: requires FUSE_READDIRPLUS implementation - // - FUSE_ASYNC_DIO - // - FUSE_PARALLEL_DIROPS (7.25) - // - FUSE_HANDLE_KILLPRIV (7.26) - // - FUSE_POSIX_ACL: affects defaultPermissions, posixACL, xattr handler (7.26) - // - FUSE_ABORT_ERROR (7.27) - // - FUSE_CACHE_SYMLINKS (7.28) - // - FUSE_NO_OPENDIR_SUPPORT (7.29) - // - FUSE_EXPLICIT_INVAL_DATA: requires page caching eviction (7.30) - // - FUSE_MAP_ALIGNMENT (7.31) + // - FUSE_EXPORT_SUPPORT + // - FUSE_POSIX_LOCKS: requires POSIX locks + // - FUSE_FLOCK_LOCKS: requires POSIX locks + // - FUSE_AUTO_INVAL_DATA: requires page caching eviction + // - FUSE_DO_READDIRPLUS/FUSE_READDIRPLUS_AUTO: requires FUSE_READDIRPLUS implementation + // - FUSE_ASYNC_DIO + // - FUSE_PARALLEL_DIROPS (7.25) + // - FUSE_HANDLE_KILLPRIV (7.26) + // - FUSE_POSIX_ACL: affects defaultPermissions, posixACL, xattr handler (7.26) + // - FUSE_ABORT_ERROR (7.27) + // - FUSE_CACHE_SYMLINKS (7.28) + // - FUSE_NO_OPENDIR_SUPPORT (7.29) + // - FUSE_EXPLICIT_INVAL_DATA: requires page caching eviction (7.30) + // - FUSE_MAP_ALIGNMENT (7.31) // initialized after receiving FUSE_INIT reply. // Until it's set, suspend sending FUSE requests. @@ -110,9 +110,9 @@ type connection struct { // Terminology note: // - // - `asyncNumMax` is the `MaxBackground` in the FUSE_INIT_IN struct. + // - `asyncNumMax` is the `MaxBackground` in the FUSE_INIT_IN struct. // - // - `asyncCongestionThreshold` is the `CongestionThreshold` in the FUSE_INIT_IN struct. + // - `asyncCongestionThreshold` is the `CongestionThreshold` in the FUSE_INIT_IN struct. // // We call the "background" requests in unix term as async requests. // The "async requests" in unix term is our async requests that expect a reply, diff --git a/pkg/sentry/fsimpl/fuse/fusefs.go b/pkg/sentry/fsimpl/fuse/fusefs.go index 2ec5f6760..8ce53b704 100644 --- a/pkg/sentry/fsimpl/fuse/fusefs.go +++ b/pkg/sentry/fsimpl/fuse/fusefs.go @@ -761,9 +761,9 @@ func (i *inode) getAttr(ctx context.Context, fs *vfs.Filesystem, opts vfs.StatOp attributeVersion := i.fs.conn.attributeVersion.Load() // TODO(gvisor.dev/issue/3679): send the request only if - // - invalid local cache for fields specified in the opts.Mask - // - forced update - // - i.attributeTime expired + // - invalid local cache for fields specified in the opts.Mask + // - forced update + // - i.attributeTime expired // If local cache is still valid, return local cache. // Currently we always send a request, // and we always set the metadata with the new result, diff --git a/pkg/sentry/fsimpl/gofer/directory.go b/pkg/sentry/fsimpl/gofer/directory.go index 77f18dcfd..0b746602b 100644 --- a/pkg/sentry/fsimpl/gofer/directory.go +++ b/pkg/sentry/fsimpl/gofer/directory.go @@ -37,10 +37,10 @@ func (d *dentry) isDir() bool { } // Preconditions: -// - filesystem.renameMu must be locked. -// - d.dirMu must be locked. -// - d.isDir(). -// - child must be a newly-created dentry that has never had a parent. +// - filesystem.renameMu must be locked. +// - d.dirMu must be locked. +// - d.isDir(). +// - child must be a newly-created dentry that has never had a parent. func (d *dentry) insertCreatedChildLocked(ctx context.Context, childIno *lisafs.Inode, childName string, updateChild func(child *dentry), ds **[]*dentry) error { child, err := d.fs.newDentryLisa(ctx, childIno) if err != nil { @@ -56,10 +56,10 @@ func (d *dentry) insertCreatedChildLocked(ctx context.Context, childIno *lisafs. } // Preconditions: -// * filesystem.renameMu must be locked. -// * d.dirMu must be locked. -// * d.isDir(). -// * child must be a newly-created dentry that has never had a parent. +// - filesystem.renameMu must be locked. +// - d.dirMu must be locked. +// - d.isDir(). +// - child must be a newly-created dentry that has never had a parent. func (d *dentry) cacheNewChildLocked(child *dentry, name string) { d.IncRef() // reference held by child on its parent child.parent = d @@ -71,8 +71,8 @@ func (d *dentry) cacheNewChildLocked(child *dentry, name string) { } // Preconditions: -// * d.dirMu must be locked. -// * d.isDir(). +// - d.dirMu must be locked. +// - d.isDir(). func (d *dentry) cacheNegativeLookupLocked(name string) { // Don't cache negative lookups if InteropModeShared is in effect (since // this makes remote lookup unavoidable), or if d.isSynthetic() (in which @@ -106,9 +106,9 @@ type createSyntheticOpts struct { // in d. // // Preconditions: -// * d.dirMu must be locked. -// * d.isDir(). -// * d does not already contain a child with the given name. +// - d.dirMu must be locked. +// - d.isDir(). +// - d does not already contain a child with the given name. func (d *dentry) createSyntheticChildLocked(opts *createSyntheticOpts) { now := d.fs.clock.Now().Nanoseconds() child := &dentry{ @@ -189,8 +189,8 @@ func (fd *directoryFD) IterDirents(ctx context.Context, cb vfs.IterDirentsCallba } // Preconditions: -// * d.isDir(). -// * There exists at least one directoryFD representing d. +// - d.isDir(). +// - There exists at least one directoryFD representing d. func (d *dentry) getDirents(ctx context.Context) ([]vfs.Dirent, error) { // NOTE(b/135560623): 9P2000.L's readdir does not specify behavior in the // presence of concurrent mutation of an iterated directory, so diff --git a/pkg/sentry/fsimpl/gofer/filesystem.go b/pkg/sentry/fsimpl/gofer/filesystem.go index fff046965..fcbe5962e 100644 --- a/pkg/sentry/fsimpl/gofer/filesystem.go +++ b/pkg/sentry/fsimpl/gofer/filesystem.go @@ -199,11 +199,11 @@ func (fs *filesystem) renameMuUnlockAndCheckCaching(ctx context.Context, ds **[] // to *ds. // // Preconditions: -// * fs.renameMu must be locked. -// * d.dirMu must be locked. -// * !rp.Done(). -// * If !d.cachedMetadataAuthoritative(), then d and all children that are -// part of rp must have been revalidated. +// - fs.renameMu must be locked. +// - d.dirMu must be locked. +// - !rp.Done(). +// - If !d.cachedMetadataAuthoritative(), then d and all children that are +// part of rp must have been revalidated. func (fs *filesystem) stepLocked(ctx context.Context, rp *vfs.ResolvingPath, d *dentry, mayFollowSymlinks bool, ds **[]*dentry) (*dentry, bool, error) { if !d.isDir() { return nil, false, linuxerr.ENOTDIR @@ -257,11 +257,11 @@ func (fs *filesystem) stepLocked(ctx context.Context, rp *vfs.ResolvingPath, d * } // Preconditions: -// * fs.opts.lisaEnabled. -// * fs.renameMu must be locked. -// * parent.dirMu must be locked. -// * parent.isDir(). -// * parent and the dentry at name have been revalidated. +// - fs.opts.lisaEnabled. +// - fs.renameMu must be locked. +// - parent.dirMu must be locked. +// - parent.isDir(). +// - parent and the dentry at name have been revalidated. func (fs *filesystem) getChildAndWalkPathLocked(ctx context.Context, parent *dentry, rp *vfs.ResolvingPath, ds **[]*dentry) (*dentry, error) { // Note that pit is a copy of the iterator that does not affect rp. pit := rp.Pit() @@ -353,11 +353,11 @@ func (fs *filesystem) getChildAndWalkPathLocked(ctx context.Context, parent *den // given name. Returns ENOENT if the child doesn't exist. // // Preconditions: -// * fs.renameMu must be locked. -// * parent.dirMu must be locked. -// * parent.isDir(). -// * name is not "." or "..". -// * parent and the dentry at name have been revalidated. +// - fs.renameMu must be locked. +// - parent.dirMu must be locked. +// - parent.isDir(). +// - name is not "." or "..". +// - parent and the dentry at name have been revalidated. func (fs *filesystem) getChildLocked(ctx context.Context, parent *dentry, name string, ds **[]*dentry) (*dentry, error) { if len(name) > MaxFilenameLen { return nil, linuxerr.ENAMETOOLONG @@ -410,10 +410,10 @@ func (fs *filesystem) getChildLocked(ctx context.Context, parent *dentry, name s // is searchable by the provider of rp. // // Preconditions: -// * fs.renameMu must be locked. -// * !rp.Done(). -// * If !d.cachedMetadataAuthoritative(), then d's cached metadata must be up -// to date. +// - fs.renameMu must be locked. +// - !rp.Done(). +// - If !d.cachedMetadataAuthoritative(), then d's cached metadata must be up +// to date. func (fs *filesystem) walkParentDirLocked(ctx context.Context, rp *vfs.ResolvingPath, d *dentry, ds **[]*dentry) (*dentry, error) { if err := fs.revalidateParentDir(ctx, rp, d, ds); err != nil { return nil, err @@ -471,8 +471,8 @@ func (fs *filesystem) resolveLocked(ctx context.Context, rp *vfs.ResolvingPath, // createInSyntheticDir (if the parent directory is synthetic) to do so. // // Preconditions: -// * !rp.Done(). -// * For the final path component in rp, !rp.ShouldFollowSymlink(). +// - !rp.Done(). +// - For the final path component in rp, !rp.ShouldFollowSymlink(). func (fs *filesystem) doCreateAt(ctx context.Context, rp *vfs.ResolvingPath, dir bool, createInRemoteDir func(parent *dentry, name string, ds **[]*dentry) error, createInSyntheticDir func(parent *dentry, name string) error) error { var ds *[]*dentry fs.renameMu.RLock() @@ -1277,9 +1277,9 @@ retry: } // Preconditions: -// * d.fs.renameMu must be locked. -// * d.dirMu must be locked. -// * !d.isSynthetic(). +// - d.fs.renameMu must be locked. +// - d.dirMu must be locked. +// - !d.isSynthetic(). func (d *dentry) createAndOpenChildLocked(ctx context.Context, rp *vfs.ResolvingPath, opts *vfs.OpenOptions, ds **[]*dentry) (*vfs.FileDescription, error) { if err := d.checkPermissions(rp.Credentials(), vfs.MayWrite); err != nil { return nil, err diff --git a/pkg/sentry/fsimpl/gofer/gofer.go b/pkg/sentry/fsimpl/gofer/gofer.go index cb7fbddd3..6882794ca 100644 --- a/pkg/sentry/fsimpl/gofer/gofer.go +++ b/pkg/sentry/fsimpl/gofer/gofer.go @@ -16,21 +16,22 @@ // server, interchangably referred to as "gofers" throughout this package. // // Lock order: -// regularFileFD/directoryFD.mu -// filesystem.renameMu -// dentry.cachingMu -// filesystem.cacheMu -// dentry.dirMu -// filesystem.syncMu -// dentry.metadataMu -// *** "memmap.Mappable locks" below this point -// dentry.mapsMu -// *** "memmap.Mappable locks taken by Translate" below this point -// dentry.handleMu -// dentry.dataMu -// filesystem.inoMu -// specialFileFD.mu -// specialFileFD.bufMu +// +// regularFileFD/directoryFD.mu +// filesystem.renameMu +// dentry.cachingMu +// filesystem.cacheMu +// dentry.dirMu +// filesystem.syncMu +// dentry.metadataMu +// *** "memmap.Mappable locks" below this point +// dentry.mapsMu +// *** "memmap.Mappable locks taken by Translate" below this point +// dentry.handleMu +// dentry.dataMu +// filesystem.inoMu +// specialFileFD.mu +// specialFileFD.bufMu // // Locking dentry.dirMu and dentry.metadataMu in multiple dentries requires that // either ancestor dentries are locked before descendant dentries, or that @@ -136,14 +137,14 @@ type filesystem struct { // renameMu serves two purposes: // - // - It synchronizes path resolution with renaming initiated by this - // client. + // - It synchronizes path resolution with renaming initiated by this + // client. // - // - It is held by path resolution to ensure that reachable dentries remain - // valid. A dentry is reachable by path resolution if it has a non-zero - // reference count (such that it is usable as vfs.ResolvingPath.Start() or - // is reachable from its children), or if it is a child dentry (such that - // it is reachable from its parent). + // - It is held by path resolution to ensure that reachable dentries remain + // valid. A dentry is reachable by path resolution if it has a non-zero + // reference count (such that it is usable as vfs.ResolvingPath.Start() or + // is reachable from its children), or if it is a child dentry (such that + // it is reachable from its parent). renameMu sync.RWMutex `state:"nosave"` // cachedDentries contains all dentries with 0 references. (Due to race @@ -242,47 +243,47 @@ const ( // InteropModeExclusive is appropriate when the filesystem client is the // only user of the remote filesystem. // - // - The client may cache arbitrary filesystem state (file data, metadata, - // filesystem structure, etc.). + // - The client may cache arbitrary filesystem state (file data, metadata, + // filesystem structure, etc.). // - // - Client changes to filesystem state may be sent to the remote - // filesystem asynchronously, except when server permission checks are - // necessary. + // - Client changes to filesystem state may be sent to the remote + // filesystem asynchronously, except when server permission checks are + // necessary. // - // - File timestamps are based on client clocks. This ensures that users of - // the client observe timestamps that are coherent with their own clocks - // and consistent with Linux's semantics (in particular, it is not always - // possible for clients to set arbitrary atimes and mtimes depending on the - // remote filesystem implementation, and never possible for clients to set - // arbitrary ctimes.) + // - File timestamps are based on client clocks. This ensures that users of + // the client observe timestamps that are coherent with their own clocks + // and consistent with Linux's semantics (in particular, it is not always + // possible for clients to set arbitrary atimes and mtimes depending on the + // remote filesystem implementation, and never possible for clients to set + // arbitrary ctimes.) InteropModeExclusive InteropMode = iota // InteropModeWritethrough is appropriate when there are read-only users of // the remote filesystem that expect to observe changes made by the // filesystem client. // - // - The client may cache arbitrary filesystem state. + // - The client may cache arbitrary filesystem state. // - // - Client changes to filesystem state must be sent to the remote - // filesystem synchronously. + // - Client changes to filesystem state must be sent to the remote + // filesystem synchronously. // - // - File timestamps are based on client clocks. As a corollary, access - // timestamp changes from other remote filesystem users will not be visible - // to the client. + // - File timestamps are based on client clocks. As a corollary, access + // timestamp changes from other remote filesystem users will not be visible + // to the client. InteropModeWritethrough // InteropModeShared is appropriate when there are users of the remote // filesystem that may mutate its state other than the client. // - // - The client must verify ("revalidate") cached filesystem state before - // using it. + // - The client must verify ("revalidate") cached filesystem state before + // using it. // - // - Client changes to filesystem state must be sent to the remote - // filesystem synchronously. + // - Client changes to filesystem state must be sent to the remote + // filesystem synchronously. // - // - File timestamps are based on server clocks. This is necessary to - // ensure that timestamp changes are synchronized between remote filesystem - // users. + // - File timestamps are based on server clocks. This is necessary to + // ensure that timestamp changes are synchronized between remote filesystem + // users. // // Note that the correctness of InteropModeShared depends on the server // correctly implementing 9P fids (i.e. each fid immutably represents a @@ -830,11 +831,11 @@ type dentry struct { // If this dentry represents a directory, children contains: // - // - Mappings of child filenames to dentries representing those children. + // - Mappings of child filenames to dentries representing those children. // - // - Mappings of child filenames that are known not to exist to nil - // dentries (only if InteropModeShared is not in effect and the directory - // is not synthetic). + // - Mappings of child filenames that are known not to exist to nil + // dentries (only if InteropModeShared is not in effect and the directory + // is not synthetic). // // children is protected by dirMu. children map[string]*dentry @@ -871,11 +872,11 @@ type dentry struct { btime atomicbitops.Int64 // File size, which differs from other metadata in two ways: // - // - We make a best-effort attempt to keep it up to date even if - // !dentry.cachedMetadataAuthoritative() for the sake of O_APPEND writes. + // - We make a best-effort attempt to keep it up to date even if + // !dentry.cachedMetadataAuthoritative() for the sake of O_APPEND writes. // - // - size is protected by both metadataMu and dataMu (i.e. both must be - // locked to mutate it; locking either is sufficient to access it). + // - size is protected by both metadataMu and dataMu (i.e. both must be + // locked to mutate it; locking either is sufficient to access it). size atomicbitops.Uint64 // If this dentry does not represent a synthetic file, deleted is 0, and // atimeDirty/mtimeDirty are non-zero, atime/mtime may have diverged from the @@ -895,19 +896,19 @@ type dentry struct { // the file into memmap.MappingSpaces. mappings is protected by mapsMu. mappings memmap.MappingSet - // - If this dentry represents a regular file or directory, readFile is the - // p9.File used for reads by all regularFileFDs/directoryFDs representing - // this dentry, and readFD (if not -1) is a host FD equivalent to readFile - // used as a faster alternative. + // - If this dentry represents a regular file or directory, readFile is the + // p9.File used for reads by all regularFileFDs/directoryFDs representing + // this dentry, and readFD (if not -1) is a host FD equivalent to readFile + // used as a faster alternative. // - // - If this dentry represents a regular file, writeFile is the p9.File - // used for writes by all regularFileFDs representing this dentry, and - // writeFD (if not -1) is a host FD equivalent to writeFile used as a - // faster alternative. + // - If this dentry represents a regular file, writeFile is the p9.File + // used for writes by all regularFileFDs representing this dentry, and + // writeFD (if not -1) is a host FD equivalent to writeFile used as a + // faster alternative. // - // - If this dentry represents a regular file, mmapFD is the host FD used - // for memory mappings. If mmapFD is -1, no such FD is available, and the - // internal page cache implementation is used for memory mappings instead. + // - If this dentry represents a regular file, mmapFD is the host FD used + // for memory mappings. If mmapFD is -1, no such FD is available, and the + // internal page cache implementation is used for memory mappings instead. // // These fields are protected by handleMu. readFD, writeFD, and mmapFD are // additionally written using atomic memory operations, allowing them to be @@ -1276,8 +1277,9 @@ func (d *dentry) updateFromGetattr(ctx context.Context) error { } // Preconditions: -// * !d.isSynthetic(). -// * d.metadataMu is locked. +// - !d.isSynthetic(). +// - d.metadataMu is locked. +// // +checklocks:d.metadataMu func (d *dentry) updateFromStatLisaLocked(ctx context.Context, fdLisa *lisafs.ClientFD) error { handleMuRLocked := false @@ -1315,8 +1317,9 @@ func (d *dentry) updateFromStatLisaLocked(ctx context.Context, fdLisa *lisafs.Cl } // Preconditions: -// * !d.isSynthetic(). -// * d.metadataMu is locked. +// - !d.isSynthetic(). +// - d.metadataMu is locked. +// // +checklocks:d.metadataMu func (d *dentry) updateFromGetattrLocked(ctx context.Context, file p9file) error { handleMuRLocked := false @@ -1914,7 +1917,8 @@ func (fs *filesystem) evictAllCachedDentriesLocked(ctx context.Context) { } // Preconditions: -// * fs.renameMu must be locked for writing; it may be temporarily unlocked. +// - fs.renameMu must be locked for writing; it may be temporarily unlocked. +// // +checklocks:fs.renameMu func (fs *filesystem) evictCachedDentryLocked(ctx context.Context) { fs.cacheMu.Lock() @@ -1958,10 +1962,11 @@ func (fs *filesystem) evictCachedDentryLocked(ctx context.Context) { // destroyLocked destroys the dentry. // // Preconditions: -// * d.fs.renameMu must be locked for writing; it may be temporarily unlocked. -// * d.refs == 0. -// * d.parent.children[d.name] != d, i.e. d is not reachable by path traversal -// from its former parent dentry. +// - d.fs.renameMu must be locked for writing; it may be temporarily unlocked. +// - d.refs == 0. +// - d.parent.children[d.name] != d, i.e. d is not reachable by path traversal +// from its former parent dentry. +// // +checklocks:d.fs.renameMu func (d *dentry) destroyLocked(ctx context.Context) { switch d.refs.Load() { @@ -2142,8 +2147,8 @@ func (d *dentry) removeXattr(ctx context.Context, creds *auth.Credentials, name } // Preconditions: -// * !d.isSynthetic(). -// * d.isRegularFile() || d.isDir(). +// - !d.isSynthetic(). +// - d.isRegularFile() || d.isDir(). func (d *dentry) ensureSharedHandle(ctx context.Context, read, write, trunc bool) error { // O_TRUNC unconditionally requires us to obtain a new handle (opened with // O_TRUNC). @@ -2176,11 +2181,11 @@ func (d *dentry) ensureSharedHandle(ctx context.Context, read, write, trunc bool // Get a new handle. If this file has been opened for both reading and // writing, try to get a single handle that is usable for both: // - // - Writable memory mappings of a host FD require that the host FD is - // opened for both reading and writing. + // - Writable memory mappings of a host FD require that the host FD is + // opened for both reading and writing. // - // - NOTE(b/141991141): Some filesystems may not ensure coherence - // between multiple handles for the same file. + // - NOTE(b/141991141): Some filesystems may not ensure coherence + // between multiple handles for the same file. var ( openReadable bool openWritable bool diff --git a/pkg/sentry/fsimpl/gofer/revalidate.go b/pkg/sentry/fsimpl/gofer/revalidate.go index 33bf5b5b4..08136e441 100644 --- a/pkg/sentry/fsimpl/gofer/revalidate.go +++ b/pkg/sentry/fsimpl/gofer/revalidate.go @@ -45,7 +45,7 @@ func (errRevalidationStepDone) Error() string { // different mounts. // // Preconditions: -// * fs.renameMu must be locked. +// - fs.renameMu must be locked. func (fs *filesystem) revalidatePath(ctx context.Context, rpOrig *vfs.ResolvingPath, start *dentry, ds **[]*dentry) error { // Revalidation is done even if start is synthetic in case the path is // something like: ../non_synthetic_file. @@ -63,7 +63,7 @@ func (fs *filesystem) revalidatePath(ctx context.Context, rpOrig *vfs.ResolvingP // revalidateParentDir does the same as revalidatePath, but stops at the parent. // // Preconditions: -// * fs.renameMu must be locked. +// - fs.renameMu must be locked. func (fs *filesystem) revalidateParentDir(ctx context.Context, rpOrig *vfs.ResolvingPath, start *dentry, ds **[]*dentry) error { // Revalidation is done even if start is synthetic in case the path is // something like: ../non_synthetic_file and parent is non synthetic. @@ -81,7 +81,7 @@ func (fs *filesystem) revalidateParentDir(ctx context.Context, rpOrig *vfs.Resol // revalidateOne does the same as revalidatePath, but checks a single dentry. // // Preconditions: -// * fs.renameMu must be locked. +// - fs.renameMu must be locked. func (fs *filesystem) revalidateOne(ctx context.Context, vfsObj *vfs.VirtualFilesystem, parent *dentry, name string, ds **[]*dentry) error { // Skip revalidation for interop mode different than InteropModeShared or // if the parent is synthetic (child must be synthetic too, but it cannot be @@ -109,8 +109,8 @@ func (fs *filesystem) revalidateOne(ctx context.Context, vfsObj *vfs.VirtualFile // calls to the gofer to handle ".." in the path. // // Preconditions: -// * fs.renameMu must be locked. -// * InteropModeShared is in effect. +// - fs.renameMu must be locked. +// - InteropModeShared is in effect. func (fs *filesystem) revalidate(ctx context.Context, rp *vfs.ResolvingPath, start *dentry, done func() bool, ds **[]*dentry) error { state := makeRevalidateState(start) defer state.release() @@ -163,17 +163,17 @@ done: // also stop for other reasons, like hitting a child not in the cache. // // Returns: -// * (dentry, nil): step worked, continue stepping.` -// * (dentry, errPartialRevalidation): revalidation should be done with the +// - (dentry, nil): step worked, continue stepping.` +// - (dentry, errPartialRevalidation): revalidation should be done with the // state gathered so far. Then continue stepping with the remainder of the // path, starting at `dentry`. -// * (nil, errRevalidationStepDone): revalidation doesn't need to step any +// - (nil, errRevalidationStepDone): revalidation doesn't need to step any // further. It hit a symlink, a mount point, or an uncached dentry. // // Preconditions: -// * fs.renameMu must be locked. -// * !rp.Done(). -// * InteropModeShared is in effect (assumes no negative dentries). +// - fs.renameMu must be locked. +// - !rp.Done(). +// - InteropModeShared is in effect (assumes no negative dentries). func (fs *filesystem) revalidateStep(ctx context.Context, rp *vfs.ResolvingPath, d *dentry, state *revalidateState) (*dentry, error) { switch name := rp.Component(); name { case ".": @@ -228,8 +228,8 @@ func (fs *filesystem) revalidateStep(ctx context.Context, rp *vfs.ResolvingPath, // update or invalidate dentries in the cache based on the result. // // Preconditions: -// * fs.renameMu must be locked. -// * InteropModeShared is in effect. +// - fs.renameMu must be locked. +// - InteropModeShared is in effect. func (fs *filesystem) revalidateHelper(ctx context.Context, vfsObj *vfs.VirtualFilesystem, state *revalidateState, ds **[]*dentry) error { if len(state.names) == 0 { return nil @@ -388,7 +388,7 @@ func (r *revalidateState) release() { } // Preconditions: -// * d is a descendant of all dentries in r.dentries. +// - d is a descendant of all dentries in r.dentries. func (r *revalidateState) add(name string, d *dentry) { r.names = append(r.names, name) r.dentries = append(r.dentries, d) diff --git a/pkg/sentry/fsimpl/gofer/save_restore.go b/pkg/sentry/fsimpl/gofer/save_restore.go index 449aec324..0b152b130 100644 --- a/pkg/sentry/fsimpl/gofer/save_restore.go +++ b/pkg/sentry/fsimpl/gofer/save_restore.go @@ -81,8 +81,8 @@ func (fs *filesystem) PrepareSave(ctx context.Context) error { } // Preconditions: -// * fd represents a pipe. -// * fd is readable. +// - fd represents a pipe. +// - fd is readable. func (fd *specialFileFD) savePipeData(ctx context.Context) error { fd.bufMu.Lock() defer fd.bufMu.Unlock() @@ -261,11 +261,11 @@ func (d *dentry) restoreFile(ctx context.Context, file p9file, qid p9.QID, attrM // Gofers do not preserve QID across checkpoint/restore, so: // - // - We must assume that the remote filesystem did not change in a way that - // would invalidate dentries, since we can't revalidate dentries by - // checking QIDs. + // - We must assume that the remote filesystem did not change in a way that + // would invalidate dentries, since we can't revalidate dentries by + // checking QIDs. // - // - We need to associate the new QID.Path with the existing d.ino. + // - We need to associate the new QID.Path with the existing d.ino. d.qidPath = qid.Path d.fs.inoMu.Lock() d.fs.inoByQIDPath[qid.Path] = d.ino @@ -310,11 +310,11 @@ func (d *dentry) restoreFileLisa(ctx context.Context, inode *lisafs.Inode, opts // Gofers do not preserve inoKey across checkpoint/restore, so: // - // - We must assume that the remote filesystem did not change in a way that - // would invalidate dentries, since we can't revalidate dentries by - // checking inoKey. + // - We must assume that the remote filesystem did not change in a way that + // would invalidate dentries, since we can't revalidate dentries by + // checking inoKey. // - // - We need to associate the new inoKey with the existing d.ino. + // - We need to associate the new inoKey with the existing d.ino. d.inoKey = inoKeyFromStat(&inode.Stat) d.fs.inoMu.Lock() d.fs.inoByKey[d.inoKey] = d.ino diff --git a/pkg/sentry/fsimpl/gofer/time.go b/pkg/sentry/fsimpl/gofer/time.go index 17a35612b..1c1ccd874 100644 --- a/pkg/sentry/fsimpl/gofer/time.go +++ b/pkg/sentry/fsimpl/gofer/time.go @@ -58,8 +58,8 @@ func (d *dentry) touchAtimeLocked(mnt *vfs.Mount) { } // Preconditions: -// * d.cachedMetadataAuthoritative() == true. -// * The caller has successfully called vfs.Mount.CheckBeginWrite(). +// - d.cachedMetadataAuthoritative() == true. +// - The caller has successfully called vfs.Mount.CheckBeginWrite(). func (d *dentry) touchCtime() { now := d.fs.clock.Now().Nanoseconds() d.metadataMu.Lock() @@ -68,8 +68,8 @@ func (d *dentry) touchCtime() { } // Preconditions: -// * d.cachedMetadataAuthoritative() == true. -// * The caller has successfully called vfs.Mount.CheckBeginWrite(). +// - d.cachedMetadataAuthoritative() == true. +// - The caller has successfully called vfs.Mount.CheckBeginWrite(). func (d *dentry) touchCMtime() { now := d.fs.clock.Now().Nanoseconds() d.metadataMu.Lock() @@ -80,8 +80,8 @@ func (d *dentry) touchCMtime() { } // Preconditions: -// * d.cachedMetadataAuthoritative() == true. -// * The caller has locked d.metadataMu. +// - d.cachedMetadataAuthoritative() == true. +// - The caller has locked d.metadataMu. func (d *dentry) touchCMtimeLocked() { now := d.fs.clock.Now().Nanoseconds() d.mtime.Store(now) diff --git a/pkg/sentry/fsimpl/kernfs/filesystem.go b/pkg/sentry/fsimpl/kernfs/filesystem.go index 9afa93333..47a071ceb 100644 --- a/pkg/sentry/fsimpl/kernfs/filesystem.go +++ b/pkg/sentry/fsimpl/kernfs/filesystem.go @@ -33,8 +33,8 @@ import ( // stepExistingLocked is loosely analogous to fs/namei.c:walk_component(). // // Preconditions: -// * Filesystem.mu must be locked for at least reading. -// * !rp.Done(). +// - Filesystem.mu must be locked for at least reading. +// - !rp.Done(). // // Postcondition: Caller must call fs.processDeferredDecRefs*. func (fs *Filesystem) stepExistingLocked(ctx context.Context, rp *vfs.ResolvingPath, d *Dentry, mayFollowSymlinks bool) (*Dentry, error) { @@ -109,10 +109,10 @@ afterSymlink: // nil) to verify that the returned child (or lack thereof) is correct. // // Preconditions: -// * Filesystem.mu must be locked for at least reading. -// * parent.dirMu must be locked. -// * parent.isDir(). -// * name is not "." or "..". +// - Filesystem.mu must be locked for at least reading. +// - parent.dirMu must be locked. +// - parent.isDir(). +// - name is not "." or "..". // // Postconditions: Caller must call fs.processDeferredDecRefs*. func (fs *Filesystem) revalidateChildLocked(ctx context.Context, vfsObj *vfs.VirtualFilesystem, parent *Dentry, name string, child *Dentry) (*Dentry, error) { @@ -182,8 +182,8 @@ func (fs *Filesystem) walkExistingLocked(ctx context.Context, rp *vfs.ResolvingP // fs/namei.c:path_parentat(). // // Preconditions: -// * Filesystem.mu must be locked for at least reading. -// * !rp.Done(). +// - Filesystem.mu must be locked for at least reading. +// - !rp.Done(). // // Postconditions: Caller must call fs.processDeferredDecRefs*. func (fs *Filesystem) walkParentDirLocked(ctx context.Context, rp *vfs.ResolvingPath) (*Dentry, error) { @@ -205,8 +205,8 @@ func (fs *Filesystem) walkParentDirLocked(ctx context.Context, rp *vfs.Resolving // directory parent, then returns rp.Component(). // // Preconditions: -// * Filesystem.mu must be locked for at least reading. -// * isDir(parentInode) == true. +// - Filesystem.mu must be locked for at least reading. +// - isDir(parentInode) == true. func checkCreateLocked(ctx context.Context, creds *auth.Credentials, name string, parent *Dentry) error { // Order of checks is important. First check if parent directory can be // executed, then check for existence, and lastly check if mount is writable. diff --git a/pkg/sentry/fsimpl/kernfs/inode_impl_util.go b/pkg/sentry/fsimpl/kernfs/inode_impl_util.go index d002f58db..bcd019480 100644 --- a/pkg/sentry/fsimpl/kernfs/inode_impl_util.go +++ b/pkg/sentry/fsimpl/kernfs/inode_impl_util.go @@ -469,9 +469,9 @@ func (o *OrderedChildren) Destroy(ctx context.Context) { // may use to update the link count for the parent directory. // // Precondition: -// * d must represent a directory inode. -// * children must not contain any conflicting entries already in o. -// * Caller must hold a reference on all inodes passed. +// - d must represent a directory inode. +// - children must not contain any conflicting entries already in o. +// - Caller must hold a reference on all inodes passed. // // Postcondition: Caller's references on inodes are transferred to o. func (o *OrderedChildren) Populate(children map[string]Inode) uint32 { diff --git a/pkg/sentry/fsimpl/kernfs/kernfs.go b/pkg/sentry/fsimpl/kernfs/kernfs.go index c1b6c7248..2f07a65cd 100644 --- a/pkg/sentry/fsimpl/kernfs/kernfs.go +++ b/pkg/sentry/fsimpl/kernfs/kernfs.go @@ -15,17 +15,17 @@ // Package kernfs provides the tools to implement inode-based filesystems. // Kernfs has two main features: // -// 1. The Inode interface, which maps VFS2's path-based filesystem operations to -// specific filesystem nodes. Kernfs uses the Inode interface to provide a -// blanket implementation for the vfs.FilesystemImpl. Kernfs also serves as -// the synchronization mechanism for all filesystem operations by holding a -// filesystem-wide lock across all operations. +// 1. The Inode interface, which maps VFS2's path-based filesystem operations to +// specific filesystem nodes. Kernfs uses the Inode interface to provide a +// blanket implementation for the vfs.FilesystemImpl. Kernfs also serves as +// the synchronization mechanism for all filesystem operations by holding a +// filesystem-wide lock across all operations. // -// 2. Various utility types which provide generic implementations for various -// parts of the Inode and vfs.FileDescription interfaces. Client filesystems -// based on kernfs can embed the appropriate set of these to avoid having to -// reimplement common filesystem operations. See inode_impl_util.go and -// fd_impl_util.go. +// 2. Various utility types which provide generic implementations for various +// parts of the Inode and vfs.FileDescription interfaces. Client filesystems +// based on kernfs can embed the appropriate set of these to avoid having to +// reimplement common filesystem operations. See inode_impl_util.go and +// fd_impl_util.go. // // Reference Model: // @@ -47,13 +47,14 @@ // // Lock ordering: // -// kernfs.Filesystem.mu -// kernel.TaskSet.mu -// kernel.Task.mu -// kernfs.Dentry.dirMu -// vfs.VirtualFilesystem.mountMu -// vfs.Dentry.mu -// (inode implementation locks, if any) +// kernfs.Filesystem.mu +// kernel.TaskSet.mu +// kernel.Task.mu +// kernfs.Dentry.dirMu +// vfs.VirtualFilesystem.mountMu +// vfs.Dentry.mu +// (inode implementation locks, if any) +// // kernfs.Filesystem.deferredDecRefsMu package kernfs @@ -361,8 +362,8 @@ func (d *Dentry) cacheLocked(ctx context.Context) { } // Preconditions: -// * fs.mu must be locked for writing. -// * fs.cachedDentriesLen != 0. +// - fs.mu must be locked for writing. +// - fs.cachedDentriesLen != 0. func (fs *Filesystem) evictCachedDentryLocked(ctx context.Context) { // Evict the least recently used dentry because cache size is greater than // max cache size (configured on mount). @@ -390,11 +391,11 @@ func (fs *Filesystem) evictCachedDentryLocked(ctx context.Context) { // destroyLocked destroys the dentry. // // Preconditions: -// * d.fs.mu must be locked for writing. -// * d.refs == 0. -// * d should have been removed from d.parent.children, i.e. d is not reachable -// by path traversal. -// * d.vfsd.IsDead() is true. +// - d.fs.mu must be locked for writing. +// - d.refs == 0. +// - d should have been removed from d.parent.children, i.e. d is not reachable +// by path traversal. +// - d.vfsd.IsDead() is true. func (d *Dentry) destroyLocked(ctx context.Context) { refs := d.refs.Load() switch refs { @@ -503,8 +504,8 @@ func (d *Dentry) OnZeroWatches(context.Context) {} // own isn't sufficient to insert a child into a directory. // // Preconditions: -// * d must represent a directory inode. -// * d.fs.mu must be locked for at least reading. +// - d must represent a directory inode. +// - d.fs.mu must be locked for at least reading. func (d *Dentry) insertChild(name string, child *Dentry) { d.dirMu.Lock() d.insertChildLocked(name, child) @@ -515,9 +516,9 @@ func (d *Dentry) insertChild(name string, child *Dentry) { // preconditions. // // Preconditions: -// * d must represent a directory inode. -// * d.dirMu must be locked. -// * d.fs.mu must be locked for at least reading. +// - d must represent a directory inode. +// - d.dirMu must be locked. +// - d.fs.mu must be locked for at least reading. func (d *Dentry) insertChildLocked(name string, child *Dentry) { if !d.isDir() { panic(fmt.Sprintf("insertChildLocked called on non-directory Dentry: %+v.", d)) @@ -622,8 +623,8 @@ func (d *Dentry) Parent() *Dentry { // Generally, implementations are not responsible for tasks that are common to // all filesystems. These include: // -// - Checking that dentries passed to methods are of the appropriate file type. -// - Checking permissions. +// - Checking that dentries passed to methods are of the appropriate file type. +// - Checking permissions. // // Inode functions may be called holding filesystem wide locks and are not // allowed to call vfs functions that may reenter, unless otherwise noted. @@ -785,14 +786,14 @@ type inodeSymlink interface { // Getlink returns the target of a symbolic link, as used by path // resolution: // - // - If the inode is a "magic link" (a link whose target is most accurately - // represented as a VirtualDentry), Getlink returns (ok VirtualDentry, "", - // nil). A reference is taken on the returned VirtualDentry. + // - If the inode is a "magic link" (a link whose target is most accurately + // represented as a VirtualDentry), Getlink returns (ok VirtualDentry, "", + // nil). A reference is taken on the returned VirtualDentry. // - // - If the inode is an ordinary symlink, Getlink returns (zero-value - // VirtualDentry, symlink target, nil). + // - If the inode is an ordinary symlink, Getlink returns (zero-value + // VirtualDentry, symlink target, nil). // - // - If the inode is not a symlink, Getlink returns (zero-value - // VirtualDentry, "", EINVAL). + // - If the inode is not a symlink, Getlink returns (zero-value + // VirtualDentry, "", EINVAL). Getlink(ctx context.Context, mnt *vfs.Mount) (vfs.VirtualDentry, string, error) } diff --git a/pkg/sentry/fsimpl/overlay/copy_up.go b/pkg/sentry/fsimpl/overlay/copy_up.go index 31dd82381..4cfc3f6fd 100644 --- a/pkg/sentry/fsimpl/overlay/copy_up.go +++ b/pkg/sentry/fsimpl/overlay/copy_up.go @@ -319,17 +319,17 @@ func (d *dentry) copyUpMaybeSyntheticMountpointLocked(ctx context.Context, forSy // Switch to the new Mappable. We do this at the end of copy-up // because: // - // - We need to switch Mappables (by changing d.wrappedMappable) before - // invalidating Translations from the old Mappable (to pick up - // Translations from the new one). + // - We need to switch Mappables (by changing d.wrappedMappable) before + // invalidating Translations from the old Mappable (to pick up + // Translations from the new one). // - // - We need to lock d.dataMu while changing d.wrappedMappable, but - // must invalidate Translations with d.dataMu unlocked (due to lock - // ordering). + // - We need to lock d.dataMu while changing d.wrappedMappable, but + // must invalidate Translations with d.dataMu unlocked (due to lock + // ordering). // - // - Consequently, once we unlock d.dataMu, other threads may - // immediately observe the new (copied-up) Mappable, which we want to - // delay until copy-up is guaranteed to succeed. + // - Consequently, once we unlock d.dataMu, other threads may + // immediately observe the new (copied-up) Mappable, which we want to + // delay until copy-up is guaranteed to succeed. d.dataMu.Lock() lowerMappable := d.wrappedMappable d.wrappedMappable = upperMappable @@ -391,9 +391,9 @@ func (d *dentry) copyXattrsLocked(ctx context.Context) error { // copyUpDescendantsLocked ensures that all descendants of d are copied up. // // Preconditions: -// * filesystem.renameMu must be locked. -// * d.dirMu must be locked. -// * d.isDir(). +// - filesystem.renameMu must be locked. +// - d.dirMu must be locked. +// - d.isDir(). func (d *dentry) copyUpDescendantsLocked(ctx context.Context, ds **[]*dentry) error { dirents, err := d.getDirentsLocked(ctx) if err != nil { diff --git a/pkg/sentry/fsimpl/overlay/directory.go b/pkg/sentry/fsimpl/overlay/directory.go index 1a2a42681..8091f718a 100644 --- a/pkg/sentry/fsimpl/overlay/directory.go +++ b/pkg/sentry/fsimpl/overlay/directory.go @@ -28,8 +28,8 @@ func (d *dentry) isDir() bool { } // Preconditions: -// * d.dirMu must be locked. -// * d.isDir(). +// - d.dirMu must be locked. +// - d.isDir(). func (d *dentry) collectWhiteoutsForRmdirLocked(ctx context.Context) (map[string]bool, error) { vfsObj := d.fs.vfsfs.VirtualFilesystem() var readdirErr error @@ -148,9 +148,9 @@ func (d *dentry) getDirents(ctx context.Context) ([]vfs.Dirent, error) { } // Preconditions: -// * filesystem.renameMu must be locked. -// * d.dirMu must be locked. -// * d.isDir(). +// - filesystem.renameMu must be locked. +// - d.dirMu must be locked. +// - d.isDir(). func (d *dentry) getDirentsLocked(ctx context.Context) ([]vfs.Dirent, error) { if d.dirents != nil { return d.dirents, nil diff --git a/pkg/sentry/fsimpl/overlay/filesystem.go b/pkg/sentry/fsimpl/overlay/filesystem.go index 94da1ad6c..f8f8f7379 100644 --- a/pkg/sentry/fsimpl/overlay/filesystem.go +++ b/pkg/sentry/fsimpl/overlay/filesystem.go @@ -132,9 +132,9 @@ func (fs *filesystem) renameMuUnlockAndCheckDrop(ctx context.Context, ds **[]*de // should be dropped once traversal is complete, are appended to ds. // // Preconditions: -// * fs.renameMu must be locked. -// * d.dirMu must be locked. -// * !rp.Done(). +// - fs.renameMu must be locked. +// - d.dirMu must be locked. +// - !rp.Done(). func (fs *filesystem) stepLocked(ctx context.Context, rp *vfs.ResolvingPath, d *dentry, mayFollowSymlinks bool, ds **[]*dentry) (*dentry, lookupLayer, error) { if !d.isDir() { return nil, lookupLayerNone, linuxerr.ENOTDIR @@ -183,8 +183,8 @@ afterSymlink: } // Preconditions: -// * fs.renameMu must be locked. -// * d.dirMu must be locked. +// - fs.renameMu must be locked. +// - d.dirMu must be locked. func (fs *filesystem) getChildLocked(ctx context.Context, parent *dentry, name string, ds **[]*dentry) (*dentry, lookupLayer, error) { if child, ok := parent.children[name]; ok { return child, child.topLookupLayer(), nil @@ -203,8 +203,8 @@ func (fs *filesystem) getChildLocked(ctx context.Context, parent *dentry, name s } // Preconditions: -// * fs.renameMu must be locked. -// * parent.dirMu must be locked. +// - fs.renameMu must be locked. +// - parent.dirMu must be locked. func (fs *filesystem) lookupLocked(ctx context.Context, parent *dentry, name string) (*dentry, lookupLayer, error) { childPath := fspath.Parse(name) child := fs.newDentry() @@ -338,8 +338,8 @@ func (fs *filesystem) lookupLocked(ctx context.Context, parent *dentry, name str // about the file rather than a dentry. // // Preconditions: -// * fs.renameMu must be locked. -// * parent.dirMu must be locked. +// - fs.renameMu must be locked. +// - parent.dirMu must be locked. func (fs *filesystem) lookupLayerLocked(ctx context.Context, parent *dentry, name string) (lookupLayer, error) { childPath := fspath.Parse(name) lookupLayer := lookupLayerNone @@ -425,8 +425,8 @@ func (ll lookupLayer) existsInOverlay() bool { // is searchable by the provider of rp. // // Preconditions: -// * fs.renameMu must be locked. -// * !rp.Done(). +// - fs.renameMu must be locked. +// - !rp.Done(). func (fs *filesystem) walkParentDirLocked(ctx context.Context, rp *vfs.ResolvingPath, d *dentry, ds **[]*dentry) (*dentry, error) { for !rp.Final() { d.dirMu.Lock() @@ -475,8 +475,8 @@ const ( // create to do so. // // Preconditions: -// * !rp.Done(). -// * For the final path component in rp, !rp.ShouldFollowSymlink(). +// - !rp.Done(). +// - For the final path component in rp, !rp.ShouldFollowSymlink(). func (fs *filesystem) doCreateAt(ctx context.Context, rp *vfs.ResolvingPath, ct createType, create func(parent *dentry, name string, haveUpperWhiteout bool) error) error { var ds *[]*dentry fs.renameMu.RLock() @@ -940,8 +940,8 @@ func (d *dentry) openCopiedUp(ctx context.Context, rp *vfs.ResolvingPath, opts * } // Preconditions: -// * parent.dirMu must be locked. -// * parent does not already contain a child named rp.Component(). +// - parent.dirMu must be locked. +// - parent does not already contain a child named rp.Component(). func (fs *filesystem) createAndOpenLocked(ctx context.Context, rp *vfs.ResolvingPath, parent *dentry, opts *vfs.OpenOptions, ds **[]*dentry, haveUpperWhiteout bool) (*vfs.FileDescription, error) { creds := rp.Credentials() if err := parent.checkPermissions(creds, vfs.MayWrite); err != nil { diff --git a/pkg/sentry/fsimpl/overlay/overlay.go b/pkg/sentry/fsimpl/overlay/overlay.go index da5ea1d48..71a6dd61a 100644 --- a/pkg/sentry/fsimpl/overlay/overlay.go +++ b/pkg/sentry/fsimpl/overlay/overlay.go @@ -18,15 +18,15 @@ // // Lock order: // -// directoryFD.mu / regularFileFD.mu -// filesystem.renameMu -// dentry.dirMu -// dentry.copyMu -// filesystem.devMu -// *** "memmap.Mappable locks" below this point -// dentry.mapsMu -// *** "memmap.Mappable locks taken by Translate" below this point -// dentry.dataMu +// directoryFD.mu / regularFileFD.mu +// filesystem.renameMu +// dentry.dirMu +// dentry.copyMu +// filesystem.devMu +// *** "memmap.Mappable locks" below this point +// dentry.mapsMu +// *** "memmap.Mappable locks taken by Translate" below this point +// dentry.dataMu // // Locking dentry.dirMu in multiple dentries requires that parent dentries are // locked before child dentries, and that filesystem.renameMu is locked to @@ -432,27 +432,27 @@ type dentry struct { // If this dentry represents a regular file, then: // - // - mapsMu is used to synchronize between copy-up and memmap.Mappable - // methods on dentry preceding mm.MemoryManager.activeMu in the lock order. + // - mapsMu is used to synchronize between copy-up and memmap.Mappable + // methods on dentry preceding mm.MemoryManager.activeMu in the lock order. // - // - dataMu is used to synchronize between copy-up and - // dentry.(memmap.Mappable).Translate. + // - dataMu is used to synchronize between copy-up and + // dentry.(memmap.Mappable).Translate. // - // - lowerMappings tracks memory mappings of the file. lowerMappings is - // used to invalidate mappings of the lower layer when the file is copied - // up to ensure that they remain coherent with subsequent writes to the - // file. (Note that, as of this writing, Linux overlayfs does not do this; - // this feature is a gVisor extension.) lowerMappings is protected by - // mapsMu. + // - lowerMappings tracks memory mappings of the file. lowerMappings is + // used to invalidate mappings of the lower layer when the file is copied + // up to ensure that they remain coherent with subsequent writes to the + // file. (Note that, as of this writing, Linux overlayfs does not do this; + // this feature is a gVisor extension.) lowerMappings is protected by + // mapsMu. // - // - If this dentry is copied-up, then wrappedMappable is the Mappable - // obtained from a call to the current top layer's - // FileDescription.ConfigureMMap(). Once wrappedMappable becomes non-nil - // (from a call to regularFileFD.ensureMappable()), it cannot become nil. - // wrappedMappable is protected by mapsMu and dataMu. + // - If this dentry is copied-up, then wrappedMappable is the Mappable + // obtained from a call to the current top layer's + // FileDescription.ConfigureMMap(). Once wrappedMappable becomes non-nil + // (from a call to regularFileFD.ensureMappable()), it cannot become nil. + // wrappedMappable is protected by mapsMu and dataMu. // - // - isMappable is non-zero iff wrappedMappable is non-nil. isMappable is - // accessed using atomic memory operations. + // - isMappable is non-zero iff wrappedMappable is non-nil. isMappable is + // accessed using atomic memory operations. mapsMu sync.Mutex `state:"nosave"` lowerMappings memmap.MappingSet dataMu sync.RWMutex `state:"nosave"` @@ -565,8 +565,8 @@ func (d *dentry) checkDropLocked(ctx context.Context) { // destroyLocked destroys the dentry. // // Preconditions: -// * d.fs.renameMu must be locked for writing. -// * d.refs == 0. +// - d.fs.renameMu must be locked for writing. +// - d.refs == 0. func (d *dentry) destroyLocked(ctx context.Context) { switch d.refs.Load() { case 0: diff --git a/pkg/sentry/fsimpl/proc/tasks_files.go b/pkg/sentry/fsimpl/proc/tasks_files.go index faec36d8d..5168d49a6 100644 --- a/pkg/sentry/fsimpl/proc/tasks_files.go +++ b/pkg/sentry/fsimpl/proc/tasks_files.go @@ -341,12 +341,12 @@ func (*versionData) Generate(ctx context.Context, buf *bytes.Buffer) error { // (COMPILER_VERSION) VERSION" // // where: - // - SYSNAME, RELEASE, and VERSION are the same as returned by - // sys_utsname - // - COMPILE_USER is the user that build the kernel - // - COMPILE_HOST is the hostname of the machine on which the kernel - // was built - // - COMPILER_VERSION is the version reported by the building compiler + // - SYSNAME, RELEASE, and VERSION are the same as returned by + // sys_utsname + // - COMPILE_USER is the user that build the kernel + // - COMPILE_HOST is the hostname of the machine on which the kernel + // was built + // - COMPILER_VERSION is the version reported by the building compiler // // Since we don't really want to expose build information to // applications, those fields are omitted. diff --git a/pkg/sentry/fsimpl/tmpfs/benchmark_test.go b/pkg/sentry/fsimpl/tmpfs/benchmark_test.go index bb24d313b..0f68fc812 100644 --- a/pkg/sentry/fsimpl/tmpfs/benchmark_test.go +++ b/pkg/sentry/fsimpl/tmpfs/benchmark_test.go @@ -35,10 +35,11 @@ import ( // Differences from stat_benchmark: // -// - Syscall interception, CopyInPath, copyOutStat, and overlayfs overheads are -// not included. +// - Syscall interception, CopyInPath, copyOutStat, and overlayfs overheads are +// not included. +// +// - *MountStat benchmarks use a tmpfs root mount and a tmpfs submount at /tmp. // -// - *MountStat benchmarks use a tmpfs root mount and a tmpfs submount at /tmp. // Non-MountStat benchmarks use a tmpfs root mount and no submounts. // stat_benchmark uses a varying root mount, a tmpfs submount at /tmp, and a // subdirectory /tmp/ (assuming TEST_TMPDIR == "/tmp"). Thus diff --git a/pkg/sentry/fsimpl/tmpfs/directory.go b/pkg/sentry/fsimpl/tmpfs/directory.go index 6d20d69cb..7937bb419 100644 --- a/pkg/sentry/fsimpl/tmpfs/directory.go +++ b/pkg/sentry/fsimpl/tmpfs/directory.go @@ -58,8 +58,8 @@ func (fs *filesystem) newDirectory(kuid auth.KUID, kgid auth.KGID, mode linux.Fi } // Preconditions: -// * filesystem.mu must be locked for writing. -// * dir must not already contain a child with the given name. +// - filesystem.mu must be locked for writing. +// - dir must not already contain a child with the given name. func (dir *directory) insertChildLocked(child *dentry, name string) { child.parent = &dir.dentry child.name = name diff --git a/pkg/sentry/fsimpl/tmpfs/filesystem.go b/pkg/sentry/fsimpl/tmpfs/filesystem.go index 16ba75647..6a2eab7a0 100644 --- a/pkg/sentry/fsimpl/tmpfs/filesystem.go +++ b/pkg/sentry/fsimpl/tmpfs/filesystem.go @@ -50,8 +50,8 @@ func (fs *filesystem) Sync(ctx context.Context) error { // stepLocked is loosely analogous to fs/namei.c:walk_component(). // // Preconditions: -// * filesystem.mu must be locked. -// * !rp.Done(). +// - filesystem.mu must be locked. +// - !rp.Done(). func stepLocked(ctx context.Context, rp *vfs.ResolvingPath, d *dentry) (*dentry, error) { dir, ok := d.inode.impl.(*directory) if !ok { @@ -110,8 +110,8 @@ afterSymlink: // fs/namei.c:path_parentat(). // // Preconditions: -// * filesystem.mu must be locked. -// * !rp.Done(). +// - filesystem.mu must be locked. +// - !rp.Done(). func walkParentDirLocked(ctx context.Context, rp *vfs.ResolvingPath, d *dentry) (*directory, error) { for !rp.Final() { next, err := stepLocked(ctx, rp, d) @@ -154,8 +154,8 @@ func resolveLocked(ctx context.Context, rp *vfs.ResolvingPath) (*dentry, error) // fs/namei.c:filename_create() and done_path_create(). // // Preconditions: -// * !rp.Done(). -// * For the final path component in rp, !rp.ShouldFollowSymlink(). +// - !rp.Done(). +// - For the final path component in rp, !rp.ShouldFollowSymlink(). func (fs *filesystem) doCreateAt(ctx context.Context, rp *vfs.ResolvingPath, dir bool, create func(parentDir *directory, name string) error) error { fs.mu.Lock() defer fs.mu.Unlock() diff --git a/pkg/sentry/fsimpl/tmpfs/named_pipe.go b/pkg/sentry/fsimpl/tmpfs/named_pipe.go index 9cd55496d..f532b1417 100644 --- a/pkg/sentry/fsimpl/tmpfs/named_pipe.go +++ b/pkg/sentry/fsimpl/tmpfs/named_pipe.go @@ -29,8 +29,8 @@ type namedPipe struct { } // Preconditions: -// * fs.mu must be locked. -// * rp.Mount().CheckBeginWrite() has been called successfully. +// - fs.mu must be locked. +// - rp.Mount().CheckBeginWrite() has been called successfully. func (fs *filesystem) newNamedPipe(kuid auth.KUID, kgid auth.KGID, mode linux.FileMode, parentDir *directory) *inode { file := &namedPipe{pipe: pipe.NewVFSPipe(true /* isNamed */, pipe.DefaultPipeSize)} file.inode.init(file, fs, kuid, kgid, linux.S_IFIFO|mode, parentDir) diff --git a/pkg/sentry/fsimpl/tmpfs/tmpfs.go b/pkg/sentry/fsimpl/tmpfs/tmpfs.go index fabc46f24..8b988edaf 100644 --- a/pkg/sentry/fsimpl/tmpfs/tmpfs.go +++ b/pkg/sentry/fsimpl/tmpfs/tmpfs.go @@ -17,15 +17,15 @@ // // Lock order: // -// filesystem.mu -// inode.mu -// regularFileFD.offMu -// *** "memmap.Mappable locks" below this point -// regularFile.mapsMu -// *** "memmap.Mappable locks taken by Translate" below this point -// regularFile.dataMu -// fs.pagesUsedMu -// directory.iterMu +// filesystem.mu +// inode.mu +// regularFileFD.offMu +// *** "memmap.Mappable locks" below this point +// regularFile.mapsMu +// *** "memmap.Mappable locks taken by Translate" below this point +// regularFile.dataMu +// fs.pagesUsedMu +// directory.iterMu package tmpfs import ( @@ -487,10 +487,10 @@ func (i *inode) init(impl interface{}, fs *filesystem, kuid auth.KUID, kgid auth // incLinksLocked increments i's link count. // // Preconditions: -// * filesystem.mu must be locked for writing. -// * i.mu must be lcoked. -// * i.nlink != 0. -// * i.nlink < maxLinks. +// - filesystem.mu must be locked for writing. +// - i.mu must be lcoked. +// - i.nlink != 0. +// - i.nlink < maxLinks. func (i *inode) incLinksLocked() { if i.nlink.RacyLoad() == 0 { panic("tmpfs.inode.incLinksLocked() called with no existing links") @@ -505,9 +505,9 @@ func (i *inode) incLinksLocked() { // remove a reference on i as well. // // Preconditions: -// * filesystem.mu must be locked for writing. -// * i.mu must be lcoked. -// * i.nlink != 0. +// - filesystem.mu must be locked for writing. +// - i.mu must be lcoked. +// - i.nlink != 0. func (i *inode) decLinksLocked(ctx context.Context) { if i.nlink.RacyLoad() == 0 { panic("tmpfs.inode.decLinksLocked() called with no existing links") @@ -790,8 +790,8 @@ func (i *inode) touchCMtime() { } // Preconditions: -// * The caller has called vfs.Mount.CheckBeginWrite(). -// * inode.mu must be locked. +// - The caller has called vfs.Mount.CheckBeginWrite(). +// - inode.mu must be locked. func (i *inode) touchCMtimeLocked() { now := i.fs.clock.Now().Nanoseconds() i.mtime.Store(now) diff --git a/pkg/sentry/fsimpl/verity/filesystem.go b/pkg/sentry/fsimpl/verity/filesystem.go index d1089d83d..48e5e71f8 100644 --- a/pkg/sentry/fsimpl/verity/filesystem.go +++ b/pkg/sentry/fsimpl/verity/filesystem.go @@ -93,9 +93,9 @@ func (fs *filesystem) renameMuRUnlockAndCheckCaching(ctx context.Context, ds **[ // should be dropped once traversal is complete, are appended to ds. // // Preconditions: -// * fs.renameMu must be locked. -// * d.dirMu must be locked. -// * !rp.Done(). +// - fs.renameMu must be locked. +// - d.dirMu must be locked. +// - !rp.Done(). func (fs *filesystem) stepLocked(ctx context.Context, rp *vfs.ResolvingPath, d *dentry, mayFollowSymlinks bool, ds **[]*dentry) (*dentry, error) { if !d.isDir() { return nil, linuxerr.ENOTDIR @@ -151,8 +151,8 @@ afterSymlink: // ErrorOnViolation mode it returns a linuxerr instead. // // Preconditions: -// * fs.renameMu must be locked. -// * d.dirMu must be locked. +// - fs.renameMu must be locked. +// - d.dirMu must be locked. func (fs *filesystem) verifyChildLocked(ctx context.Context, parent *dentry, child *dentry) (*dentry, error) { vfsObj := fs.vfsfs.VirtualFilesystem() @@ -435,8 +435,8 @@ func (fs *filesystem) verifyStatAndChildrenLocked(ctx context.Context, d *dentry } // Preconditions: -// * fs.renameMu must be locked. -// * parent.dirMu must be locked. +// - fs.renameMu must be locked. +// - parent.dirMu must be locked. func (fs *filesystem) getChildLocked(ctx context.Context, parent *dentry, name string, ds **[]*dentry) (*dentry, error) { if child, ok := parent.children[name]; ok { // If verity is enabled on child, we should check again whether @@ -522,8 +522,8 @@ func (fs *filesystem) getChildLocked(ctx context.Context, parent *dentry, name s } // Preconditions: -// * fs.renameMu must be locked. -// * parent.dirMu must be locked. +// - fs.renameMu must be locked. +// - parent.dirMu must be locked. func (fs *filesystem) lookupAndVerifyLocked(ctx context.Context, parent *dentry, name string) (*dentry, error) { vfsObj := fs.vfsfs.VirtualFilesystem() @@ -637,8 +637,8 @@ func (fs *filesystem) lookupAndVerifyLocked(ctx context.Context, parent *dentry, // is searchable by the provider of rp. // // Preconditions: -// * fs.renameMu must be locked. -// * !rp.Done(). +// - fs.renameMu must be locked. +// - !rp.Done(). func (fs *filesystem) walkParentDirLocked(ctx context.Context, rp *vfs.ResolvingPath, d *dentry, ds **[]*dentry) (*dentry, error) { for !rp.Final() { d.dirMu.Lock() diff --git a/pkg/sentry/fsimpl/verity/verity.go b/pkg/sentry/fsimpl/verity/verity.go index c77316386..9f0b01b67 100644 --- a/pkg/sentry/fsimpl/verity/verity.go +++ b/pkg/sentry/fsimpl/verity/verity.go @@ -22,13 +22,13 @@ // // Lock order: // -// filesystem.renameMu -// dentry.cachingMu -// filesystem.cacheMu -// dentry.dirMu -// fileDescription.mu -// filesystem.verityMu -// dentry.hashMu +// filesystem.renameMu +// dentry.cachingMu +// filesystem.cacheMu +// dentry.dirMu +// fileDescription.mu +// filesystem.verityMu +// dentry.hashMu // // Locking dentry.dirMu in multiple dentries requires that parent dentries are // locked before child dentries, and that filesystem.renameMu is locked to @@ -709,8 +709,8 @@ func (d *dentry) decRefNoCaching() int64 { // destroyLocked destroys the dentry. // // Preconditions: -// * d.fs.renameMu must be locked for writing. -// * d.refs == 0. +// - d.fs.renameMu must be locked for writing. +// - d.refs == 0. func (d *dentry) destroyLocked(ctx context.Context) { switch d.refs.Load() { case 0: @@ -880,7 +880,8 @@ func (fs *filesystem) evictAllCachedDentriesLocked(ctx context.Context) { } // Preconditions: -// * fs.renameMu must be locked for writing; it may be temporarily unlocked. +// - fs.renameMu must be locked for writing; it may be temporarily unlocked. +// // +checklocks:fs.renameMu func (fs *filesystem) evictCachedDentryLocked(ctx context.Context) { fs.cacheMu.Lock() @@ -1216,8 +1217,8 @@ func (fd *fileDescription) generateMerkleLocked(ctx context.Context) ([]byte, ui // xattrs. // // Preconditions: -// * fd.d.fs.verityMu must be locked. -// * fd.d.isDir() == true. +// - fd.d.fs.verityMu must be locked. +// - fd.d.isDir() == true. func (fd *fileDescription) recordChildrenLocked(ctx context.Context) error { // Record the children names in the Merkle tree file. childrenNames, err := json.Marshal(fd.d.childrenNames) diff --git a/pkg/sentry/fsmetric/fsmetric.go b/pkg/sentry/fsmetric/fsmetric.go index 17d0d5025..30248a8fa 100644 --- a/pkg/sentry/fsmetric/fsmetric.go +++ b/pkg/sentry/fsmetric/fsmetric.go @@ -73,6 +73,7 @@ func StartReadWait() time.Time { // FinishReadWait is marked nosplit for performance since it's often called // from defer statements, which prevents it from being inlined // (https://github.com/golang/go/issues/38471). +// //go:nosplit func FinishReadWait(m *metric.Uint64Metric, start time.Time) { if !RecordWaitTime { diff --git a/pkg/sentry/kernel/auth/id.go b/pkg/sentry/kernel/auth/id.go index 994486ea8..6551d184b 100644 --- a/pkg/sentry/kernel/auth/id.go +++ b/pkg/sentry/kernel/auth/id.go @@ -46,9 +46,9 @@ const ( // NoID is uint32(-1). -1 is consistently used as a special value, in Linux // and by extension in the auth package, to mean "no ID": // - // - ID mapping returns -1 if the ID is not mapped. + // - ID mapping returns -1 if the ID is not mapped. // - // - Most set*id() syscalls accept -1 to mean "do not change this ID". + // - Most set*id() syscalls accept -1 to mean "do not change this ID". NoID = math.MaxUint32 // OverflowUID is the default value of /proc/sys/kernel/overflowuid. The diff --git a/pkg/sentry/kernel/auth/id_map.go b/pkg/sentry/kernel/auth/id_map.go index f06a374a0..5c33009c9 100644 --- a/pkg/sentry/kernel/auth/id_map.go +++ b/pkg/sentry/kernel/auth/id_map.go @@ -133,16 +133,16 @@ func (ns *UserNamespace) SetUIDMap(ctx context.Context, entries []IDMapEntry) er // // 4. One of the following two cases applies: // - // * Either the writing process has the CAP_SETUID (CAP_SETGID) capability - // in the parent user namespace. + // * Either the writing process has the CAP_SETUID (CAP_SETGID) capability + // in the parent user namespace. // """ if !c.HasCapabilityIn(linux.CAP_SETUID, ns.parent) { // """ - // * Or otherwise all of the following restrictions apply: + // * Or otherwise all of the following restrictions apply: // - // + The data written to uid_map (gid_map) must consist of a single line - // that maps the writing process' effective user ID (group ID) in the - // parent user namespace to a user ID (group ID) in the user namespace. + // + The data written to uid_map (gid_map) must consist of a single line + // that maps the writing process' effective user ID (group ID) in the + // parent user namespace to a user ID (group ID) in the user namespace. // """ if len(entries) != 1 || ns.parent.MapToKUID(UID(entries[0].FirstParentID)) != c.EffectiveKUID || entries[0].Length != 1 { return linuxerr.EPERM diff --git a/pkg/sentry/kernel/epoll/epoll.go b/pkg/sentry/kernel/epoll/epoll.go index e56f422c8..09425c10b 100644 --- a/pkg/sentry/kernel/epoll/epoll.go +++ b/pkg/sentry/kernel/epoll/epoll.go @@ -16,10 +16,11 @@ // facility. See epoll(7) for more details. // // Lock order: -// EventPoll.mu -// fdnotifier.notifier.mu -// EventPoll.listsMu -// unix.baseEndpoint.Mutex +// +// EventPoll.mu +// fdnotifier.notifier.mu +// EventPoll.listsMu +// unix.baseEndpoint.Mutex package epoll import ( diff --git a/pkg/sentry/kernel/futex/futex.go b/pkg/sentry/kernel/futex/futex.go index 2c9ea65aa..5783519c0 100644 --- a/pkg/sentry/kernel/futex/futex.go +++ b/pkg/sentry/kernel/futex/futex.go @@ -201,18 +201,18 @@ func atomicOp(t Target, addr hostarch.Addr, opIn uint32) (bool, error) { type Waiter struct { // Synchronization: // - // - A Waiter that is not enqueued in a bucket is exclusively owned (no - // synchronization applies). + // - A Waiter that is not enqueued in a bucket is exclusively owned (no + // synchronization applies). // - // - A Waiter is enqueued in a bucket by calling WaitPrepare(). After this, - // waiterEntry, bucket, and key are protected by the bucket.mu ("bucket - // lock") of the containing bucket, and bitmask is immutable. Note that - // since bucket is mutated using atomic memory operations, bucket.Load() - // may be called without holding the bucket lock, although it may change - // racily. See WaitComplete(). + // - A Waiter is enqueued in a bucket by calling WaitPrepare(). After this, + // waiterEntry, bucket, and key are protected by the bucket.mu ("bucket + // lock") of the containing bucket, and bitmask is immutable. Note that + // since bucket is mutated using atomic memory operations, bucket.Load() + // may be called without holding the bucket lock, although it may change + // racily. See WaitComplete(). // - // - A Waiter is only guaranteed to be no longer queued after calling - // WaitComplete(). + // - A Waiter is only guaranteed to be no longer queued after calling + // WaitComplete(). // waiterEntry links Waiter into bucket.waiters. waiterEntry @@ -342,11 +342,11 @@ func getKey(t Target, addr hostarch.Addr, private bool) (Key, error) { // bucketIndexForAddr returns the index into Manager.buckets for addr. func bucketIndexForAddr(addr hostarch.Addr) uintptr { - // - The bottom 2 bits of addr must be 0, per getKey. + // - The bottom 2 bits of addr must be 0, per getKey. // - // - On amd64, the top 16 bits of addr (bits 48-63) must be equal to bit 47 - // for a canonical address, and (on all existing platforms) bit 47 must be - // 0 for an application address. + // - On amd64, the top 16 bits of addr (bits 48-63) must be equal to bit 47 + // for a canonical address, and (on all existing platforms) bit 47 must be + // 0 for an application address. // // Thus 19 bits of addr are "useless" for hashing, leaving only 45 "useful" // bits. We choose one of the simplest possible hash functions that at diff --git a/pkg/sentry/kernel/kernel.go b/pkg/sentry/kernel/kernel.go index 8b5af6a66..241c205ab 100644 --- a/pkg/sentry/kernel/kernel.go +++ b/pkg/sentry/kernel/kernel.go @@ -18,13 +18,13 @@ // // Lock order (outermost locks must be taken first): // -// Kernel.extMu -// ThreadGroup.timerMu -// ktime.Timer.mu (for kernelCPUClockTicker and IntervalTimer) -// TaskSet.mu -// SignalHandlers.mu -// Task.mu -// runningTasksMu +// Kernel.extMu +// ThreadGroup.timerMu +// ktime.Timer.mu (for kernelCPUClockTicker and IntervalTimer) +// TaskSet.mu +// SignalHandlers.mu +// Task.mu +// runningTasksMu // // Locking SignalHandlers.mu in multiple SignalHandlers requires locking // TaskSet.mu exclusively first. Locking Task.mu in multiple Tasks at the same @@ -1132,8 +1132,8 @@ func (k *Kernel) Start() error { // pauseTimeLocked pauses all Timers and Timekeeper updates. // // Preconditions: -// * Any task goroutines running in k must be stopped. -// * k.extMu must be locked. +// - Any task goroutines running in k must be stopped. +// - k.extMu must be locked. func (k *Kernel) pauseTimeLocked(ctx context.Context) { // k.cpuClockTicker may be nil since Kernel.SaveTo() may be called before // Kernel.Start(). @@ -1177,8 +1177,8 @@ func (k *Kernel) pauseTimeLocked(ctx context.Context) { // effect. // // Preconditions: -// * Any task goroutines running in k must be stopped. -// * k.extMu must be locked. +// - Any task goroutines running in k must be stopped. +// - k.extMu must be locked. func (k *Kernel) resumeTimeLocked(ctx context.Context) { if k.cpuClockTicker != nil { k.cpuClockTicker.Resume() diff --git a/pkg/sentry/kernel/pipe/pipe.go b/pkg/sentry/kernel/pipe/pipe.go index 955f75097..fdf8e4792 100644 --- a/pkg/sentry/kernel/pipe/pipe.go +++ b/pkg/sentry/kernel/pipe/pipe.go @@ -246,8 +246,8 @@ func (p *Pipe) Open(ctx context.Context, d *fs.Dirent, flags fs.FileFlags) *fs.F // unlocked.) // // Preconditions: -// * p.mu must be locked. -// * This pipe must have readers. +// - p.mu must be locked. +// - This pipe must have readers. func (p *Pipe) peekLocked(count int64, f func(safemem.BlockSeq) (uint64, error)) (int64, error) { // Don't block for a zero-length read even if the pipe is empty. if count == 0 { @@ -277,8 +277,8 @@ func (p *Pipe) peekLocked(count int64, f func(safemem.BlockSeq) (uint64, error)) // longer be visible to future reads. // // Preconditions: -// * p.mu must be locked. -// * The pipe must contain at least n bytes. +// - p.mu must be locked. +// - The pipe must contain at least n bytes. func (p *Pipe) consumeLocked(n int64) { p.off += n if max := int64(len(p.buf)); p.off >= max { @@ -300,7 +300,7 @@ func (p *Pipe) consumeLocked(n int64) { // p.queue.Notify(waiter.ReadableEvents) with p.mu unlocked. // // Preconditions: -// * p.mu must be locked. +// - p.mu must be locked. func (p *Pipe) writeLocked(count int64, f func(safemem.BlockSeq) (uint64, error)) (int64, error) { // Can't write to a pipe with no readers. if !p.HasReaders() { diff --git a/pkg/sentry/kernel/ptrace.go b/pkg/sentry/kernel/ptrace.go index c9c434c4b..82d0562d9 100644 --- a/pkg/sentry/kernel/ptrace.go +++ b/pkg/sentry/kernel/ptrace.go @@ -179,12 +179,12 @@ func (t *Task) canTraceStandard(target *Task, attach bool) bool { // // 2. Deny access if neither of the following is true: // - // - The real, effective, and saved-set user IDs of the target match the - // caller's user ID, *and* the real, effective, and saved-set group IDs of - // the target match the caller's group ID. + // - The real, effective, and saved-set user IDs of the target match the + // caller's user ID, *and* the real, effective, and saved-set group IDs of + // the target match the caller's group ID. // - // - The caller has the CAP_SYS_PTRACE capability in the user namespace of - // the target. + // - The caller has the CAP_SYS_PTRACE capability in the user namespace of + // the target. // // 3. Deny access if the target process "dumpable" attribute has a value // other than 1 (SUID_DUMP_USER; see the discussion of PR_SET_DUMPABLE in @@ -199,12 +199,12 @@ func (t *Task) canTraceStandard(target *Task, attach bool) bool { // // b) Deny access if neither of the following is true: // - // - The caller and the target process are in the same user namespace, and - // the caller's capabilities are a proper superset of the target process's - // permitted capabilities. + // - The caller and the target process are in the same user namespace, and + // the caller's capabilities are a proper superset of the target process's + // permitted capabilities. // - // - The caller has the CAP_SYS_PTRACE capability in the target process's - // user namespace. + // - The caller has the CAP_SYS_PTRACE capability in the target process's + // user namespace. // // Note that the commoncap LSM does not distinguish between // PTRACE_MODE_READ and PTRACE_MODE_ATTACH. (ED: From earlier in this @@ -363,8 +363,8 @@ func (s *ptraceStop) Killable() bool { // waiting. // // Preconditions: -// * The TaskSet mutex must be locked. -// * The caller must be running on the task goroutine. +// - The TaskSet mutex must be locked. +// - The caller must be running on the task goroutine. func (t *Task) beginPtraceStopLocked() bool { t.tg.signalHandlers.mu.Lock() defer t.tg.signalHandlers.mu.Unlock() @@ -410,8 +410,8 @@ func (t *Task) ptraceTrapLocked(code int32) { // Task.Kill, and returns true. Otherwise it returns false. // // Preconditions: -// * The TaskSet mutex must be locked. -// * The caller must be running on the task goroutine of t's tracer. +// - The TaskSet mutex must be locked. +// - The caller must be running on the task goroutine of t's tracer. func (t *Task) ptraceFreeze() bool { t.tg.signalHandlers.mu.Lock() defer t.tg.signalHandlers.mu.Unlock() @@ -442,8 +442,8 @@ func (t *Task) ptraceUnfreeze() { } // Preconditions: -// * t must be in a frozen ptraceStop. -// * t's signal mutex must be locked. +// - t must be in a frozen ptraceStop. +// - t's signal mutex must be locked. func (t *Task) ptraceUnfreezeLocked() { // Do this even if the task has been killed to ensure a panic if t.stop is // nil or not a ptraceStop. @@ -648,8 +648,9 @@ func (t *Task) forgetTracerLocked() { // enter ptrace signal-delivery-stop. // // Preconditions: -// * The signal mutex must be locked. -// * The caller must be running on the task goroutine. +// - The signal mutex must be locked. +// - The caller must be running on the task goroutine. +// // +checklocks:t.tg.signalHandlers.mu func (t *Task) ptraceSignalLocked(info *linux.SignalInfo) bool { if linux.Signal(info.Signo) == linux.SIGKILL { @@ -981,8 +982,8 @@ func (t *Task) ptraceInterrupt(target *Task) error { } // Preconditions: -// * The TaskSet mutex must be locked for writing. -// * t must have a tracer. +// - The TaskSet mutex must be locked for writing. +// - t must have a tracer. func (t *Task) ptraceSetOptionsLocked(opts uintptr) error { const valid = uintptr(linux.PTRACE_O_EXITKILL | linux.PTRACE_O_TRACESYSGOOD | diff --git a/pkg/sentry/kernel/rseq.go b/pkg/sentry/kernel/rseq.go index de352f4f2..709b1f165 100644 --- a/pkg/sentry/kernel/rseq.go +++ b/pkg/sentry/kernel/rseq.go @@ -175,9 +175,9 @@ func (t *Task) OldRSeqCPUAddr() hostarch.Addr { // t's CPU number. // // Preconditions: -// * t.RSeqAvailable() == true. -// * The caller must be running on the task goroutine. -// * t's AddressSpace must be active. +// - t.RSeqAvailable() == true. +// - The caller must be running on the task goroutine. +// - t's AddressSpace must be active. func (t *Task) SetOldRSeqCPUAddr(addr hostarch.Addr) error { t.oldRSeqCPUAddr = addr @@ -193,8 +193,8 @@ func (t *Task) SetOldRSeqCPUAddr(addr hostarch.Addr) error { } // Preconditions: -// * The caller must be running on the task goroutine. -// * t's AddressSpace must be active. +// - The caller must be running on the task goroutine. +// - t's AddressSpace must be active. func (t *Task) rseqUpdateCPU() error { if t.rseqAddr == 0 && t.oldRSeqCPUAddr == 0 { t.rseqCPU = -1 @@ -214,8 +214,8 @@ func (t *Task) rseqUpdateCPU() error { } // Preconditions: -// * The caller must be running on the task goroutine. -// * t's AddressSpace must be active. +// - The caller must be running on the task goroutine. +// - t's AddressSpace must be active. func (t *Task) oldRSeqCopyOutCPU() error { if t.oldRSeqCPUAddr == 0 { return nil @@ -228,8 +228,8 @@ func (t *Task) oldRSeqCopyOutCPU() error { } // Preconditions: -// * The caller must be running on the task goroutine. -// * t's AddressSpace must be active. +// - The caller must be running on the task goroutine. +// - t's AddressSpace must be active. func (t *Task) rseqCopyOutCPU() error { if t.rseqAddr == 0 { return nil @@ -247,8 +247,8 @@ func (t *Task) rseqCopyOutCPU() error { } // Preconditions: -// * The caller must be running on the task goroutine. -// * t's AddressSpace must be active. +// - The caller must be running on the task goroutine. +// - t's AddressSpace must be active. func (t *Task) rseqClearCPU() error { buf := t.CopyScratchBuffer(8) // CPUIDStart and CPUID are the first two fields in linux.RSeq. @@ -266,19 +266,20 @@ func (t *Task) rseqClearCPU() error { // This is a bit complex since both the RSeq and RSeqCriticalSection structs // are stored in userspace. So we must: // -// 1. Copy in the address of RSeqCriticalSection from RSeq. -// 2. Copy in RSeqCriticalSection itself. -// 3. Validate critical section struct version, address range, abort address. -// 4. Validate the abort signature (4 bytes preceding abort IP match expected -// signature). +// 1. Copy in the address of RSeqCriticalSection from RSeq. +// 2. Copy in RSeqCriticalSection itself. +// 3. Validate critical section struct version, address range, abort address. +// 4. Validate the abort signature (4 bytes preceding abort IP match expected +// signature). +// // 5. Clear address of RSeqCriticalSection from RSeq. // 6. Finally, conditionally abort. // // See kernel/rseq.c:rseq_ip_fixup for reference. // // Preconditions: -// * The caller must be running on the task goroutine. -// * t's AddressSpace must be active. +// - The caller must be running on the task goroutine. +// - t's AddressSpace must be active. func (t *Task) rseqAddrInterrupt() { if t.rseqAddr == 0 { return diff --git a/pkg/sentry/kernel/shm/shm.go b/pkg/sentry/kernel/shm/shm.go index 26d88c48d..e70727b4c 100644 --- a/pkg/sentry/kernel/shm/shm.go +++ b/pkg/sentry/kernel/shm/shm.go @@ -16,19 +16,19 @@ // // Known missing features: // -// - SHM_LOCK/SHM_UNLOCK are no-ops. The sentry currently doesn't implement -// memory locking in general. +// - SHM_LOCK/SHM_UNLOCK are no-ops. The sentry currently doesn't implement +// memory locking in general. // -// - SHM_HUGETLB and related flags for shmget(2) are ignored. There's no easy -// way to implement hugetlb support on a per-map basis, and it has no impact -// on correctness. +// - SHM_HUGETLB and related flags for shmget(2) are ignored. There's no easy +// way to implement hugetlb support on a per-map basis, and it has no impact +// on correctness. // -// - SHM_NORESERVE for shmget(2) is ignored, the sentry doesn't implement swap -// so it's meaningless to reserve space for swap. +// - SHM_NORESERVE for shmget(2) is ignored, the sentry doesn't implement swap +// so it's meaningless to reserve space for swap. // -// - No per-process segment size enforcement. This feature probably isn't used -// much anyways, since Linux sets the per-process limits to the system-wide -// limits by default. +// - No per-process segment size enforcement. This feature probably isn't used +// much anyways, since Linux sets the per-process limits to the system-wide +// limits by default. // // Lock ordering: mm.mappingMu -> shm registry lock -> shm lock package shm diff --git a/pkg/sentry/kernel/task_block.go b/pkg/sentry/kernel/task_block.go index d321018c0..45d28d363 100644 --- a/pkg/sentry/kernel/task_block.go +++ b/pkg/sentry/kernel/task_block.go @@ -29,11 +29,11 @@ import ( // monotonic clock indicates that timeout has elapsed (only if haveTimeout is true), // or t is interrupted. It returns: // -// - The remaining timeout, which is guaranteed to be 0 if the timeout expired, -// and is unspecified if haveTimeout is false. +// - The remaining timeout, which is guaranteed to be 0 if the timeout expired, +// and is unspecified if haveTimeout is false. // -// - An error which is nil if an event is received from C, ETIMEDOUT if the timeout -// expired, and linuxerr.ErrInterrupted if t is interrupted. +// - An error which is nil if an event is received from C, ETIMEDOUT if the timeout +// expired, and linuxerr.ErrInterrupted if t is interrupted. // // Preconditions: The caller must be running on the task goroutine. func (t *Task) BlockWithTimeout(C chan struct{}, haveTimeout bool, timeout time.Duration) (time.Duration, error) { diff --git a/pkg/sentry/kernel/task_clone.go b/pkg/sentry/kernel/task_clone.go index 78e7a4bd2..e41862229 100644 --- a/pkg/sentry/kernel/task_clone.go +++ b/pkg/sentry/kernel/task_clone.go @@ -404,14 +404,14 @@ func (t *Task) Unshare(flags int32) error { // an error." - unshare(2). This is incorrect (cf. // kernel/fork.c:ksys_unshare()): // - // - CLONE_THREAD does not imply CLONE_VM. + // - CLONE_THREAD does not imply CLONE_VM. // - // - CLONE_SIGHAND implies CLONE_THREAD. + // - CLONE_SIGHAND implies CLONE_THREAD. // - // - Only CLONE_VM requires that the caller is not sharing its address - // space with another thread. CLONE_SIGHAND requires that the caller is not - // sharing its signal handlers, and CLONE_THREAD requires that the caller - // is the only thread in its thread group. + // - Only CLONE_VM requires that the caller is not sharing its address + // space with another thread. CLONE_SIGHAND requires that the caller is not + // sharing its signal handlers, and CLONE_THREAD requires that the caller + // is the only thread in its thread group. // // Since we don't count the number of tasks using each address space or set // of signal handlers, we reject CLONE_VM and CLONE_SIGHAND altogether. diff --git a/pkg/sentry/kernel/task_exec.go b/pkg/sentry/kernel/task_exec.go index ca44fbcc3..49dd0e4e3 100644 --- a/pkg/sentry/kernel/task_exec.go +++ b/pkg/sentry/kernel/task_exec.go @@ -186,14 +186,14 @@ func (r *runSyscallAfterExecStop) execute(t *Task) taskRunState { // // Details: // - // - If the thread group is sharing its signal handlers with another thread - // group via CLONE_SIGHAND, execve forces the signal handlers to be copied - // (see Linux's fs/exec.c:de_thread). We're not reference-counting signal - // handlers, so we always make a copy. + // - If the thread group is sharing its signal handlers with another thread + // group via CLONE_SIGHAND, execve forces the signal handlers to be copied + // (see Linux's fs/exec.c:de_thread). We're not reference-counting signal + // handlers, so we always make a copy. // - // - "Disposition" only means sigaction::sa_handler/sa_sigaction; flags, - // restorer (if present), and mask are always reset. (See Linux's - // fs/exec.c:setup_new_exec => kernel/signal.c:flush_signal_handlers.) + // - "Disposition" only means sigaction::sa_handler/sa_sigaction; flags, + // restorer (if present), and mask are always reset. (See Linux's + // fs/exec.c:setup_new_exec => kernel/signal.c:flush_signal_handlers.) t.tg.signalHandlers = t.tg.signalHandlers.CopyForExec() t.endStopCond.L = &t.tg.signalHandlers.mu // "Any alternate signal stack is not preserved (sigaltstack(2))." - execve(2) @@ -261,9 +261,9 @@ func (r *runSyscallAfterExecStop) execute(t *Task) taskRunState { // thread group leader, promoteLocked is a no-op. // // Preconditions: -// * All other tasks in t's thread group, including the existing leader (if it -// is not t), have reached TaskExitZombie. -// * The TaskSet mutex must be locked for writing. +// - All other tasks in t's thread group, including the existing leader (if it +// is not t), have reached TaskExitZombie. +// - The TaskSet mutex must be locked for writing. func (t *Task) promoteLocked() { oldLeader := t.tg.leader if t == oldLeader { diff --git a/pkg/sentry/kernel/task_exit.go b/pkg/sentry/kernel/task_exit.go index 50584c47c..b455e261b 100644 --- a/pkg/sentry/kernel/task_exit.go +++ b/pkg/sentry/kernel/task_exit.go @@ -16,13 +16,13 @@ package kernel // This file implements the task exit cycle: // -// - Tasks are asynchronously requested to exit with Task.Kill. +// - Tasks are asynchronously requested to exit with Task.Kill. // -// - When able, the task goroutine enters the exit path starting from state -// runExit. +// - When able, the task goroutine enters the exit path starting from state +// runExit. // -// - Other tasks observe completed exits with Task.Wait (which implements the -// wait*() family of syscalls). +// - Other tasks observe completed exits with Task.Wait (which implements the +// wait*() family of syscalls). import ( "errors" @@ -454,24 +454,24 @@ func (t *Task) reparentLocked(parent *Task) { // // There are a few ways for an exit notification to be resolved: // -// - The exit notification may be acknowledged by a call to Task.Wait with -// WaitOptions.ConsumeEvent set (e.g. due to a wait4() syscall). +// - The exit notification may be acknowledged by a call to Task.Wait with +// WaitOptions.ConsumeEvent set (e.g. due to a wait4() syscall). // -// - If the notified party is the parent, and the parent thread group is not -// also the tracer thread group, and the notification signal is SIGCHLD, the -// parent may explicitly ignore the notification (see quote in exitNotify). -// Note that it's possible for the notified party to ignore the signal in other -// cases, but the notification is only resolved under the above conditions. -// (Actually, there is one exception; see the last paragraph of the "leader, -// has tracer, tracer thread group is parent thread group" case below.) +// - If the notified party is the parent, and the parent thread group is not +// also the tracer thread group, and the notification signal is SIGCHLD, the +// parent may explicitly ignore the notification (see quote in exitNotify). +// Note that it's possible for the notified party to ignore the signal in other +// cases, but the notification is only resolved under the above conditions. +// (Actually, there is one exception; see the last paragraph of the "leader, +// has tracer, tracer thread group is parent thread group" case below.) // -// - If the notified party is the parent, and the parent does not exist, the -// notification is resolved as if ignored. (This is only possible in the -// sentry. In Linux, the only task / thread group without a parent is global -// init, and killing global init causes a kernel panic.) +// - If the notified party is the parent, and the parent does not exist, the +// notification is resolved as if ignored. (This is only possible in the +// sentry. In Linux, the only task / thread group without a parent is global +// init, and killing global init causes a kernel panic.) // -// - If the notified party is a tracer, the tracer may detach the traced task. -// (Zombie tasks cannot be ptrace-attached, so the reverse is not possible.) +// - If the notified party is a tracer, the tracer may detach the traced task. +// (Zombie tasks cannot be ptrace-attached, so the reverse is not possible.) // // In addition, if the notified party is the parent, the parent may exit and // cause the notifying task to be reparented to another thread group. This does @@ -482,23 +482,23 @@ func (t *Task) reparentLocked(parent *Task) { // whether it is a thread group leader; whether the task is ptraced; and, if // so, whether the tracer thread group is the same as the parent thread group. // -// - Non-leader, no tracer: No notification is generated; the task is reaped -// immediately. +// - Non-leader, no tracer: No notification is generated; the task is reaped +// immediately. // -// - Non-leader, has tracer: SIGCHLD is sent to the tracer. When the tracer -// notification is resolved (by waiting or detaching), the task is reaped. (For -// non-leaders, whether the tracer and parent thread groups are the same is -// irrelevant.) +// - Non-leader, has tracer: SIGCHLD is sent to the tracer. When the tracer +// notification is resolved (by waiting or detaching), the task is reaped. (For +// non-leaders, whether the tracer and parent thread groups are the same is +// irrelevant.) // -// - Leader, no tracer: The task remains a zombie, with no notification sent, -// until all other tasks in the thread group are dead. (In Linux terms, this -// condition is indicated by include/linux/sched.h:thread_group_empty(); tasks -// are removed from their thread_group list in kernel/exit.c:release_task() => -// __exit_signal() => __unhash_process().) Then the thread group's termination -// signal is sent to the parent. When the parent notification is resolved (by -// waiting or ignoring), the task is reaped. +// - Leader, no tracer: The task remains a zombie, with no notification sent, +// until all other tasks in the thread group are dead. (In Linux terms, this +// condition is indicated by include/linux/sched.h:thread_group_empty(); tasks +// are removed from their thread_group list in kernel/exit.c:release_task() => +// __exit_signal() => __unhash_process().) Then the thread group's termination +// signal is sent to the parent. When the parent notification is resolved (by +// waiting or ignoring), the task is reaped. // -// - Leader, has tracer, tracer thread group is not parent thread group: +// - Leader, has tracer, tracer thread group is not parent thread group: // SIGCHLD is sent to the tracer. When the tracer notification is resolved (by // waiting or detaching), and all other tasks in the thread group are dead, the // thread group's termination signal is sent to the parent. (Note that the @@ -506,7 +506,7 @@ func (t *Task) reparentLocked(parent *Task) { // group is empty.) When the parent notification is resolved, the task is // reaped. // -// - Leader, has tracer, tracer thread group is parent thread group: +// - Leader, has tracer, tracer thread group is parent thread group: // // If all other tasks in the thread group are dead, the thread group's // termination signal is sent to the parent. At this point, the notification @@ -634,11 +634,11 @@ func (t *Task) exitNotifyLocked(fromPtraceDetach bool) { // // Some undocumented Linux-specific details: // - // - All of the above is ignored if the termination signal isn't - // SIGCHLD. + // - All of the above is ignored if the termination signal isn't + // SIGCHLD. // - // - SA_NOCLDWAIT causes the leader to be immediately reaped, but - // does not suppress the SIGCHLD. + // - SA_NOCLDWAIT causes the leader to be immediately reaped, but + // does not suppress the SIGCHLD. signalParent := t.tg.terminationSignal.IsValid() t.parent.tg.signalHandlers.mu.Lock() if t.tg.terminationSignal == linux.SIGCHLD || fromPtraceDetach { diff --git a/pkg/sentry/kernel/task_identity.go b/pkg/sentry/kernel/task_identity.go index a9067b682..1de90ea97 100644 --- a/pkg/sentry/kernel/task_identity.go +++ b/pkg/sentry/kernel/task_identity.go @@ -461,20 +461,20 @@ func (t *Task) SetKeepCaps(k bool) { // (set-user/group-ID bits and file capabilities). This allows us to make a lot // of simplifying assumptions: // -// - We assume the no_new_privs bit (set by prctl(SET_NO_NEW_PRIVS)), which -// disables the features we don't support anyway, is always set. This -// drastically simplifies this function. +// - We assume the no_new_privs bit (set by prctl(SET_NO_NEW_PRIVS)), which +// disables the features we don't support anyway, is always set. This +// drastically simplifies this function. // -// - We don't set AT_SECURE = 1, because no_new_privs always being set means -// that the conditions that require AT_SECURE = 1 never arise. (Compare Linux's -// security/commoncap.c:cap_bprm_set_creds() and cap_bprm_secureexec().) +// - We don't set AT_SECURE = 1, because no_new_privs always being set means +// that the conditions that require AT_SECURE = 1 never arise. (Compare Linux's +// security/commoncap.c:cap_bprm_set_creds() and cap_bprm_secureexec().) // -// - We don't check for CAP_SYS_ADMIN in prctl(PR_SET_SECCOMP), since -// seccomp-bpf is also allowed if the task has no_new_privs set. +// - We don't check for CAP_SYS_ADMIN in prctl(PR_SET_SECCOMP), since +// seccomp-bpf is also allowed if the task has no_new_privs set. // -// - Task.ptraceAttach does not serialize with execve as it does in Linux, -// since no_new_privs being set has the same effect as the presence of an -// unprivileged tracer. +// - Task.ptraceAttach does not serialize with execve as it does in Linux, +// since no_new_privs being set has the same effect as the presence of an +// unprivileged tracer. // // Preconditions: t.mu must be locked. func (t *Task) updateCredsForExecLocked() { diff --git a/pkg/sentry/kernel/task_run.go b/pkg/sentry/kernel/task_run.go index 628c64225..0905ce03d 100644 --- a/pkg/sentry/kernel/task_run.go +++ b/pkg/sentry/kernel/task_run.go @@ -78,14 +78,14 @@ func (t *Task) run() { for { // Explanation for this ordering: // - // - A freshly-started task that is stopped should not do anything - // before it enters the stop. + // - A freshly-started task that is stopped should not do anything + // before it enters the stop. // - // - If taskRunState.execute returns nil, the task goroutine should - // exit without checking for a stop. + // - If taskRunState.execute returns nil, the task goroutine should + // exit without checking for a stop. // - // - Task.Start won't start Task.run if t.runState is nil, so this - // ordering is safe. + // - Task.Start won't start Task.run if t.runState is nil, so this + // ordering is safe. t.doStop() t.runState = t.runState.execute(t) if t.runState == nil { diff --git a/pkg/sentry/kernel/task_sched.go b/pkg/sentry/kernel/task_sched.go index 4cfc46ed7..36d54089f 100644 --- a/pkg/sentry/kernel/task_sched.go +++ b/pkg/sentry/kernel/task_sched.go @@ -133,9 +133,9 @@ func (t *Task) accountTaskGoroutineEnter(state TaskGoroutineState) { } // Preconditions: -// * The caller must be running on the task goroutine -// * The caller must be leaving a state indicated by a previous call to -// t.accountTaskGoroutineEnter(state). +// - The caller must be running on the task goroutine +// - The caller must be leaving a state indicated by a previous call to +// t.accountTaskGoroutineEnter(state). func (t *Task) accountTaskGoroutineLeave(state TaskGoroutineState) { if state != TaskGoroutineRunningApp { // Task is unblocking/continuing. @@ -204,7 +204,7 @@ func (tg *ThreadGroup) CPUStats() usage.CPUStats { } // Preconditions: Same as TaskGoroutineSchedInfo.userTicksAt, plus: -// * The TaskSet mutex must be locked. +// - The TaskSet mutex must be locked. func (tg *ThreadGroup) cpuStatsAtLocked(now uint64) usage.CPUStats { stats := tg.exitedCPUStats // Account for live tasks. diff --git a/pkg/sentry/kernel/task_signals.go b/pkg/sentry/kernel/task_signals.go index b2639a0e1..33c000ac5 100644 --- a/pkg/sentry/kernel/task_signals.go +++ b/pkg/sentry/kernel/task_signals.go @@ -324,8 +324,8 @@ func (t *Task) SignalReturn(rt bool) (*SyscallControl, error) { // Sigtimedwait implements the semantics of sigtimedwait(2). // // Preconditions: -// * The caller must be running on the task goroutine. -// * t.exitState < TaskExitZombie. +// - The caller must be running on the task goroutine. +// - t.exitState < TaskExitZombie. func (t *Task) Sigtimedwait(set linux.SignalSet, timeout time.Duration) (*linux.SignalInfo, error) { // set is the set of signals we're interested in; invert it to get the set // of signals to block. @@ -372,7 +372,6 @@ func (t *Task) Sigtimedwait(set linux.SignalSet, timeout time.Duration) (*linux. // linuxerr.ESRCH - The task has exited. // linuxerr.EINVAL - The signal is not valid. // linuxerr.EAGAIN - THe signal is realtime, and cannot be queued. -// func (t *Task) SendSignal(info *linux.SignalInfo) error { t.tg.pidns.owner.mu.RLock() defer t.tg.pidns.owner.mu.RUnlock() @@ -522,20 +521,20 @@ func (t *Task) canReceiveSignalLocked(sig linux.Signal) bool { // Notify that the signal is queued. t.signalQueue.Notify(waiter.EventMask(linux.MakeSignalSet(sig))) - // - Do not choose tasks that are blocking the signal. + // - Do not choose tasks that are blocking the signal. if linux.SignalSetOf(sig)&linux.SignalSet(t.signalMask.RacyLoad()) != 0 { return false } - // - No need to check Task.exitState, as the exit path sets every bit in the - // signal mask when it transitions from TaskExitNone to TaskExitInitiated. - // - No special case for SIGKILL: SIGKILL already interrupted all tasks in the - // task group via applySignalSideEffects => killLocked. - // - Do not choose stopped tasks, which cannot handle signals. + // - No need to check Task.exitState, as the exit path sets every bit in the + // signal mask when it transitions from TaskExitNone to TaskExitInitiated. + // - No special case for SIGKILL: SIGKILL already interrupted all tasks in the + // task group via applySignalSideEffects => killLocked. + // - Do not choose stopped tasks, which cannot handle signals. if t.stop != nil { return false } - // - Do not choose tasks that have already been interrupted, as they may be - // busy handling another signal. + // - Do not choose tasks that have already been interrupted, as they may be + // busy handling another signal. if len(t.interruptChan) != 0 { return false } @@ -590,8 +589,8 @@ func (t *Task) SignalMask() linux.SignalSet { // SetSignalMask sets t's signal mask. // // Preconditions: -// * The caller must be running on the task goroutine. -// * t.exitState < TaskExitZombie. +// - The caller must be running on the task goroutine. +// - t.exitState < TaskExitZombie. func (t *Task) SetSignalMask(mask linux.SignalSet) { // By precondition, t prevents t.tg from completing an execve and mutating // t.tg.signalHandlers, so we can skip the TaskSet mutex. diff --git a/pkg/sentry/kernel/task_stop.go b/pkg/sentry/kernel/task_stop.go index 7068431d4..44b4ff102 100644 --- a/pkg/sentry/kernel/task_stop.go +++ b/pkg/sentry/kernel/task_stop.go @@ -23,12 +23,12 @@ package kernel // There are multiple interfaces for interacting with stops because there are // multiple cases to consider: // -// - A task goroutine can begin a stop on its associated task (e.g. a -// vfork() syscall stopping the calling task until the child task releases its -// MM). In this case, calling Task.interrupt is both unnecessary (the task -// goroutine obviously cannot be blocked in Task.block or executing application -// code) and undesirable (as it may spuriously interrupt a in-progress -// syscall). +// - A task goroutine can begin a stop on its associated task (e.g. a +// vfork() syscall stopping the calling task until the child task releases its +// MM). In this case, calling Task.interrupt is both unnecessary (the task +// goroutine obviously cannot be blocked in Task.block or executing application +// code) and undesirable (as it may spuriously interrupt a in-progress +// syscall). // // Beginning internal stops in this case is implemented by // Task.beginInternalStop / Task.beginInternalStopLocked. As of this writing, @@ -36,30 +36,30 @@ package kernel // autosave; however, autosave terminates the sentry without ending the // external stop, so the spurious interrupt is moot. // -// - An arbitrary goroutine can begin a stop on an unrelated task (e.g. all -// tasks being stopped in preparation for state checkpointing). If the task -// goroutine may be in Task.block or executing application code, it must be -// interrupted by Task.interrupt for it to actually enter the stop; since, -// strictly speaking, we have no way of determining this, we call -// Task.interrupt unconditionally. +// - An arbitrary goroutine can begin a stop on an unrelated task (e.g. all +// tasks being stopped in preparation for state checkpointing). If the task +// goroutine may be in Task.block or executing application code, it must be +// interrupted by Task.interrupt for it to actually enter the stop; since, +// strictly speaking, we have no way of determining this, we call +// Task.interrupt unconditionally. // // Beginning external stops in this case is implemented by // Task.BeginExternalStop. As of this writing, there are no instances of this // case that begin internal stops. // -// - An arbitrary goroutine can end a stop on an unrelated task (e.g. an -// exiting task resuming a sibling task that has been blocked in an execve() -// syscall waiting for other tasks to exit). In this case, Task.endStopCond -// must be notified to kick the task goroutine out of Task.doStop. +// - An arbitrary goroutine can end a stop on an unrelated task (e.g. an +// exiting task resuming a sibling task that has been blocked in an execve() +// syscall waiting for other tasks to exit). In this case, Task.endStopCond +// must be notified to kick the task goroutine out of Task.doStop. // // Ending internal stops in this case is implemented by // Task.endInternalStopLocked. Ending external stops in this case is // implemented by Task.EndExternalStop. // -// - Hypothetically, a task goroutine can end an internal stop on its -// associated task. As of this writing, there are no instances of this case. -// However, any instances of this case could still use the above functions, -// since notifying Task.endStopCond would be unnecessary but harmless. +// - Hypothetically, a task goroutine can end an internal stop on its +// associated task. As of this writing, there are no instances of this case. +// However, any instances of this case could still use the above functions, +// since notifying Task.endStopCond would be unnecessary but harmless. import ( "fmt" @@ -72,10 +72,10 @@ import ( // distinguished by their type. The obvious way to implement such a TaskStop // is: // -// type groupStop struct{} -// func (groupStop) Killable() bool { return true } -// ... -// t.beginInternalStop(groupStop{}) +// type groupStop struct{} +// func (groupStop) Killable() bool { return true } +// ... +// t.beginInternalStop(groupStop{}) // // However, this doesn't work because the state package can't serialize values, // only pointers. Furthermore, the correctness of save/restore depends on the @@ -84,10 +84,10 @@ import ( // occurred between the two. As a result, the current idiom is to always use a // typecast nil for data-free TaskStops: // -// type groupStop struct{} -// func (*groupStop) Killable() bool { return true } -// ... -// t.beginInternalStop((*groupStop)(nil)) +// type groupStop struct{} +// func (*groupStop) Killable() bool { return true } +// ... +// t.beginInternalStop((*groupStop)(nil)) // // This is pretty gross, but the alternatives seem grosser. type TaskStop interface { @@ -99,8 +99,8 @@ type TaskStop interface { // beginInternalStop indicates the start of an internal stop that applies to t. // // Preconditions: -// * The caller must be running on the task goroutine. -// * The task must not already be in an internal stop (i.e. t.stop == nil). +// - The caller must be running on the task goroutine. +// - The task must not already be in an internal stop (i.e. t.stop == nil). func (t *Task) beginInternalStop(s TaskStop) { t.tg.pidns.owner.mu.RLock() defer t.tg.pidns.owner.mu.RUnlock() @@ -110,7 +110,7 @@ func (t *Task) beginInternalStop(s TaskStop) { } // Preconditions: Same as beginInternalStop, plus: -// * The signal mutex must be locked. +// - The signal mutex must be locked. func (t *Task) beginInternalStopLocked(s TaskStop) { if t.stop != nil { panic(fmt.Sprintf("Attempting to enter internal stop %#v when already in internal stop %#v", s, t.stop)) @@ -129,8 +129,8 @@ func (t *Task) beginInternalStopLocked(s TaskStop) { // for you. // // Preconditions: -// * The signal mutex must be locked. -// * The task must be in an internal stop (i.e. t.stop != nil). +// - The signal mutex must be locked. +// - The task must be in an internal stop (i.e. t.stop != nil). func (t *Task) endInternalStopLocked() { if t.stop == nil { panic("Attempting to leave non-existent internal stop") diff --git a/pkg/sentry/kernel/task_usermem.go b/pkg/sentry/kernel/task_usermem.go index bff226a11..4df472613 100644 --- a/pkg/sentry/kernel/task_usermem.go +++ b/pkg/sentry/kernel/task_usermem.go @@ -87,8 +87,8 @@ func (t *Task) CopyInString(addr hostarch.Addr, maxlen int) (string, error) { // number of elements. For example, the following strings correspond to // the following set of sizes: // -// { "a", "b", "c" } => 6 (3 for lengths, 3 for elements) -// { "abc" } => 4 (3 for length, 1 for elements) +// { "a", "b", "c" } => 6 (3 for lengths, 3 for elements) +// { "abc" } => 4 (3 for length, 1 for elements) // // This Task's AddressSpace must be active. func (t *Task) CopyInVector(addr hostarch.Addr, maxElemSize, maxTotalSize int) ([]string, error) { @@ -125,8 +125,8 @@ func (t *Task) CopyInVector(addr hostarch.Addr, maxElemSize, maxTotalSize int) ( // memory mapped at addr. // // Preconditions: Same as usermem.IO.CopyOut, plus: -// * The caller must be running on the task goroutine. -// * t's AddressSpace must be active. +// - The caller must be running on the task goroutine. +// - t's AddressSpace must be active. func (t *Task) CopyOutIovecs(addr hostarch.Addr, src hostarch.AddrRangeSeq) error { switch t.Arch().Width() { case 8: @@ -160,22 +160,22 @@ func (t *Task) CopyOutIovecs(addr hostarch.Addr, src hostarch.AddrRangeSeq) erro // CopyInIovecs shares the following properties with Linux's // lib/iov_iter.c:import_iovec() => fs/read_write.c:rw_copy_check_uvector(): // -// - If the length of any AddrRange would exceed the range of an ssize_t, -// CopyInIovecs returns EINVAL. +// - If the length of any AddrRange would exceed the range of an ssize_t, +// CopyInIovecs returns EINVAL. // -// - If the length of any AddrRange would cause its end to overflow, -// CopyInIovecs returns EFAULT. +// - If the length of any AddrRange would cause its end to overflow, +// CopyInIovecs returns EFAULT. // -// - If any AddrRange would include addresses outside the application address -// range, CopyInIovecs returns EFAULT. +// - If any AddrRange would include addresses outside the application address +// range, CopyInIovecs returns EFAULT. // -// - The combined length of all AddrRanges is limited to MAX_RW_COUNT. If the -// combined length of all AddrRanges would otherwise exceed this amount, ranges -// beyond MAX_RW_COUNT are silently truncated. +// - The combined length of all AddrRanges is limited to MAX_RW_COUNT. If the +// combined length of all AddrRanges would otherwise exceed this amount, ranges +// beyond MAX_RW_COUNT are silently truncated. // // Preconditions: Same as usermem.IO.CopyIn, plus: -// * The caller must be running on the task goroutine. -// * t's AddressSpace must be active. +// - The caller must be running on the task goroutine. +// - t's AddressSpace must be active. func (t *Task) CopyInIovecs(addr hostarch.Addr, numIovecs int) (hostarch.AddrRangeSeq, error) { if numIovecs == 0 { return hostarch.AddrRangeSeq{}, nil diff --git a/pkg/sentry/kernel/thread_group.go b/pkg/sentry/kernel/thread_group.go index 48a58f10f..f1a55f25f 100644 --- a/pkg/sentry/kernel/thread_group.go +++ b/pkg/sentry/kernel/thread_group.go @@ -112,13 +112,13 @@ type ThreadGroup struct { // // Analogues in Linux: // - // - groupContNotify && groupContInterrupted is represented by - // SIGNAL_CLD_STOPPED. + // - groupContNotify && groupContInterrupted is represented by + // SIGNAL_CLD_STOPPED. // - // - groupContNotify && !groupContInterrupted is represented by - // SIGNAL_CLD_CONTINUED. + // - groupContNotify && !groupContInterrupted is represented by + // SIGNAL_CLD_CONTINUED. // - // - !groupContNotify is represented by neither flag being set. + // - !groupContNotify is represented by neither flag being set. // // groupContNotify and groupContInterrupted are protected by the signal // mutex. @@ -208,11 +208,11 @@ type ThreadGroup struct { // maxRSS is the historical maximum resident set size of the thread group, updated when: // - // - A task in the thread group exits, since after all tasks have - // exited the MemoryManager is no longer reachable. + // - A task in the thread group exits, since after all tasks have + // exited the MemoryManager is no longer reachable. // - // - The thread group completes an execve, since this changes - // MemoryManagers. + // - The thread group completes an execve, since this changes + // MemoryManagers. // // maxRSS is protected by the TaskSet mutex. maxRSS uint64 @@ -375,11 +375,11 @@ func (tg *ThreadGroup) SetControllingTTY(tty *TTY, steal bool, isReadable bool) for othertg := range tg.pidns.owner.Root.tgids { // This won't deadlock by locking tg.signalHandlers // because at this point: - // - We only lock signalHandlers if it's in the same - // session as the tty's controlling thread group. - // - We know that the calling thread group is not in - // the same session as the tty's controlling thread - // group. + // - We only lock signalHandlers if it's in the same + // session as the tty's controlling thread group. + // - We know that the calling thread group is not in + // the same session as the tty's controlling thread + // group. if othertg.processGroup.session == tty.tg.processGroup.session { othertg.signalHandlers.mu.Lock() othertg.tty = nil diff --git a/pkg/sentry/kernel/time/time.go b/pkg/sentry/kernel/time/time.go index a4a0c4767..fa40508de 100644 --- a/pkg/sentry/kernel/time/time.go +++ b/pkg/sentry/kernel/time/time.go @@ -609,9 +609,9 @@ func (t *Timer) Swap(s Setting) (Time, Setting) { // starts the timer, while setting s.Enabled to false stops it. // // Preconditions: -// * The Timer must not be paused. -// * f cannot call any Timer methods since it is called with the Timer mutex -// locked. +// - The Timer must not be paused. +// - f cannot call any Timer methods since it is called with the Timer mutex +// locked. func (t *Timer) SwapAnd(s Setting, f func()) (Time, Setting) { now := t.clock.Now() t.mu.Lock() diff --git a/pkg/sentry/kernel/vdso.go b/pkg/sentry/kernel/vdso.go index cc0917504..7011f60fd 100644 --- a/pkg/sentry/kernel/vdso.go +++ b/pkg/sentry/kernel/vdso.go @@ -45,11 +45,11 @@ type vdsoParams struct { // // Its memory layout looks like: // -// type page struct { -// // seq is a sequence counter that protects the fields below. -// seq uint64 -// vdsoParams -// } +// type page struct { +// // seq is a sequence counter that protects the fields below. +// seq uint64 +// vdsoParams +// } // // Everything in the struct is 8 bytes for easy alignment. // @@ -81,11 +81,11 @@ type VDSOParamPage struct { // NewVDSOParamPage returns a VDSOParamPage. // // Preconditions: -// * fr is a single page allocated from mfp.MemoryFile(). VDSOParamPage does -// not take ownership of fr; it must remain allocated for the lifetime of the -// VDSOParamPage. -// * VDSOParamPage must be the only writer to fr. -// * mfp.MemoryFile().MapInternal(fr) must return a single safemem.Block. +// - fr is a single page allocated from mfp.MemoryFile(). VDSOParamPage does +// not take ownership of fr; it must remain allocated for the lifetime of the +// VDSOParamPage. +// - VDSOParamPage must be the only writer to fr. +// - mfp.MemoryFile().MapInternal(fr) must return a single safemem.Block. func NewVDSOParamPage(mfp pgalloc.MemoryFileProvider, fr memmap.FileRange) *VDSOParamPage { return &VDSOParamPage{ mfp: mfp, diff --git a/pkg/sentry/kernel/version.go b/pkg/sentry/kernel/version.go index 5640dd71d..678ef9e27 100644 --- a/pkg/sentry/kernel/version.go +++ b/pkg/sentry/kernel/version.go @@ -25,9 +25,9 @@ type Version struct { // Operating system version. On Linux this takes the shape // "#VERSION CONFIG_FLAGS TIMESTAMP" // where: - // - VERSION is a sequence counter incremented on every successful build - // - CONFIG_FLAGS is a space-separated list of major enabled kernel features - // (e.g. "SMP" and "PREEMPT") - // - TIMESTAMP is the build timestamp as returned by `date` + // - VERSION is a sequence counter incremented on every successful build + // - CONFIG_FLAGS is a space-separated list of major enabled kernel features + // (e.g. "SMP" and "PREEMPT") + // - TIMESTAMP is the build timestamp as returned by `date` Version string } diff --git a/pkg/sentry/loader/elf.go b/pkg/sentry/loader/elf.go index f5b066ca3..d41254c13 100644 --- a/pkg/sentry/loader/elf.go +++ b/pkg/sentry/loader/elf.go @@ -390,11 +390,11 @@ type loadedELF struct { phdrNum int // auxv contains a subset of ELF-specific auxiliary vector entries: - // * AT_PHDR - // * AT_PHENT - // * AT_PHNUM - // * AT_BASE - // * AT_ENTRY + // * AT_PHDR + // * AT_PHENT + // * AT_PHNUM + // * AT_BASE + // * AT_ENTRY auxv arch.Auxv } @@ -578,8 +578,8 @@ func loadParsedELF(ctx context.Context, m *mm.MemoryManager, f fsbridge.File, in // It does not load the ELF interpreter, or return any auxv entries. // // Preconditions: -// * f is an ELF file. -// * f is the first ELF loaded into m. +// - f is an ELF file. +// - f is the first ELF loaded into m. func loadInitialELF(ctx context.Context, m *mm.MemoryManager, fs cpuid.FeatureSet, f fsbridge.File) (loadedELF, arch.Context, error) { info, err := parseHeader(ctx, f) if err != nil { diff --git a/pkg/sentry/loader/loader.go b/pkg/sentry/loader/loader.go index 4c329116b..20719b51d 100644 --- a/pkg/sentry/loader/loader.go +++ b/pkg/sentry/loader/loader.go @@ -153,10 +153,10 @@ const ( // interpreter will be loaded. // // It returns: -// * loadedELF, description of the loaded binary -// * arch.Context matching the binary arch -// * fs.Dirent of the binary file -// * Possibly updated args.Argv +// - loadedELF, description of the loaded binary +// - arch.Context matching the binary arch +// - fs.Dirent of the binary file +// - Possibly updated args.Argv func loadExecutable(ctx context.Context, args LoadArgs) (loadedELF, arch.Context, fsbridge.File, []string, error) { for i := 0; i < maxLoaderAttempts; i++ { if args.File == nil { @@ -228,8 +228,8 @@ func loadExecutable(ctx context.Context, args LoadArgs) (loadedELF, arch.Context // path and argv. // // Preconditions: -// * The Task MemoryManager is empty. -// * Load is called on the Task goroutine. +// - The Task MemoryManager is empty. +// - Load is called on the Task goroutine. func Load(ctx context.Context, args LoadArgs, extraAuxv []arch.AuxEntry, vdso *VDSO) (abi.OS, arch.Context, string, *syserr.Error) { // Load the executable itself. loaded, ac, file, newArgv, err := loadExecutable(ctx, args) diff --git a/pkg/sentry/loader/vdso.go b/pkg/sentry/loader/vdso.go index 80b238709..1abb5141d 100644 --- a/pkg/sentry/loader/vdso.go +++ b/pkg/sentry/loader/vdso.go @@ -73,12 +73,12 @@ func (b *byteFullReader) ReadFull(ctx context.Context, dst usermem.IOSequence, o // segments have the same layout in the ELF as they expect to have in memory. // // Namely, this means that we must verify: -// * PT_LOAD file offsets are equivalent to the memory offset from the first -// segment. -// * No extra zeroed space (memsz) is required. -// * PT_LOAD segments are in order. -// * No two PT_LOAD segments occupy parts of the same page. -// * PT_LOAD segments don't extend beyond the end of the file. +// - PT_LOAD file offsets are equivalent to the memory offset from the first +// segment. +// - No extra zeroed space (memsz) is required. +// - PT_LOAD segments are in order. +// - No two PT_LOAD segments occupy parts of the same page. +// - PT_LOAD segments don't extend beyond the end of the file. // // ctx may be nil if f does not need it. func validateVDSO(ctx context.Context, f fullReader, size uint64) (elfInfo, error) { diff --git a/pkg/sentry/memmap/memmap.go b/pkg/sentry/memmap/memmap.go index 610686ea0..f433f3829 100644 --- a/pkg/sentry/memmap/memmap.go +++ b/pkg/sentry/memmap/memmap.go @@ -29,8 +29,8 @@ import ( // See mm/mm.go for Mappable's place in the lock order. // // All Mappable methods have the following preconditions: -// * hostarch.AddrRanges and MappableRanges must be non-empty (Length() != 0). -// * hostarch.Addrs and Mappable offsets must be page-aligned. +// - hostarch.AddrRanges and MappableRanges must be non-empty (Length() != 0). +// - hostarch.Addrs and Mappable offsets must be page-aligned. type Mappable interface { // AddMapping notifies the Mappable of a mapping from addresses ar in ms to // offsets [offset, offset+ar.Length()) in this Mappable. @@ -49,9 +49,9 @@ type Mappable interface { // Mappable. // // Preconditions: - // * offset+ar.Length() does not overflow. - // * The removed mapping must exist. writable must match the - // corresponding call to AddMapping. + // * offset+ar.Length() does not overflow. + // * The removed mapping must exist. writable must match the + // corresponding call to AddMapping. RemoveMapping(ctx context.Context, ms MappingSpace, ar hostarch.AddrRange, offset uint64, writable bool) // CopyMapping notifies the Mappable of an attempt to copy a mapping in ms @@ -63,9 +63,9 @@ type Mappable interface { // MappingSpace; it is analogous to Linux's vm_operations_struct::mremap. // // Preconditions: - // * offset+srcAR.Length() and offset+dstAR.Length() do not overflow. - // * The mapping at srcAR must exist. writable must match the - // corresponding call to AddMapping. + // * offset+srcAR.Length() and offset+dstAR.Length() do not overflow. + // * The mapping at srcAR must exist. writable must match the + // corresponding call to AddMapping. CopyMapping(ctx context.Context, ms MappingSpace, srcAR, dstAR hostarch.AddrRange, offset uint64, writable bool) error // Translate returns the Mappable's current mappings for at least the range @@ -81,13 +81,13 @@ type Mappable interface { // of a valid Translation. // // Preconditions: - // * required.Length() > 0. - // * optional.IsSupersetOf(required). - // * required and optional must be page-aligned. - // * The caller must have established a mapping for all of the queried - // offsets via a previous call to AddMapping. - // * The caller is responsible for ensuring that calls to Translate - // synchronize with invalidation. + // * required.Length() > 0. + // * optional.IsSupersetOf(required). + // * required and optional must be page-aligned. + // * The caller must have established a mapping for all of the queried + // offsets via a previous call to AddMapping. + // * The caller is responsible for ensuring that calls to Translate + // synchronize with invalidation. // // Postconditions: See CheckTranslateResult. Translate(ctx context.Context, required, optional MappableRange, at hostarch.AccessType) ([]Translation, error) @@ -221,8 +221,8 @@ type MappingSpace interface { // in the lock order. // // Preconditions: - // * ar.Length() != 0. - // * ar must be page-aligned. + // * ar.Length() != 0. + // * ar must be page-aligned. Invalidate(ar hostarch.AddrRange, opts InvalidateOpts) } @@ -389,19 +389,19 @@ type File interface { // IncRef increments the reference count on all pages in fr. // // Preconditions: - // * fr.Start and fr.End must be page-aligned. - // * fr.Length() > 0. - // * At least one reference must be held on all pages in fr. (The File - // interface does not provide a way to acquire an initial reference; - // implementors may define mechanisms for doing so.) + // * fr.Start and fr.End must be page-aligned. + // * fr.Length() > 0. + // * At least one reference must be held on all pages in fr. (The File + // interface does not provide a way to acquire an initial reference; + // implementors may define mechanisms for doing so.) IncRef(fr FileRange) // DecRef decrements the reference count on all pages in fr. // // Preconditions: - // * fr.Start and fr.End must be page-aligned. - // * fr.Length() > 0. - // * At least one reference must be held on all pages in fr. + // * fr.Start and fr.End must be page-aligned. + // * fr.Length() > 0. + // * At least one reference must be held on all pages in fr. DecRef(fr FileRange) // MapInternal returns a mapping of the given file offsets in the invoking @@ -410,8 +410,8 @@ type File interface { // Note that fr.Start and fr.End need not be page-aligned. // // Preconditions: - // * fr.Length() > 0. - // * At least one reference must be held on all pages in fr. + // * fr.Length() > 0. + // * At least one reference must be held on all pages in fr. // // Postconditions: The returned mapping is valid as long as at least one // reference is held on the mapped pages. diff --git a/pkg/sentry/mm/address_space.go b/pkg/sentry/mm/address_space.go index 168b267b9..16603a580 100644 --- a/pkg/sentry/mm/address_space.go +++ b/pkg/sentry/mm/address_space.go @@ -166,11 +166,11 @@ func (mm *MemoryManager) Deactivate() { // for all addresses in ar should be precommitted. // // Preconditions: -// * mm.activeMu must be locked. -// * mm.as != nil. -// * ar.Length() != 0. -// * ar must be page-aligned. -// * pseg == mm.pmas.LowerBoundSegment(ar.Start). +// - mm.activeMu must be locked. +// - mm.as != nil. +// - ar.Length() != 0. +// - ar must be page-aligned. +// - pseg == mm.pmas.LowerBoundSegment(ar.Start). func (mm *MemoryManager) mapASLocked(pseg pmaIterator, ar hostarch.AddrRange, precommit bool) error { // By default, map entire pmas at a time, under the assumption that there // is no cost to mapping more of a pma than necessary. diff --git a/pkg/sentry/mm/io.go b/pkg/sentry/mm/io.go index 5fcfeb473..150793578 100644 --- a/pkg/sentry/mm/io.go +++ b/pkg/sentry/mm/io.go @@ -443,9 +443,9 @@ func (mm *MemoryManager) LoadUint32(ctx context.Context, addr hostarch.Addr, opt // operation spanning ioar. // // Preconditions: -// * mm.as != nil. -// * ioar.Length() != 0. -// * ioar.Contains(addr). +// - mm.as != nil. +// - ioar.Length() != 0. +// - ioar.Contains(addr). func (mm *MemoryManager) handleASIOFault(ctx context.Context, addr hostarch.Addr, ioar hostarch.AddrRange, at hostarch.AccessType) error { // Try to map all remaining pages in the I/O operation. This RoundUp can't // overflow because otherwise it would have been caught by CheckIORange. @@ -634,8 +634,8 @@ func (mm *MemoryManager) withVecInternalMappings(ctx context.Context, ars hostar // truncate hostarch.AddrRangeSeq when errors occur. // // Preconditions: -// * !arsit.IsEmpty(). -// * end <= arsit.Head().End. +// - !arsit.IsEmpty(). +// - end <= arsit.Head().End. func truncatedAddrRangeSeq(ars, arsit hostarch.AddrRangeSeq, end hostarch.Addr) hostarch.AddrRangeSeq { ar := arsit.Head() if end <= ar.Start { diff --git a/pkg/sentry/mm/mm.go b/pkg/sentry/mm/mm.go index 0634953a5..c8682681e 100644 --- a/pkg/sentry/mm/mm.go +++ b/pkg/sentry/mm/mm.go @@ -17,18 +17,18 @@ // // Lock order: // -// fs locks, except for memmap.Mappable locks -// mm.MemoryManager.metadataMu -// mm.MemoryManager.mappingMu -// Locks taken by memmap.Mappable methods other than Translate -// mm.MemoryManager.activeMu -// Locks taken by memmap.Mappable.Translate -// mm.privateRefs.mu -// platform.AddressSpace locks -// memmap.File locks -// mm.aioManager.mu -// mm.AIOContext.mu -// kernel.TaskSet.mu +// fs locks, except for memmap.Mappable locks +// mm.MemoryManager.metadataMu +// mm.MemoryManager.mappingMu +// Locks taken by memmap.Mappable methods other than Translate +// mm.MemoryManager.activeMu +// Locks taken by memmap.Mappable.Translate +// mm.privateRefs.mu +// platform.AddressSpace locks +// memmap.File locks +// mm.aioManager.mu +// mm.AIOContext.mu +// kernel.TaskSet.mu // // Only mm.MemoryManager.Fork is permitted to lock mm.MemoryManager.activeMu in // multiple mm.MemoryManagers, as it does so in a well-defined order (forked diff --git a/pkg/sentry/mm/pma.go b/pkg/sentry/mm/pma.go index a6638a522..ef15e704d 100644 --- a/pkg/sentry/mm/pma.go +++ b/pkg/sentry/mm/pma.go @@ -34,8 +34,8 @@ import ( // iterator. // // Preconditions: -// * mm.activeMu must be locked. -// * ar.Length() != 0. +// - mm.activeMu must be locked. +// - ar.Length() != 0. func (mm *MemoryManager) existingPMAsLocked(ar hostarch.AddrRange, at hostarch.AccessType, ignorePermissions bool, needInternalMappings bool) pmaIterator { if checkInvariants { if !ar.WellFormed() || ar.Length() == 0 { @@ -84,22 +84,22 @@ func (mm *MemoryManager) existingVecPMAsLocked(ars hostarch.AddrRangeSeq, at hos // getPMAsLocked ensures that pmas exist for all addresses in ar, and support // access of type at. It returns: // -// - An iterator to the pma containing ar.Start. If no pma contains ar.Start, -// the iterator is unspecified. +// - An iterator to the pma containing ar.Start. If no pma contains ar.Start, +// the iterator is unspecified. // -// - An iterator to the gap after the last pma containing an address in ar. If -// pmas exist for no addresses in ar, the iterator is to a gap that begins -// before ar.Start. +// - An iterator to the gap after the last pma containing an address in ar. If +// pmas exist for no addresses in ar, the iterator is to a gap that begins +// before ar.Start. // -// - An error that is non-nil if pmas exist for only a subset of ar. +// - An error that is non-nil if pmas exist for only a subset of ar. // // Preconditions: -// * mm.mappingMu must be locked. -// * mm.activeMu must be locked for writing. -// * ar.Length() != 0. -// * vseg.Range().Contains(ar.Start). -// * vmas must exist for all addresses in ar, and support accesses of type at -// (i.e. permission checks must have been performed against vmas). +// - mm.mappingMu must be locked. +// - mm.activeMu must be locked for writing. +// - ar.Length() != 0. +// - vseg.Range().Contains(ar.Start). +// - vmas must exist for all addresses in ar, and support accesses of type at +// (i.e. permission checks must have been performed against vmas). func (mm *MemoryManager) getPMAsLocked(ctx context.Context, vseg vmaIterator, ar hostarch.AddrRange, at hostarch.AccessType) (pmaIterator, pmaGapIterator, error) { if checkInvariants { if !ar.WellFormed() || ar.Length() == 0 { @@ -143,10 +143,10 @@ func (mm *MemoryManager) getPMAsLocked(ctx context.Context, vseg vmaIterator, ar // why. // // Preconditions: -// * mm.mappingMu must be locked. -// * mm.activeMu must be locked for writing. -// * vmas must exist for all addresses in ars, and support accesses of type at -// (i.e. permission checks must have been performed against vmas). +// - mm.mappingMu must be locked. +// - mm.activeMu must be locked for writing. +// - vmas must exist for all addresses in ars, and support accesses of type at +// (i.e. permission checks must have been performed against vmas). func (mm *MemoryManager) getVecPMAsLocked(ctx context.Context, ars hostarch.AddrRangeSeq, at hostarch.AccessType) (hostarch.AddrRangeSeq, error) { for arsit := ars; !arsit.IsEmpty(); arsit = arsit.Tail() { ar := arsit.Head() @@ -183,16 +183,15 @@ func (mm *MemoryManager) getVecPMAsLocked(ctx context.Context, ars hostarch.Addr // getPMAsInternalLocked is equivalent to getPMAsLocked, with the following // exceptions: // -// - getPMAsInternalLocked returns a pmaIterator on a best-effort basis (that -// is, the returned iterator may be terminal, even if a pma that contains -// ar.Start exists). Returning this iterator on a best-effort basis allows -// callers that require it to use it when it's cheaply available, while also -// avoiding the overhead of retrieving it when it's not. +// - getPMAsInternalLocked returns a pmaIterator on a best-effort basis (that +// is, the returned iterator may be terminal, even if a pma that contains +// ar.Start exists). Returning this iterator on a best-effort basis allows +// callers that require it to use it when it's cheaply available, while also +// avoiding the overhead of retrieving it when it's not. // -// - getPMAsInternalLocked additionally requires that ar is page-aligned. -// -// getPMAsInternalLocked is an implementation helper for getPMAsLocked and -// getVecPMAsLocked; other clients should call one of those instead. +// - getPMAsInternalLocked additionally requires that ar is page-aligned. +// getPMAsInternalLocked is an implementation helper for getPMAsLocked and +// getVecPMAsLocked; other clients should call one of those instead. func (mm *MemoryManager) getPMAsInternalLocked(ctx context.Context, vseg vmaIterator, ar hostarch.AddrRange, at hostarch.AccessType) (pmaIterator, pmaGapIterator, error) { if checkInvariants { if !ar.WellFormed() || ar.Length() == 0 || !ar.IsPageAligned() { @@ -340,11 +339,11 @@ func (mm *MemoryManager) getPMAsInternalLocked(ctx context.Context, vseg vmaIter // The majority of copy-on-write breaks on executable // pages come from: // - // - The ELF loader, which must zero out bytes on the - // last page of each segment after the end of the - // segment. + // - The ELF loader, which must zero out bytes on the + // last page of each segment after the end of the + // segment. // - // - gdb's use of ptrace to insert breakpoints. + // - gdb's use of ptrace to insert breakpoints. // // Neither of these cases has enough spatial locality // to benefit from copying nearby pages, so if the vma @@ -554,9 +553,9 @@ func privateAligned(ar hostarch.AddrRange) hostarch.AddrRange { // and update the pma to indicate that it does not require copy-on-write. // // Preconditions: -// * vseg.Range().IsSupersetOf(pseg.Range()). -// * mm.mappingMu must be locked. -// * mm.activeMu must be locked for writing. +// - vseg.Range().IsSupersetOf(pseg.Range()). +// - mm.mappingMu must be locked. +// - mm.activeMu must be locked for writing. func (mm *MemoryManager) isPMACopyOnWriteLocked(vseg vmaIterator, pseg pmaIterator) bool { pma := pseg.ValuePtr() if !pma.needCOW { @@ -606,9 +605,9 @@ func (mm *MemoryManager) Invalidate(ar hostarch.AddrRange, opts memmap.Invalidat // addresses in ar. // // Preconditions: -// * mm.activeMu must be locked for writing. -// * ar.Length() != 0. -// * ar must be page-aligned. +// - mm.activeMu must be locked for writing. +// - ar.Length() != 0. +// - ar must be page-aligned. func (mm *MemoryManager) invalidateLocked(ar hostarch.AddrRange, invalidatePrivate, invalidateShared bool) { if checkInvariants { if !ar.WellFormed() || ar.Length() == 0 || !ar.IsPageAligned() { @@ -653,8 +652,8 @@ func (mm *MemoryManager) invalidateLocked(ar hostarch.AddrRange, invalidatePriva // in the Linux kernel. // // Preconditions: -// * ar.Length() != 0. -// * ar must be page-aligned. +// - ar.Length() != 0. +// - ar must be page-aligned. func (mm *MemoryManager) Pin(ctx context.Context, ar hostarch.AddrRange, at hostarch.AccessType, ignorePermissions bool) ([]PinnedRange, error) { if checkInvariants { if !ar.WellFormed() || ar.Length() == 0 || !ar.IsPageAligned() { @@ -735,12 +734,12 @@ func Unpin(prs []PinnedRange) { // movePMAsLocked moves all pmas in oldAR to newAR. // // Preconditions: -// * mm.activeMu must be locked for writing. -// * oldAR.Length() != 0. -// * oldAR.Length() <= newAR.Length(). -// * !oldAR.Overlaps(newAR). -// * mm.pmas.IsEmptyRange(newAR). -// * oldAR and newAR must be page-aligned. +// - mm.activeMu must be locked for writing. +// - oldAR.Length() != 0. +// - oldAR.Length() <= newAR.Length(). +// - !oldAR.Overlaps(newAR). +// - mm.pmas.IsEmptyRange(newAR). +// - oldAR and newAR must be page-aligned. func (mm *MemoryManager) movePMAsLocked(oldAR, newAR hostarch.AddrRange) { if checkInvariants { if !oldAR.WellFormed() || oldAR.Length() == 0 || !oldAR.IsPageAligned() { @@ -789,18 +788,18 @@ func (mm *MemoryManager) movePMAsLocked(oldAR, newAR hostarch.AddrRange) { // getPMAInternalMappingsLocked ensures that pmas for all addresses in ar have // cached internal mappings. It returns: // -// - An iterator to the gap after the last pma with internal mappings -// containing an address in ar. If internal mappings exist for no addresses in -// ar, the iterator is to a gap that begins before ar.Start. +// - An iterator to the gap after the last pma with internal mappings +// containing an address in ar. If internal mappings exist for no addresses in +// ar, the iterator is to a gap that begins before ar.Start. // -// - An error that is non-nil if internal mappings exist for only a subset of -// ar. +// - An error that is non-nil if internal mappings exist for only a subset of +// ar. // // Preconditions: -// * mm.activeMu must be locked for writing. -// * pseg.Range().Contains(ar.Start). -// * pmas must exist for all addresses in ar. -// * ar.Length() != 0. +// - mm.activeMu must be locked for writing. +// - pseg.Range().Contains(ar.Start). +// - pmas must exist for all addresses in ar. +// - ar.Length() != 0. // // Postconditions: getPMAInternalMappingsLocked does not invalidate iterators // into mm.pmas. @@ -831,8 +830,8 @@ func (mm *MemoryManager) getPMAInternalMappingsLocked(pseg pmaIterator, ar hosta // error explaining why. // // Preconditions: -// * mm.activeMu must be locked for writing. -// * pmas must exist for all addresses in ar. +// - mm.activeMu must be locked for writing. +// - pmas must exist for all addresses in ar. // // Postconditions: getVecPMAInternalMappingsLocked does not invalidate iterators // into mm.pmas. @@ -852,11 +851,11 @@ func (mm *MemoryManager) getVecPMAInternalMappingsLocked(ars hostarch.AddrRangeS // internalMappingsLocked returns internal mappings for addresses in ar. // // Preconditions: -// * mm.activeMu must be locked. -// * Internal mappings must have been previously established for all addresses -// in ar. -// * ar.Length() != 0. -// * pseg.Range().Contains(ar.Start). +// - mm.activeMu must be locked. +// - Internal mappings must have been previously established for all addresses +// in ar. +// - ar.Length() != 0. +// - pseg.Range().Contains(ar.Start). func (mm *MemoryManager) internalMappingsLocked(pseg pmaIterator, ar hostarch.AddrRange) safemem.BlockSeq { if checkInvariants { if !ar.WellFormed() || ar.Length() == 0 { @@ -891,9 +890,9 @@ func (mm *MemoryManager) internalMappingsLocked(pseg pmaIterator, ar hostarch.Ad // vecInternalMappingsLocked returns internal mappings for addresses in ars. // // Preconditions: -// * mm.activeMu must be locked. -// * Internal mappings must have been previously established for all addresses -// in ars. +// - mm.activeMu must be locked. +// - Internal mappings must have been previously established for all addresses +// in ars. func (mm *MemoryManager) vecInternalMappingsLocked(ars hostarch.AddrRangeSeq) safemem.BlockSeq { var ims []safemem.Block for ; !ars.IsEmpty(); ars = ars.Tail() { @@ -1023,8 +1022,8 @@ func (pmaSetFunctions) Split(ar hostarch.AddrRange, p pma, split hostarch.Addr) // so by scanning linearly backward from pgap. // // Preconditions: -// * mm.activeMu must be locked. -// * addr <= pgap.Start(). +// - mm.activeMu must be locked. +// - addr <= pgap.Start(). func (mm *MemoryManager) findOrSeekPrevUpperBoundPMA(addr hostarch.Addr, pgap pmaGapIterator) pmaIterator { if checkInvariants { if !pgap.Ok() { @@ -1071,8 +1070,8 @@ func (pseg pmaIterator) fileRange() memmap.FileRange { } // Preconditions: -// * pseg.Range().IsSupersetOf(ar). -// * ar.Length != 0. +// - pseg.Range().IsSupersetOf(ar). +// - ar.Length != 0. func (pseg pmaIterator) fileRangeOf(ar hostarch.AddrRange) memmap.FileRange { if checkInvariants { if !pseg.Ok() { diff --git a/pkg/sentry/mm/syscalls.go b/pkg/sentry/mm/syscalls.go index cae187153..90724baca 100644 --- a/pkg/sentry/mm/syscalls.go +++ b/pkg/sentry/mm/syscalls.go @@ -159,8 +159,8 @@ func (mm *MemoryManager) MMap(ctx context.Context, opts memmap.MMapOpts) (hostar // into mm.as if it is active. // // Preconditions: -// * mm.mappingMu must be locked. -// * vseg.Range().IsSupersetOf(ar). +// - mm.mappingMu must be locked. +// - vseg.Range().IsSupersetOf(ar). func (mm *MemoryManager) populateVMA(ctx context.Context, vseg vmaIterator, ar hostarch.AddrRange, precommit bool) { if !vseg.ValuePtr().effectivePerms.Any() { // Linux doesn't populate inaccessible pages. See @@ -203,8 +203,8 @@ func (mm *MemoryManager) populateVMA(ctx context.Context, vseg vmaIterator, ar h // expensive operations that don't require it to be locked. // // Preconditions: -// * mm.mappingMu must be locked for writing. -// * vseg.Range().IsSupersetOf(ar). +// - mm.mappingMu must be locked for writing. +// - vseg.Range().IsSupersetOf(ar). // // Postconditions: mm.mappingMu will be unlocked. // +checklocksrelease:mm.mappingMu diff --git a/pkg/sentry/mm/vma.go b/pkg/sentry/mm/vma.go index ad1b964a3..7971ea90f 100644 --- a/pkg/sentry/mm/vma.go +++ b/pkg/sentry/mm/vma.go @@ -35,8 +35,8 @@ import ( // the same slice. // // Preconditions: -// * mm.mappingMu must be locked for writing. -// * opts must be valid as defined by the checks in MMap. +// - mm.mappingMu must be locked for writing. +// - opts must be valid as defined by the checks in MMap. func (mm *MemoryManager) createVMALocked(ctx context.Context, opts memmap.MMapOpts, droppedIDs []memmap.MappingIdentity) (vmaIterator, hostarch.AddrRange, []memmap.MappingIdentity, error) { if opts.MaxPerms != opts.MaxPerms.Effective() { panic(fmt.Sprintf("Non-effective MaxPerms %s cannot be enforced", opts.MaxPerms)) @@ -140,9 +140,9 @@ func (mm *MemoryManager) createVMALocked(ctx context.Context, opts memmap.MMapOp type findAvailableOpts struct { // These fields are equivalent to those in memmap.MMapOpts, except that: // - // - Addr must be page-aligned. + // - Addr must be page-aligned. // - // - Unmap allows existing guard pages in the returned range. + // - Unmap allows existing guard pages in the returned range. Addr hostarch.Addr Fixed bool @@ -259,18 +259,18 @@ func (mm *MemoryManager) mlockedBytesRangeLocked(ar hostarch.AddrRange) uint64 { // getVMAsLocked ensures that vmas exist for all addresses in ar, and support // access of type (at, ignorePermissions). It returns: // -// - An iterator to the vma containing ar.Start. If no vma contains ar.Start, -// the iterator is unspecified. +// - An iterator to the vma containing ar.Start. If no vma contains ar.Start, +// the iterator is unspecified. // -// - An iterator to the gap after the last vma containing an address in ar. If -// vmas exist for no addresses in ar, the iterator is to a gap that begins -// before ar.Start. +// - An iterator to the gap after the last vma containing an address in ar. If +// vmas exist for no addresses in ar, the iterator is to a gap that begins +// before ar.Start. // -// - An error that is non-nil if vmas exist for only a subset of ar. +// - An error that is non-nil if vmas exist for only a subset of ar. // // Preconditions: -// * mm.mappingMu must be locked for reading; it may be temporarily unlocked. -// * ar.Length() != 0. +// - mm.mappingMu must be locked for reading; it may be temporarily unlocked. +// - ar.Length() != 0. func (mm *MemoryManager) getVMAsLocked(ctx context.Context, ar hostarch.AddrRange, at hostarch.AccessType, ignorePermissions bool) (vmaIterator, vmaGapIterator, error) { if checkInvariants { if !ar.WellFormed() || ar.Length() == 0 { @@ -358,9 +358,9 @@ const guardBytes = 256 * hostarch.PageSize // the same slice. // // Preconditions: -// * mm.mappingMu must be locked for writing. -// * ar.Length() != 0. -// * ar must be page-aligned. +// - mm.mappingMu must be locked for writing. +// - ar.Length() != 0. +// - ar must be page-aligned. func (mm *MemoryManager) unmapLocked(ctx context.Context, ar hostarch.AddrRange, droppedIDs []memmap.MappingIdentity) (vmaGapIterator, []memmap.MappingIdentity) { if checkInvariants { if !ar.WellFormed() || ar.Length() == 0 || !ar.IsPageAligned() { @@ -384,9 +384,9 @@ func (mm *MemoryManager) unmapLocked(ctx context.Context, ar hostarch.AddrRange, // the same slice. // // Preconditions: -// * mm.mappingMu must be locked for writing. -// * ar.Length() != 0. -// * ar must be page-aligned. +// - mm.mappingMu must be locked for writing. +// - ar.Length() != 0. +// - ar must be page-aligned. func (mm *MemoryManager) removeVMAsLocked(ctx context.Context, ar hostarch.AddrRange, droppedIDs []memmap.MappingIdentity) (vmaGapIterator, []memmap.MappingIdentity) { if checkInvariants { if !ar.WellFormed() || ar.Length() == 0 || !ar.IsPageAligned() { @@ -495,8 +495,8 @@ func (vmaSetFunctions) Split(ar hostarch.AddrRange, v vma, split hostarch.Addr) } // Preconditions: -// * vseg.ValuePtr().mappable != nil. -// * vseg.Range().Contains(addr). +// - vseg.ValuePtr().mappable != nil. +// - vseg.Range().Contains(addr). func (vseg vmaIterator) mappableOffsetAt(addr hostarch.Addr) uint64 { if checkInvariants { if !vseg.Ok() { @@ -521,9 +521,9 @@ func (vseg vmaIterator) mappableRange() memmap.MappableRange { } // Preconditions: -// * vseg.ValuePtr().mappable != nil. -// * vseg.Range().IsSupersetOf(ar). -// * ar.Length() != 0. +// - vseg.ValuePtr().mappable != nil. +// - vseg.Range().IsSupersetOf(ar). +// - ar.Length() != 0. func (vseg vmaIterator) mappableRangeOf(ar hostarch.AddrRange) memmap.MappableRange { if checkInvariants { if !vseg.Ok() { @@ -546,9 +546,9 @@ func (vseg vmaIterator) mappableRangeOf(ar hostarch.AddrRange) memmap.MappableRa } // Preconditions: -// * vseg.ValuePtr().mappable != nil. -// * vseg.mappableRange().IsSupersetOf(mr). -// * mr.Length() != 0. +// - vseg.ValuePtr().mappable != nil. +// - vseg.mappableRange().IsSupersetOf(mr). +// - mr.Length() != 0. func (vseg vmaIterator) addrRangeOf(mr memmap.MappableRange) hostarch.AddrRange { if checkInvariants { if !vseg.Ok() { @@ -574,8 +574,8 @@ func (vseg vmaIterator) addrRangeOf(mr memmap.MappableRange) hostarch.AddrRange // scanning linearly forward from vseg. // // Preconditions: -// * mm.mappingMu must be locked. -// * addr >= vseg.Start(). +// - mm.mappingMu must be locked. +// - addr >= vseg.Start(). func (vseg vmaIterator) seekNextLowerBound(addr hostarch.Addr) vmaIterator { if checkInvariants { if !vseg.Ok() { diff --git a/pkg/sentry/pgalloc/pgalloc.go b/pkg/sentry/pgalloc/pgalloc.go index de22a34d2..252535f54 100644 --- a/pkg/sentry/pgalloc/pgalloc.go +++ b/pkg/sentry/pgalloc/pgalloc.go @@ -17,8 +17,8 @@ // // Lock order: // -// pgalloc.MemoryFile.mu -// pgalloc.MemoryFile.mappingsMu +// pgalloc.MemoryFile.mu +// pgalloc.MemoryFile.mappingsMu package pgalloc import ( @@ -219,11 +219,11 @@ const ( // As of this writing, the behavior of DelayedEvictionEnabled depends on // whether or not MemoryFileOpts.UseHostMemcgPressure is enabled: // - // - If UseHostMemcgPressure is true, evictions are delayed until memory - // pressure is indicated. + // - If UseHostMemcgPressure is true, evictions are delayed until memory + // pressure is indicated. // - // - Otherwise, evictions are only delayed until the reclaimer goroutine - // is out of work (pages to reclaim). + // - Otherwise, evictions are only delayed until the reclaimer goroutine + // is out of work (pages to reclaim). DelayedEvictionEnabled // DelayedEvictionManual requires that evictable allocations are only @@ -572,8 +572,8 @@ func findAvailableRangeBottomUp(usage *usageSet, length, alignment uint64) (memm // by r.ReadToBlocks(), it returns that error. // // Preconditions: -// * length > 0. -// * length must be page-aligned. +// - length > 0. +// - length must be page-aligned. func (f *MemoryFile) AllocateAndFill(length uint64, kind usage.MemoryKind, r safemem.Reader) (memmap.FileRange, error) { fr, err := f.Allocate(length, AllocOpts{Kind: kind}) if err != nil { @@ -1260,9 +1260,9 @@ func (f *MemoryFile) startEvictionsLocked() bool { } // Preconditions: -// * info == f.evictable[user]. -// * !info.evicting. -// * f.mu must be locked. +// - info == f.evictable[user]. +// - !info.evicting. +// - f.mu must be locked. func (f *MemoryFile) startEvictionGoroutineLocked(user EvictableMemoryUser, info *evictableMemoryUserInfo) { info.evicting = true f.evictionWG.Add(1) diff --git a/pkg/sentry/platform/interrupt/interrupt.go b/pkg/sentry/platform/interrupt/interrupt.go index 9dfac3eae..7cf01c7b5 100644 --- a/pkg/sentry/platform/interrupt/interrupt.go +++ b/pkg/sentry/platform/interrupt/interrupt.go @@ -48,15 +48,16 @@ type Forwarder struct { // // Usage: // -// if !f.Enable(r) { -// // There was an interrupt. -// return -// } +// if !f.Enable(r) { +// // There was an interrupt. +// return +// } +// // defer f.Disable() // // Preconditions: -// * r must not be nil. -// * f must not already be forwarding interrupts to a Receiver. +// - r must not be nil. +// - f must not already be forwarding interrupts to a Receiver. func (f *Forwarder) Enable(r Receiver) bool { if r == nil { panic("nil Receiver") diff --git a/pkg/sentry/platform/kvm/machine_amd64.go b/pkg/sentry/platform/kvm/machine_amd64.go index 7423dcc99..c99009f0d 100644 --- a/pkg/sentry/platform/kvm/machine_amd64.go +++ b/pkg/sentry/platform/kvm/machine_amd64.go @@ -187,7 +187,7 @@ var bitsForScaling = func() int64 { // strict inverse of this value. This simplifies this function considerably. // // Roughly, the returned value "scaledTSC" will have: -// scaledTSC/hostTSC == 1/rawFreq +// scaledTSC/hostTSC == 1/rawFreq // //go:nosplit func scaledTSC(rawFreq uintptr) int64 { diff --git a/pkg/sentry/platform/platform.go b/pkg/sentry/platform/platform.go index 96900a322..bae31ef1f 100644 --- a/pkg/sentry/platform/platform.go +++ b/pkg/sentry/platform/platform.go @@ -192,21 +192,21 @@ type Context interface { // // Switch may return one of the following special errors: // - // - nil: The Context invoked a system call. + // - nil: The Context invoked a system call. // - // - ErrContextSignal: The Context was interrupted by a signal. The - // returned *linux.SignalInfo contains information about the signal. If - // linux.SignalInfo.Signo == SIGSEGV, the returned hostarch.AccessType - // contains the access type of the triggering fault. The caller owns - // the returned SignalInfo. + // - ErrContextSignal: The Context was interrupted by a signal. The + // returned *linux.SignalInfo contains information about the signal. If + // linux.SignalInfo.Signo == SIGSEGV, the returned hostarch.AccessType + // contains the access type of the triggering fault. The caller owns + // the returned SignalInfo. // - // - ErrContextInterrupt: The Context was interrupted by a call to - // Interrupt(). Switch() may return ErrContextInterrupt spuriously. In - // particular, most implementations of Interrupt() will cause the first - // following call to Switch() to return ErrContextInterrupt if there is no - // concurrent call to Switch(). + // - ErrContextInterrupt: The Context was interrupted by a call to + // Interrupt(). Switch() may return ErrContextInterrupt spuriously. In + // particular, most implementations of Interrupt() will cause the first + // following call to Switch() to return ErrContextInterrupt if there is no + // concurrent call to Switch(). // - // - ErrContextCPUPreempted: See the definition of that error for details. + // - ErrContextCPUPreempted: See the definition of that error for details. Switch(ctx context.Context, mm MemoryManager, ac arch.Context, cpu int32) (*linux.SignalInfo, hostarch.AccessType, error) // PullFullState() pulls a full state of the application thread. @@ -258,15 +258,15 @@ var ( // ErrContextCPUPreempted is returned by Context.Switch() to indicate that // one of the following occurred: // - // - The CPU executing the Context is not the CPU passed to - // Context.Switch(). + // - The CPU executing the Context is not the CPU passed to + // Context.Switch(). // - // - The CPU executing the Context may have executed another Context since - // the last time it executed this one; or the CPU has previously executed - // another Context, and has never executed this one. + // - The CPU executing the Context may have executed another Context since + // the last time it executed this one; or the CPU has previously executed + // another Context, and has never executed this one. // - // - Platform.PreemptAllCPUs() was called since the last return from - // Context.Switch(). + // - Platform.PreemptAllCPUs() was called since the last return from + // Context.Switch(). ErrContextCPUPreempted = fmt.Errorf("interrupted by CPU preemption") ) @@ -291,18 +291,18 @@ type AddressSpace interface { // implementations may choose to ignore it. // // Preconditions: - // * addr and fr must be page-aligned. - // * fr.Length() > 0. - // * at.Any() == true. - // * At least one reference must be held on all pages in fr, and must - // continue to be held as long as pages are mapped. + // * addr and fr must be page-aligned. + // * fr.Length() > 0. + // * at.Any() == true. + // * At least one reference must be held on all pages in fr, and must + // continue to be held as long as pages are mapped. MapFile(addr hostarch.Addr, f memmap.File, fr memmap.FileRange, at hostarch.AccessType, precommit bool) error // Unmap unmaps the given range. // // Preconditions: - // * addr is page-aligned. - // * length > 0. + // * addr is page-aligned. + // * length > 0. Unmap(addr hostarch.Addr, length uint64) // Release releases this address space. After releasing, a new AddressSpace @@ -424,7 +424,7 @@ type Constructor interface { // // Arguments: // - // * deviceFile - the device file (e.g. /dev/kvm for the KVM platform). + // * deviceFile - the device file (e.g. /dev/kvm for the KVM platform). New(deviceFile *os.File) (Platform, error) // OpenDevice opens the path to the device used by the platform. diff --git a/pkg/sentry/platform/ptrace/ptrace.go b/pkg/sentry/platform/ptrace/ptrace.go index 2566679c4..1268816d5 100644 --- a/pkg/sentry/platform/ptrace/ptrace.go +++ b/pkg/sentry/platform/ptrace/ptrace.go @@ -40,8 +40,8 @@ // // Lock order: // -// subprocess.mu -// context.mu +// subprocess.mu +// context.mu package ptrace import ( diff --git a/pkg/sentry/platform/ptrace/subprocess_linux.go b/pkg/sentry/platform/ptrace/subprocess_linux.go index 129ca52e2..513346c42 100644 --- a/pkg/sentry/platform/ptrace/subprocess_linux.go +++ b/pkg/sentry/platform/ptrace/subprocess_linux.go @@ -129,7 +129,6 @@ func attachedThread(flags uintptr, defaultAction linux.BPFAction) (*thread, erro // malloc calls, and no new stack segments. For the same reason compiler does // not race instrument it. // -// //go:norace func forkStub(flags uintptr, instrs []linux.BPFInstruction) (*thread, error) { // Declare all variables up front in order to ensure that there's no diff --git a/pkg/sentry/seccheck/checkers/remote/wire/wire.go b/pkg/sentry/seccheck/checkers/remote/wire/wire.go index da68cba0f..430e165c5 100644 --- a/pkg/sentry/seccheck/checkers/remote/wire/wire.go +++ b/pkg/sentry/seccheck/checkers/remote/wire/wire.go @@ -23,9 +23,9 @@ const HeaderStructSize = 8 // Header is used to describe the message being sent to the remote process. // -// 0 --------- 16 ---------- 32 ----------- 64 -----------+ -// | HeaderSize | MessageType | DroppedCount | Payload... | -// +---- 16 ----+---- 16 -----+----- 32 -----+------------+ +// 0 --------- 16 ---------- 32 ----------- 64 -----------+ +// | HeaderSize | MessageType | DroppedCount | Payload... | +// +---- 16 ----+---- 16 -----+----- 32 -----+------------+ // // +marshal type Header struct { diff --git a/pkg/sentry/socket/netfilter/ipv4.go b/pkg/sentry/socket/netfilter/ipv4.go index 6cbfee8b6..43d9380c4 100644 --- a/pkg/sentry/socket/netfilter/ipv4.go +++ b/pkg/sentry/socket/netfilter/ipv4.go @@ -235,12 +235,12 @@ func filterFromIPTIP(iptip linux.IPTIP) (stack.IPHeaderFilter, error) { func containsUnsupportedFields4(iptip linux.IPTIP) bool { // The following features are supported: - // - Protocol - // - Dst and DstMask - // - Src and SrcMask - // - The inverse destination IP check flag - // - InputInterface, InputInterfaceMask and its inverse. - // - OutputInterface, OutputInterfaceMask and its inverse. + // - Protocol + // - Dst and DstMask + // - Src and SrcMask + // - The inverse destination IP check flag + // - InputInterface, InputInterfaceMask and its inverse. + // - OutputInterface, OutputInterfaceMask and its inverse. const flagMask = 0 // Disable any supported inverse flags. const inverseMask = linux.IPT_INV_DSTIP | linux.IPT_INV_SRCIP | diff --git a/pkg/sentry/socket/netfilter/ipv6.go b/pkg/sentry/socket/netfilter/ipv6.go index 902707abf..0e66490a5 100644 --- a/pkg/sentry/socket/netfilter/ipv6.go +++ b/pkg/sentry/socket/netfilter/ipv6.go @@ -238,12 +238,12 @@ func filterFromIP6TIP(iptip linux.IP6TIP) (stack.IPHeaderFilter, error) { func containsUnsupportedFields6(iptip linux.IP6TIP) bool { // The following features are supported: - // - Protocol - // - Dst and DstMask - // - Src and SrcMask - // - The inverse destination IP check flag - // - InputInterface, InputInterfaceMask and its inverse. - // - OutputInterface, OutputInterfaceMask and its inverse. + // - Protocol + // - Dst and DstMask + // - Src and SrcMask + // - The inverse destination IP check flag + // - InputInterface, InputInterfaceMask and its inverse. + // - OutputInterface, OutputInterfaceMask and its inverse. const flagMask = linux.IP6T_F_PROTO // Disable any supported inverse flags. const inverseMask = linux.IP6T_INV_DSTIP | linux.IP6T_INV_SRCIP | diff --git a/pkg/sentry/socket/netfilter/netfilter.go b/pkg/sentry/socket/netfilter/netfilter.go index 5f38ae091..e4c06bdcb 100644 --- a/pkg/sentry/socket/netfilter/netfilter.go +++ b/pkg/sentry/socket/netfilter/netfilter.go @@ -239,8 +239,8 @@ func SetEntries(task *kernel.Task, stk *stack.Stack, optVal []byte, ipv6 bool) * // We found a user chain. Before inserting it into the table, // check that: - // - There's some other rule after it. - // - There are no matchers. + // - There's some other rule after it. + // - There are no matchers. if ruleIdx == len(table.Rules)-1 { nflog("user chain must have a rule or default policy") return syserr.ErrInvalidArgument @@ -285,9 +285,9 @@ func SetEntries(task *kernel.Task, stk *stack.Stack, optVal []byte, ipv6 bool) * } // TODO(gvisor.dev/issue/6167): Check the following conditions: - // - There are no loops. - // - There are no chains without an unconditional final rule. - // - There are no chains without an unconditional underflow rule. + // - There are no loops. + // - There are no chains without an unconditional final rule. + // - There are no chains without an unconditional underflow rule. stk.IPTables().ReplaceTable(nameToID[replace.Name.String()], table, ipv6) return nil diff --git a/pkg/sentry/socket/netfilter/targets.go b/pkg/sentry/socket/netfilter/targets.go index eaf601543..9791efcc1 100644 --- a/pkg/sentry/socket/netfilter/targets.go +++ b/pkg/sentry/socket/netfilter/targets.go @@ -256,11 +256,11 @@ func (*errorTargetMaker) unmarshal(buf []byte, filter stack.IPHeaderFilter) (tar errTgt.UnmarshalUnsafe(buf) // Error targets are used in 2 cases: - // * An actual error case. These rules have an error named - // ErrorTargetName. The last entry of the table is usually an error - // case to catch any packets that somehow fall through every rule. - // * To mark the start of a user defined chain. These - // rules have an error with the name of the chain. + // * An actual error case. These rules have an error named + // ErrorTargetName. The last entry of the table is usually an error + // case to catch any packets that somehow fall through every rule. + // * To mark the start of a user defined chain. These + // rules have an error with the name of the chain. switch name := errTgt.Name.String(); name { case ErrorTargetName: return &errorTarget{stack.ErrorTarget{ diff --git a/pkg/sentry/socket/unix/transport/connectioned.go b/pkg/sentry/socket/unix/transport/connectioned.go index 108f6bcd9..88abc146a 100644 --- a/pkg/sentry/socket/unix/transport/connectioned.go +++ b/pkg/sentry/socket/unix/transport/connectioned.go @@ -477,8 +477,8 @@ func (e *connectionedEndpoint) Accept(ctx context.Context, peerAddr *tcpip.FullA } // Preconditions: -// * e.Listening() -// * e is locked. +// - e.Listening() +// - e is locked. func (e *connectionedEndpoint) getAcceptedEndpointLocked(ctx context.Context) (*connectionedEndpoint, *syserr.Error) { // Accept connections from within the sentry first, since this avoids // an RPC to the gofer on the common path. diff --git a/pkg/sentry/socket/unix/transport/host.go b/pkg/sentry/socket/unix/transport/host.go index 2ce193818..9ed26e604 100644 --- a/pkg/sentry/socket/unix/transport/host.go +++ b/pkg/sentry/socket/unix/transport/host.go @@ -358,9 +358,9 @@ func (c *HostConnectedEndpoint) SetReceiveBufferSize(v int64) (newSz int64) { // SCMConnectedEndpoint represents an endpoint backed by a host fd that was // passed through a gofer Unix socket. It resembles HostConnectedEndpoint, with the // following differences: -// - SCMConnectedEndpoint is not saveable, because the host cannot guarantee -// the same descriptor number across S/R. -// - SCMConnectedEndpoint holds ownership of its fd and notification queue. +// - SCMConnectedEndpoint is not saveable, because the host cannot guarantee +// the same descriptor number across S/R. +// - SCMConnectedEndpoint holds ownership of its fd and notification queue. type SCMConnectedEndpoint struct { HostConnectedEndpoint diff --git a/pkg/sentry/syscalls/linux/sigset.go b/pkg/sentry/syscalls/linux/sigset.go index 373948991..9d34d60a3 100644 --- a/pkg/sentry/syscalls/linux/sigset.go +++ b/pkg/sentry/syscalls/linux/sigset.go @@ -49,10 +49,10 @@ func copyOutSigSet(t *kernel.Task, sigSetAddr hostarch.Addr, mask linux.SignalSe // copyInSigSetWithSize copies in a structure as below // -// struct { -// sigset_t* sigset_addr; -// size_t sizeof_sigset; -// }; +// struct { +// sigset_t* sigset_addr; +// size_t sizeof_sigset; +// }; // // and returns sigset_addr and size. func copyInSigSetWithSize(t *kernel.Task, addr hostarch.Addr) (hostarch.Addr, uint, error) { diff --git a/pkg/sentry/syscalls/linux/sys_clone_amd64.go b/pkg/sentry/syscalls/linux/sys_clone_amd64.go index 2b2dbd9f9..e068d366a 100644 --- a/pkg/sentry/syscalls/linux/sys_clone_amd64.go +++ b/pkg/sentry/syscalls/linux/sys_clone_amd64.go @@ -25,7 +25,8 @@ import ( // Clone implements linux syscall clone(2). // sys_clone has so many flavors. We implement the default one in linux 3.11 // x86_64: -// sys_clone(clone_flags, newsp, parent_tidptr, child_tidptr, tls_val) +// +// sys_clone(clone_flags, newsp, parent_tidptr, child_tidptr, tls_val) func Clone(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { flags := int(args[0].Int()) stack := args[1].Pointer() diff --git a/pkg/sentry/syscalls/linux/sys_clone_arm64.go b/pkg/sentry/syscalls/linux/sys_clone_arm64.go index 877c86e6a..fa2bb4299 100644 --- a/pkg/sentry/syscalls/linux/sys_clone_arm64.go +++ b/pkg/sentry/syscalls/linux/sys_clone_arm64.go @@ -25,7 +25,8 @@ import ( // Clone implements linux syscall clone(2). // sys_clone has so many flavors, and we implement the default one in linux 3.11 // arm64(kernel/fork.c with CONFIG_CLONE_BACKWARDS defined in the config file): -// sys_clone(clone_flags, newsp, parent_tidptr, tls_val, child_tidptr) +// +// sys_clone(clone_flags, newsp, parent_tidptr, tls_val, child_tidptr) func Clone(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { flags := int(args[0].Int()) stack := args[1].Pointer() diff --git a/pkg/sentry/syscalls/linux/sys_inotify.go b/pkg/sentry/syscalls/linux/sys_inotify.go index b7ad1922e..beebddd3f 100644 --- a/pkg/sentry/syscalls/linux/sys_inotify.go +++ b/pkg/sentry/syscalls/linux/sys_inotify.go @@ -89,7 +89,7 @@ func InotifyAddWatch(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kern resolve := mask&linux.IN_DONT_FOLLOW == 0 // "EINVAL: The given event mask contains no valid events." - // -- inotify_add_watch(2) + // -- inotify_add_watch(2) if validBits := mask & linux.ALL_INOTIFY_BITS; validBits == 0 { return 0, nil, linuxerr.EINVAL } diff --git a/pkg/sentry/syscalls/linux/sys_rusage.go b/pkg/sentry/syscalls/linux/sys_rusage.go index a689abcc9..c1bdf4660 100644 --- a/pkg/sentry/syscalls/linux/sys_rusage.go +++ b/pkg/sentry/syscalls/linux/sys_rusage.go @@ -51,6 +51,7 @@ func getrusage(t *kernel.Task, which int32) linux.Rusage { } // Getrusage implements linux syscall getrusage(2). +// // marked "y" are supported now // marked "*" are not used on Linux // marked "p" are pending for support diff --git a/pkg/sentry/syscalls/linux/sys_signal.go b/pkg/sentry/syscalls/linux/sys_signal.go index 55aea8e0d..3d3cfe003 100644 --- a/pkg/sentry/syscalls/linux/sys_signal.go +++ b/pkg/sentry/syscalls/linux/sys_signal.go @@ -28,8 +28,9 @@ import ( ) // "For a process to have permission to send a signal it must -// - either be privileged (CAP_KILL), or -// - the real or effective user ID of the sending process must be equal to the +// - either be privileged (CAP_KILL), or +// - the real or effective user ID of the sending process must be equal to the +// // real or saved set-user-ID of the target process. // // In the case of SIGCONT it suffices when the sending and receiving processes diff --git a/pkg/sentry/syscalls/linux/sys_time.go b/pkg/sentry/syscalls/linux/sys_time.go index 134b66dac..11f4384d6 100644 --- a/pkg/sentry/syscalls/linux/sys_time.go +++ b/pkg/sentry/syscalls/linux/sys_time.go @@ -127,11 +127,11 @@ func getClock(t *kernel.Task, clockID int32) (ktime.Clock, error) { linux.CLOCK_MONOTONIC_RAW, linux.CLOCK_BOOTTIME: // CLOCK_MONOTONIC approximates CLOCK_MONOTONIC_RAW. // CLOCK_BOOTTIME is internally mapped to CLOCK_MONOTONIC, as: - // - CLOCK_BOOTTIME should behave as CLOCK_MONOTONIC while also - // including suspend time. - // - gVisor has no concept of suspend/resume. - // - CLOCK_MONOTONIC already includes save/restore time, which is - // the closest to suspend time. + // - CLOCK_BOOTTIME should behave as CLOCK_MONOTONIC while also + // including suspend time. + // - gVisor has no concept of suspend/resume. + // - CLOCK_MONOTONIC already includes save/restore time, which is + // the closest to suspend time. return t.Kernel().MonotonicClock(), nil case linux.CLOCK_PROCESS_CPUTIME_ID: return t.ThreadGroup().CPUClock(), nil diff --git a/pkg/sentry/syscalls/linux/vfs2/inotify.go b/pkg/sentry/syscalls/linux/vfs2/inotify.go index d8d5dd7ad..5ba605ae9 100644 --- a/pkg/sentry/syscalls/linux/vfs2/inotify.go +++ b/pkg/sentry/syscalls/linux/vfs2/inotify.go @@ -80,7 +80,7 @@ func InotifyAddWatch(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kern mask := args[2].Uint() // "EINVAL: The given event mask contains no valid events." - // -- inotify_add_watch(2) + // -- inotify_add_watch(2) if mask&linux.ALL_INOTIFY_BITS == 0 { return 0, nil, linuxerr.EINVAL } diff --git a/pkg/sentry/syscalls/linux/vfs2/sync.go b/pkg/sentry/syscalls/linux/vfs2/sync.go index 120a7843c..8c5fb1e1f 100644 --- a/pkg/sentry/syscalls/linux/vfs2/sync.go +++ b/pkg/sentry/syscalls/linux/vfs2/sync.go @@ -86,23 +86,23 @@ func SyncFileRange(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel // TODO(gvisor.dev/issue/1897): Currently, the only file syncing we support // is a full-file sync, i.e. fsync(2). As a result, there are severe // limitations on how much we support sync_file_range: - // - In Linux, sync_file_range(2) doesn't write out the file's metadata, even - // if the file size is changed. We do. - // - We always sync the entire file instead of [offset, offset+nbytes). - // - We do not support the use of WAIT_BEFORE without WAIT_AFTER. For - // correctness, we would have to perform a write-out every time WAIT_BEFORE - // was used, but this would be much more expensive than expected if there - // were no write-out operations in progress. - // - Whenever WAIT_AFTER is used, we sync the file. - // - Ignore WRITE. If this flag is used with WAIT_AFTER, then the file will - // be synced anyway. If this flag is used without WAIT_AFTER, then it is - // safe (and less expensive) to do nothing, because the syscall will not - // wait for the write-out to complete--we only need to make sure that the - // next time WAIT_BEFORE or WAIT_AFTER are used, the write-out completes. - // - According to fs/sync.c, WAIT_BEFORE|WAIT_AFTER "will detect any I/O - // errors or ENOSPC conditions and will return those to the caller, after - // clearing the EIO and ENOSPC flags in the address_space." We don't do - // this. + // - In Linux, sync_file_range(2) doesn't write out the file's metadata, even + // if the file size is changed. We do. + // - We always sync the entire file instead of [offset, offset+nbytes). + // - We do not support the use of WAIT_BEFORE without WAIT_AFTER. For + // correctness, we would have to perform a write-out every time WAIT_BEFORE + // was used, but this would be much more expensive than expected if there + // were no write-out operations in progress. + // - Whenever WAIT_AFTER is used, we sync the file. + // - Ignore WRITE. If this flag is used with WAIT_AFTER, then the file will + // be synced anyway. If this flag is used without WAIT_AFTER, then it is + // safe (and less expensive) to do nothing, because the syscall will not + // wait for the write-out to complete--we only need to make sure that the + // next time WAIT_BEFORE or WAIT_AFTER are used, the write-out completes. + // - According to fs/sync.c, WAIT_BEFORE|WAIT_AFTER "will detect any I/O + // errors or ENOSPC conditions and will return those to the caller, after + // clearing the EIO and ENOSPC flags in the address_space." We don't do + // this. if flags&linux.SYNC_FILE_RANGE_WAIT_BEFORE != 0 && flags&linux.SYNC_FILE_RANGE_WAIT_AFTER == 0 { diff --git a/pkg/sentry/time/parameters.go b/pkg/sentry/time/parameters.go index cd1b95117..1e7bfe2bb 100644 --- a/pkg/sentry/time/parameters.go +++ b/pkg/sentry/time/parameters.go @@ -107,19 +107,19 @@ func (p Parameters) ComputeTime(nowCycles TSCValue) (int64, bool) { // errorAdjust returns a new Parameters struct "adjusted" that satisfies: // // 1. adjusted.ComputeTime(now) = prevParams.ComputeTime(now) -// * i.e., the current time does not jump. +// - i.e., the current time does not jump. // // 2. adjusted.ComputeTime(TSC at next update) = newParams.ComputeTime(TSC at next update) -// * i.e., Any error between prevParams and newParams will be corrected over +// - i.e., Any error between prevParams and newParams will be corrected over // the course of the next update period. // // errorAdjust also returns the current clock error. // // Preconditions: -// * newParams.BaseCycles >= prevParams.BaseCycles; i.e., TSC must not go -// backwards. -// * newParams.BaseCycles <= now; i.e., the new parameters be computed at or -// before now. +// - newParams.BaseCycles >= prevParams.BaseCycles; i.e., TSC must not go +// backwards. +// - newParams.BaseCycles <= now; i.e., the new parameters be computed at or +// before now. func errorAdjust(prevParams Parameters, newParams Parameters, now TSCValue) (Parameters, ReferenceNS, error) { if newParams.BaseCycles < prevParams.BaseCycles { // Oh dear! Something is very wrong. diff --git a/pkg/sentry/vfs/dentry.go b/pkg/sentry/vfs/dentry.go index 585ff7a06..79ed28dbd 100644 --- a/pkg/sentry/vfs/dentry.go +++ b/pkg/sentry/vfs/dentry.go @@ -28,33 +28,33 @@ import ( // // Dentry is loosely analogous to Linux's struct dentry, but: // -// - VFS does not associate Dentries with inodes. gVisor interacts primarily -// with filesystems that are accessed through filesystem APIs (as opposed to -// raw block devices); many such APIs support only paths and file descriptors, -// and not inodes. Furthermore, when parties outside the scope of VFS can -// rename inodes on such filesystems, VFS generally cannot "follow" the rename, -// both due to synchronization issues and because it may not even be able to -// name the destination path; this implies that it would in fact be incorrect -// for Dentries to be associated with inodes on such filesystems. Consequently, -// operations that are inode operations in Linux are FilesystemImpl methods -// and/or FileDescriptionImpl methods in gVisor's VFS. Filesystems that do -// support inodes may store appropriate state in implementations of DentryImpl. +// - VFS does not associate Dentries with inodes. gVisor interacts primarily +// with filesystems that are accessed through filesystem APIs (as opposed to +// raw block devices); many such APIs support only paths and file descriptors, +// and not inodes. Furthermore, when parties outside the scope of VFS can +// rename inodes on such filesystems, VFS generally cannot "follow" the rename, +// both due to synchronization issues and because it may not even be able to +// name the destination path; this implies that it would in fact be incorrect +// for Dentries to be associated with inodes on such filesystems. Consequently, +// operations that are inode operations in Linux are FilesystemImpl methods +// and/or FileDescriptionImpl methods in gVisor's VFS. Filesystems that do +// support inodes may store appropriate state in implementations of DentryImpl. // -// - VFS does not require that Dentries are instantiated for all paths accessed -// through VFS, only those that are tracked beyond the scope of a single -// Filesystem operation. This includes file descriptions, mount points, mount -// roots, process working directories, and chroots. This avoids instantiation -// of Dentries for operations on mutable remote filesystems that can't actually -// cache any state in the Dentry. +// - VFS does not require that Dentries are instantiated for all paths accessed +// through VFS, only those that are tracked beyond the scope of a single +// Filesystem operation. This includes file descriptions, mount points, mount +// roots, process working directories, and chroots. This avoids instantiation +// of Dentries for operations on mutable remote filesystems that can't actually +// cache any state in the Dentry. // -// - VFS does not track filesystem structure (i.e. relationships between -// Dentries), since both the relevant state and synchronization are -// filesystem-specific. +// - VFS does not track filesystem structure (i.e. relationships between +// Dentries), since both the relevant state and synchronization are +// filesystem-specific. // -// - For the reasons above, VFS is not directly responsible for managing Dentry -// lifetime. Dentry reference counts only indicate the extent to which VFS -// requires Dentries to exist; Filesystems may elect to cache or discard -// Dentries with zero references. +// - For the reasons above, VFS is not directly responsible for managing Dentry +// lifetime. Dentry reference counts only indicate the extent to which VFS +// requires Dentries to exist; Filesystems may elect to cache or discard +// Dentries with zero references. // // +stateify savable type Dentry struct { @@ -246,8 +246,9 @@ func (vfs *VirtualFilesystem) InvalidateDentry(ctx context.Context, d *Dentry) { // CommitRenameExchangeDentry depending on the rename's outcome. // // Preconditions: -// * If to is not nil, it must be a child Dentry from the same Filesystem. -// * from != to. +// - If to is not nil, it must be a child Dentry from the same Filesystem. +// - from != to. +// // +checklocksacquire:from.mu // +checklocksacquire:to.mu func (vfs *VirtualFilesystem) PrepareRenameDentry(mntns *MountNamespace, from, to *Dentry) error { diff --git a/pkg/sentry/vfs/file_description.go b/pkg/sentry/vfs/file_description.go index 0a9970281..ccfbd722f 100644 --- a/pkg/sentry/vfs/file_description.go +++ b/pkg/sentry/vfs/file_description.go @@ -361,11 +361,11 @@ type FileDescriptionImpl interface { // // Errors: // - // - If opts.Flags specifies unsupported options, PRead returns EOPNOTSUPP. + // - If opts.Flags specifies unsupported options, PRead returns EOPNOTSUPP. // // Preconditions: - // * The FileDescription was opened for reading. - // * FileDescriptionOptions.DenyPRead == false. + // * The FileDescription was opened for reading. + // * FileDescriptionOptions.DenyPRead == false. PRead(ctx context.Context, dst usermem.IOSequence, offset int64, opts ReadOptions) (int64, error) // Read is similar to PRead, but does not specify an offset. @@ -378,7 +378,7 @@ type FileDescriptionImpl interface { // // Errors: // - // - If opts.Flags specifies unsupported options, Read returns EOPNOTSUPP. + // - If opts.Flags specifies unsupported options, Read returns EOPNOTSUPP. // // Preconditions: The FileDescription was opened for reading. Read(ctx context.Context, dst usermem.IOSequence, opts ReadOptions) (int64, error) @@ -393,12 +393,12 @@ type FileDescriptionImpl interface { // // Errors: // - // - If opts.Flags specifies unsupported options, PWrite returns + // - If opts.Flags specifies unsupported options, PWrite returns // EOPNOTSUPP. // // Preconditions: - // * The FileDescription was opened for writing. - // * FileDescriptionOptions.DenyPWrite == false. + // * The FileDescription was opened for writing. + // * FileDescriptionOptions.DenyPWrite == false. PWrite(ctx context.Context, src usermem.IOSequence, offset int64, opts WriteOptions) (int64, error) // Write is similar to PWrite, but does not specify an offset, which is @@ -411,7 +411,7 @@ type FileDescriptionImpl interface { // // Errors: // - // - If opts.Flags specifies unsupported options, Write returns EOPNOTSUPP. + // - If opts.Flags specifies unsupported options, Write returns EOPNOTSUPP. // // Preconditions: The FileDescription was opened for writing. Write(ctx context.Context, src usermem.IOSequence, opts WriteOptions) (int64, error) diff --git a/pkg/sentry/vfs/filesystem.go b/pkg/sentry/vfs/filesystem.go index 059939010..252c691c3 100644 --- a/pkg/sentry/vfs/filesystem.go +++ b/pkg/sentry/vfs/filesystem.go @@ -103,12 +103,12 @@ func (fs *Filesystem) DecRef(ctx context.Context) { // // All methods may return errors not specified, notably including: // -// - ENOENT if a required path component does not exist. +// - ENOENT if a required path component does not exist. // -// - ENOTDIR if an intermediate path component is not a directory. +// - ENOTDIR if an intermediate path component is not a directory. // -// - Errors from vfs-package functions (ResolvingPath.Resolve*(), -// Mount.CheckBeginWrite(), permission-checking functions, etc.) +// - Errors from vfs-package functions (ResolvingPath.Resolve*(), +// Mount.CheckBeginWrite(), permission-checking functions, etc.) // // For all methods that take or return linux.Statx, Statx.Uid and Statx.Gid // should be interpreted as IDs in the root UserNamespace (i.e. as auth.KUID @@ -135,11 +135,11 @@ type FilesystemImpl interface { // GetDentryAt does not correspond directly to a Linux syscall; it is used // in the implementation of: // - // - Syscalls that need to resolve two paths: link(), linkat(). + // - Syscalls that need to resolve two paths: link(), linkat(). // - // - Syscalls that need to refer to a filesystem position outside the - // context of a file description: chdir(), fchdir(), chroot(), mount(), - // umount(). + // - Syscalls that need to refer to a filesystem position outside the + // context of a file description: chdir(), fchdir(), chroot(), mount(), + // umount(). GetDentryAt(ctx context.Context, rp *ResolvingPath, opts GetDentryOptions) (*Dentry, error) // GetParentDentryAt returns a Dentry representing the directory at the @@ -164,28 +164,28 @@ type FilesystemImpl interface { // // Errors: // - // - If the last path component in rp is "." or "..", LinkAt returns - // EEXIST. + // - If the last path component in rp is "." or "..", LinkAt returns + // EEXIST. // - // - If a file already exists at rp, LinkAt returns EEXIST. + // - If a file already exists at rp, LinkAt returns EEXIST. // - // - If rp.MustBeDir(), LinkAt returns ENOENT. + // - If rp.MustBeDir(), LinkAt returns ENOENT. // - // - If the directory in which the link would be created has been removed - // by RmdirAt or RenameAt, LinkAt returns ENOENT. + // - If the directory in which the link would be created has been removed + // by RmdirAt or RenameAt, LinkAt returns ENOENT. // - // - If rp.Mount != vd.Mount(), LinkAt returns EXDEV. + // - If rp.Mount != vd.Mount(), LinkAt returns EXDEV. // - // - If vd represents a directory, LinkAt returns EPERM. + // - If vd represents a directory, LinkAt returns EPERM. // - // - If vd represents a file for which all existing links have been - // removed, or a file created by open(O_TMPFILE|O_EXCL), LinkAt returns - // ENOENT. Equivalently, if vd represents a file with a link count of 0 not - // created by open(O_TMPFILE) without O_EXCL, LinkAt returns ENOENT. + // - If vd represents a file for which all existing links have been + // removed, or a file created by open(O_TMPFILE|O_EXCL), LinkAt returns + // ENOENT. Equivalently, if vd represents a file with a link count of 0 not + // created by open(O_TMPFILE) without O_EXCL, LinkAt returns ENOENT. // // Preconditions: - // * !rp.Done(). - // * For the final path component in rp, !rp.ShouldFollowSymlink(). + // * !rp.Done(). + // * For the final path component in rp, !rp.ShouldFollowSymlink(). // // Postconditions: If LinkAt returns an error returned by // ResolvingPath.Resolve*(), then !rp.Done(). @@ -195,17 +195,17 @@ type FilesystemImpl interface { // // Errors: // - // - If the last path component in rp is "." or "..", MkdirAt returns - // EEXIST. + // - If the last path component in rp is "." or "..", MkdirAt returns + // EEXIST. // - // - If a file already exists at rp, MkdirAt returns EEXIST. + // - If a file already exists at rp, MkdirAt returns EEXIST. // - // - If the directory in which the new directory would be created has been - // removed by RmdirAt or RenameAt, MkdirAt returns ENOENT. + // - If the directory in which the new directory would be created has been + // removed by RmdirAt or RenameAt, MkdirAt returns ENOENT. // // Preconditions: - // * !rp.Done(). - // * For the final path component in rp, !rp.ShouldFollowSymlink(). + // * !rp.Done(). + // * For the final path component in rp, !rp.ShouldFollowSymlink(). // // Postconditions: If MkdirAt returns an error returned by // ResolvingPath.Resolve*(), then !rp.Done(). @@ -216,19 +216,19 @@ type FilesystemImpl interface { // // Errors: // - // - If the last path component in rp is "." or "..", MknodAt returns - // EEXIST. + // - If the last path component in rp is "." or "..", MknodAt returns + // EEXIST. // - // - If a file already exists at rp, MknodAt returns EEXIST. + // - If a file already exists at rp, MknodAt returns EEXIST. // - // - If rp.MustBeDir(), MknodAt returns ENOENT. + // - If rp.MustBeDir(), MknodAt returns ENOENT. // - // - If the directory in which the file would be created has been removed - // by RmdirAt or RenameAt, MknodAt returns ENOENT. + // - If the directory in which the file would be created has been removed + // by RmdirAt or RenameAt, MknodAt returns ENOENT. // // Preconditions: - // * !rp.Done(). - // * For the final path component in rp, !rp.ShouldFollowSymlink(). + // * !rp.Done(). + // * For the final path component in rp, !rp.ShouldFollowSymlink(). // // Postconditions: If MknodAt returns an error returned by // ResolvingPath.Resolve*(), then !rp.Done(). @@ -239,16 +239,16 @@ type FilesystemImpl interface { // // Errors: // - // - If opts.Flags specifies O_TMPFILE and this feature is unsupported by - // the implementation, OpenAt returns EOPNOTSUPP. (All other unsupported - // features are silently ignored, consistently with Linux's open*(2).) + // - If opts.Flags specifies O_TMPFILE and this feature is unsupported by + // the implementation, OpenAt returns EOPNOTSUPP. (All other unsupported + // features are silently ignored, consistently with Linux's open*(2).) OpenAt(ctx context.Context, rp *ResolvingPath, opts OpenOptions) (*FileDescription, error) // ReadlinkAt returns the target of the symbolic link at rp. // // Errors: // - // - If the file at rp is not a symbolic link, ReadlinkAt returns EINVAL. + // - If the file at rp is not a symbolic link, ReadlinkAt returns EINVAL. ReadlinkAt(ctx context.Context, rp *ResolvingPath) (string, error) // RenameAt renames the file named oldName in directory oldParentVD to rp. @@ -256,75 +256,75 @@ type FilesystemImpl interface { // // Errors [1]: // - // - If opts.Flags specifies unsupported options, RenameAt returns EINVAL. + // - If opts.Flags specifies unsupported options, RenameAt returns EINVAL. // - // - If the last path component in rp is "." or "..", and opts.Flags - // contains RENAME_NOREPLACE, RenameAt returns EEXIST. + // - If the last path component in rp is "." or "..", and opts.Flags + // contains RENAME_NOREPLACE, RenameAt returns EEXIST. // - // - If the last path component in rp is "." or "..", and opts.Flags does - // not contain RENAME_NOREPLACE, RenameAt returns EBUSY. + // - If the last path component in rp is "." or "..", and opts.Flags does + // not contain RENAME_NOREPLACE, RenameAt returns EBUSY. // - // - If rp.Mount != oldParentVD.Mount(), RenameAt returns EXDEV. + // - If rp.Mount != oldParentVD.Mount(), RenameAt returns EXDEV. // - // - If the renamed file is not a directory, and opts.MustBeDir is true, - // RenameAt returns ENOTDIR. + // - If the renamed file is not a directory, and opts.MustBeDir is true, + // RenameAt returns ENOTDIR. // - // - If renaming would replace an existing file and opts.Flags contains - // RENAME_NOREPLACE, RenameAt returns EEXIST. + // - If renaming would replace an existing file and opts.Flags contains + // RENAME_NOREPLACE, RenameAt returns EEXIST. // - // - If there is no existing file at rp and opts.Flags contains - // RENAME_EXCHANGE, RenameAt returns ENOENT. + // - If there is no existing file at rp and opts.Flags contains + // RENAME_EXCHANGE, RenameAt returns ENOENT. // - // - If there is an existing non-directory file at rp, and rp.MustBeDir() - // is true, RenameAt returns ENOTDIR. + // - If there is an existing non-directory file at rp, and rp.MustBeDir() + // is true, RenameAt returns ENOTDIR. // - // - If the renamed file is not a directory, opts.Flags does not contain - // RENAME_EXCHANGE, and rp.MustBeDir() is true, RenameAt returns ENOTDIR. - // (This check is not subsumed by the check for directory replacement below - // since it applies even if there is no file to replace.) + // - If the renamed file is not a directory, opts.Flags does not contain + // RENAME_EXCHANGE, and rp.MustBeDir() is true, RenameAt returns ENOTDIR. + // (This check is not subsumed by the check for directory replacement below + // since it applies even if there is no file to replace.) // - // - If the renamed file is a directory, and the new parent directory of - // the renamed file is either the renamed directory or a descendant - // subdirectory of the renamed directory, RenameAt returns EINVAL. + // - If the renamed file is a directory, and the new parent directory of + // the renamed file is either the renamed directory or a descendant + // subdirectory of the renamed directory, RenameAt returns EINVAL. // - // - If renaming would exchange the renamed file with an ancestor directory - // of the renamed file, RenameAt returns EINVAL. + // - If renaming would exchange the renamed file with an ancestor directory + // of the renamed file, RenameAt returns EINVAL. // - // - If renaming would replace an ancestor directory of the renamed file, - // RenameAt returns ENOTEMPTY. (This check would be subsumed by the - // non-empty directory check below; however, this check takes place before - // the self-rename check.) + // - If renaming would replace an ancestor directory of the renamed file, + // RenameAt returns ENOTEMPTY. (This check would be subsumed by the + // non-empty directory check below; however, this check takes place before + // the self-rename check.) // - // - If the renamed file would replace or exchange with itself (i.e. the - // source and destination paths resolve to the same file), RenameAt returns - // nil, skipping the checks described below. + // - If the renamed file would replace or exchange with itself (i.e. the + // source and destination paths resolve to the same file), RenameAt returns + // nil, skipping the checks described below. // - // - If the source or destination directory is not writable by the provider - // of rp.Credentials(), RenameAt returns EACCES. + // - If the source or destination directory is not writable by the provider + // of rp.Credentials(), RenameAt returns EACCES. // - // - If the renamed file is a directory, and renaming would replace a - // non-directory file, RenameAt returns ENOTDIR. + // - If the renamed file is a directory, and renaming would replace a + // non-directory file, RenameAt returns ENOTDIR. // - // - If the renamed file is not a directory, and renaming would replace a - // directory, RenameAt returns EISDIR. + // - If the renamed file is not a directory, and renaming would replace a + // directory, RenameAt returns EISDIR. // - // - If the new parent directory of the renamed file has been removed by - // RmdirAt or a preceding call to RenameAt, RenameAt returns ENOENT. + // - If the new parent directory of the renamed file has been removed by + // RmdirAt or a preceding call to RenameAt, RenameAt returns ENOENT. // - // - If the renamed file is a directory, it is not writable by the - // provider of rp.Credentials(), and the source and destination parent - // directories are different, RenameAt returns EACCES. (This is nominally - // required to change the ".." entry in the renamed directory.) + // - If the renamed file is a directory, it is not writable by the + // provider of rp.Credentials(), and the source and destination parent + // directories are different, RenameAt returns EACCES. (This is nominally + // required to change the ".." entry in the renamed directory.) // - // - If renaming would replace a non-empty directory, RenameAt returns - // ENOTEMPTY. + // - If renaming would replace a non-empty directory, RenameAt returns + // ENOTEMPTY. // // Preconditions: - // * !rp.Done(). - // * For the final path component in rp, !rp.ShouldFollowSymlink(). - // * oldParentVD.Dentry() was obtained from a previous call to - // oldParentVD.Mount().Filesystem().Impl().GetParentDentryAt(). - // * oldName is not "." or "..". + // * !rp.Done(). + // * For the final path component in rp, !rp.ShouldFollowSymlink(). + // * oldParentVD.Dentry() was obtained from a previous call to + // oldParentVD.Mount().Filesystem().Impl().GetParentDentryAt(). + // * oldName is not "." or "..". // // Postconditions: If RenameAt returns an error returned by // ResolvingPath.Resolve*(), then !rp.Done(). @@ -338,18 +338,18 @@ type FilesystemImpl interface { // // Errors: // - // - If the last path component in rp is ".", RmdirAt returns EINVAL. + // - If the last path component in rp is ".", RmdirAt returns EINVAL. // - // - If the last path component in rp is "..", RmdirAt returns ENOTEMPTY. + // - If the last path component in rp is "..", RmdirAt returns ENOTEMPTY. // - // - If no file exists at rp, RmdirAt returns ENOENT. + // - If no file exists at rp, RmdirAt returns ENOENT. // - // - If the file at rp exists but is not a directory, RmdirAt returns - // ENOTDIR. + // - If the file at rp exists but is not a directory, RmdirAt returns + // ENOTDIR. // // Preconditions: - // * !rp.Done(). - // * For the final path component in rp, !rp.ShouldFollowSymlink(). + // * !rp.Done(). + // * For the final path component in rp, !rp.ShouldFollowSymlink(). // // Postconditions: If RmdirAt returns an error returned by // ResolvingPath.Resolve*(), then !rp.Done(). @@ -361,7 +361,7 @@ type FilesystemImpl interface { // // Errors: // - // - If opts specifies unsupported options, SetStatAt returns EINVAL. + // - If opts specifies unsupported options, SetStatAt returns EINVAL. SetStatAt(ctx context.Context, rp *ResolvingPath, opts SetStatOptions) error // StatAt returns metadata for the file at rp. @@ -376,19 +376,19 @@ type FilesystemImpl interface { // // Errors: // - // - If the last path component in rp is "." or "..", SymlinkAt returns - // EEXIST. + // - If the last path component in rp is "." or "..", SymlinkAt returns + // EEXIST. // - // - If a file already exists at rp, SymlinkAt returns EEXIST. + // - If a file already exists at rp, SymlinkAt returns EEXIST. // - // - If rp.MustBeDir(), SymlinkAt returns ENOENT. + // - If rp.MustBeDir(), SymlinkAt returns ENOENT. // - // - If the directory in which the symbolic link would be created has been - // removed by RmdirAt or RenameAt, SymlinkAt returns ENOENT. + // - If the directory in which the symbolic link would be created has been + // removed by RmdirAt or RenameAt, SymlinkAt returns ENOENT. // // Preconditions: - // * !rp.Done(). - // * For the final path component in rp, !rp.ShouldFollowSymlink(). + // * !rp.Done(). + // * For the final path component in rp, !rp.ShouldFollowSymlink(). // // Postconditions: If SymlinkAt returns an error returned by // ResolvingPath.Resolve*(), then !rp.Done(). @@ -398,19 +398,19 @@ type FilesystemImpl interface { // // Errors: // - // - If the last path component in rp is "." or "..", UnlinkAt returns - // EISDIR. + // - If the last path component in rp is "." or "..", UnlinkAt returns + // EISDIR. // - // - If no file exists at rp, UnlinkAt returns ENOENT. + // - If no file exists at rp, UnlinkAt returns ENOENT. // - // - If rp.MustBeDir(), and the file at rp exists and is not a directory, - // UnlinkAt returns ENOTDIR. + // - If rp.MustBeDir(), and the file at rp exists and is not a directory, + // UnlinkAt returns ENOTDIR. // - // - If the file at rp exists but is a directory, UnlinkAt returns EISDIR. + // - If the file at rp exists but is a directory, UnlinkAt returns EISDIR. // // Preconditions: - // * !rp.Done(). - // * For the final path component in rp, !rp.ShouldFollowSymlink(). + // * !rp.Done(). + // * For the final path component in rp, !rp.ShouldFollowSymlink(). // // Postconditions: If UnlinkAt returns an error returned by // ResolvingPath.Resolve*(), then !rp.Done(). @@ -420,14 +420,14 @@ type FilesystemImpl interface { // // Errors: // - // - If extended attributes are not supported by the filesystem, - // ListXattrAt returns ENOTSUP. + // - If extended attributes are not supported by the filesystem, + // ListXattrAt returns ENOTSUP. // - // - If the size of the list (including a NUL terminating byte after every - // entry) would exceed size, ERANGE may be returned. Note that - // implementations are free to ignore size entirely and return without - // error). In all cases, if size is 0, the list should be returned without - // error, regardless of size. + // - If the size of the list (including a NUL terminating byte after every + // entry) would exceed size, ERANGE may be returned. Note that + // implementations are free to ignore size entirely and return without + // error). In all cases, if size is 0, the list should be returned without + // error, regardless of size. ListXattrAt(ctx context.Context, rp *ResolvingPath, size uint64) ([]string, error) // GetXattrAt returns the value associated with the given extended @@ -435,16 +435,16 @@ type FilesystemImpl interface { // // Errors: // - // - If extended attributes are not supported by the filesystem, GetXattrAt - // returns ENOTSUP. + // - If extended attributes are not supported by the filesystem, GetXattrAt + // returns ENOTSUP. // - // - If an extended attribute named opts.Name does not exist, ENODATA is - // returned. + // - If an extended attribute named opts.Name does not exist, ENODATA is + // returned. // - // - If the size of the return value exceeds opts.Size, ERANGE may be - // returned (note that implementations are free to ignore opts.Size entirely - // and return without error). In all cases, if opts.Size is 0, the value - // should be returned without error, regardless of size. + // - If the size of the return value exceeds opts.Size, ERANGE may be + // returned (note that implementations are free to ignore opts.Size entirely + // and return without error). In all cases, if opts.Size is 0, the value + // should be returned without error, regardless of size. GetXattrAt(ctx context.Context, rp *ResolvingPath, opts GetXattrOptions) (string, error) // SetXattrAt changes the value associated with the given extended @@ -452,33 +452,33 @@ type FilesystemImpl interface { // // Errors: // - // - If extended attributes are not supported by the filesystem, SetXattrAt - // returns ENOTSUP. + // - If extended attributes are not supported by the filesystem, SetXattrAt + // returns ENOTSUP. // - // - If XATTR_CREATE is set in opts.Flag and opts.Name already exists, - // EEXIST is returned. If XATTR_REPLACE is set and opts.Name does not exist, - // ENODATA is returned. + // - If XATTR_CREATE is set in opts.Flag and opts.Name already exists, + // EEXIST is returned. If XATTR_REPLACE is set and opts.Name does not exist, + // ENODATA is returned. SetXattrAt(ctx context.Context, rp *ResolvingPath, opts SetXattrOptions) error // RemoveXattrAt removes the given extended attribute from the file at rp. // // Errors: // - // - If extended attributes are not supported by the filesystem, - // RemoveXattrAt returns ENOTSUP. + // - If extended attributes are not supported by the filesystem, + // RemoveXattrAt returns ENOTSUP. // - // - If name does not exist, ENODATA is returned. + // - If name does not exist, ENODATA is returned. RemoveXattrAt(ctx context.Context, rp *ResolvingPath, name string) error // BoundEndpointAt returns the Unix socket endpoint bound at the path rp. // // Errors: // - // - If the file does not have write permissions, then BoundEndpointAt - // returns EACCES. + // - If the file does not have write permissions, then BoundEndpointAt + // returns EACCES. // - // - If a non-socket file exists at rp, then BoundEndpointAt returns - // ECONNREFUSED. + // - If a non-socket file exists at rp, then BoundEndpointAt returns + // ECONNREFUSED. BoundEndpointAt(ctx context.Context, rp *ResolvingPath, opts BoundEndpointOptions) (transport.BoundEndpoint, error) // PrependPath prepends a path from vd to vd.Mount().Root() to b. diff --git a/pkg/sentry/vfs/filesystem_impl_util.go b/pkg/sentry/vfs/filesystem_impl_util.go index 15b234d61..b16c41fa5 100644 --- a/pkg/sentry/vfs/filesystem_impl_util.go +++ b/pkg/sentry/vfs/filesystem_impl_util.go @@ -26,7 +26,7 @@ import ( // returns it as a map. If str contains duplicate keys, then the last value // wins. For example: // -// str = "key0=value0,key1,key2=value2,key0=value3" -> map{'key0':'value3','key1':'','key2':'value2'} +// str = "key0=value0,key1,key2=value2,key0=value3" -> map{'key0':'value3','key1':”,'key2':'value2'} // // GenericParseMountOptions is not appropriate if values may contain commas, // e.g. in the case of the mpol mount option for tmpfs(5). diff --git a/pkg/sentry/vfs/mount.go b/pkg/sentry/vfs/mount.go index 321e1c2d4..1854813a6 100644 --- a/pkg/sentry/vfs/mount.go +++ b/pkg/sentry/vfs/mount.go @@ -398,8 +398,8 @@ type umountRecursiveOptions struct { // umountRecursiveLocked is analogous to Linux's fs/namespace.c:umount_tree(). // // Preconditions: -// * vfs.mountMu must be locked. -// * vfs.mounts.seq must be in a writer critical section. +// - vfs.mountMu must be locked. +// - vfs.mounts.seq must be in a writer critical section. func (vfs *VirtualFilesystem) umountRecursiveLocked(mnt *Mount, opts *umountRecursiveOptions, vdsToDecRef []VirtualDentry, mountsToDecRef []*Mount) ([]VirtualDentry, []*Mount) { if !mnt.umounted { mnt.umounted = true @@ -429,10 +429,10 @@ func (vfs *VirtualFilesystem) umountRecursiveLocked(mnt *Mount, opts *umountRecu // references held by vd. // // Preconditions: -// * vfs.mountMu must be locked. -// * vfs.mounts.seq must be in a writer critical section. -// * d.mu must be locked. -// * mnt.parent() == nil, i.e. mnt must not already be connected. +// - vfs.mountMu must be locked. +// - vfs.mounts.seq must be in a writer critical section. +// - d.mu must be locked. +// - mnt.parent() == nil, i.e. mnt must not already be connected. func (vfs *VirtualFilesystem) connectLocked(mnt *Mount, vd VirtualDentry, mntns *MountNamespace) { if checkInvariants { if mnt.parent() != nil { @@ -461,9 +461,9 @@ func (vfs *VirtualFilesystem) connectLocked(mnt *Mount, vd VirtualDentry, mntns // mount parent/point with a reference held. // // Preconditions: -// * vfs.mountMu must be locked. -// * vfs.mounts.seq must be in a writer critical section. -// * mnt.parent() != nil. +// - vfs.mountMu must be locked. +// - vfs.mounts.seq must be in a writer critical section. +// - mnt.parent() != nil. func (vfs *VirtualFilesystem) disconnectLocked(mnt *Mount) VirtualDentry { vd := mnt.getKey() if checkInvariants { @@ -595,12 +595,12 @@ func (mntns *MountNamespace) DecRef(ctx context.Context) { func (vfs *VirtualFilesystem) getMountAt(ctx context.Context, mnt *Mount, d *Dentry) *Mount { // The first mount is special-cased: // - // - The caller is assumed to have checked d.isMounted() already. (This - // isn't a precondition because it doesn't matter for correctness.) + // - The caller is assumed to have checked d.isMounted() already. (This + // isn't a precondition because it doesn't matter for correctness.) // - // - We return nil, instead of mnt, if there is no mount at (mnt, d). + // - We return nil, instead of mnt, if there is no mount at (mnt, d). // - // - We don't drop the caller's references on mnt and d. + // - We don't drop the caller's references on mnt and d. retryFirst: next := vfs.mounts.Lookup(mnt, d) if next == nil { @@ -635,16 +635,16 @@ retryFirst: // point exists (i.e. mnt is a root mount), getMountpointAt returns (nil, nil). // // Preconditions: -// * References are held on mnt and root. -// * vfsroot is not (mnt, mnt.root). +// - References are held on mnt and root. +// - vfsroot is not (mnt, mnt.root). func (vfs *VirtualFilesystem) getMountpointAt(ctx context.Context, mnt *Mount, vfsroot VirtualDentry) VirtualDentry { // The first mount is special-cased: // - // - The caller must have already checked mnt against vfsroot. + // - The caller must have already checked mnt against vfsroot. // - // - We return nil, instead of mnt, if there is no mount point for mnt. + // - We return nil, instead of mnt, if there is no mount point for mnt. // - // - We don't drop the caller's reference on mnt. + // - We don't drop the caller's reference on mnt. retryFirst: epoch := vfs.mounts.seq.BeginRead() parent, point := mnt.parent(), mnt.point() diff --git a/pkg/sentry/vfs/mount_test.go b/pkg/sentry/vfs/mount_test.go index cb882a983..060dd8c7c 100644 --- a/pkg/sentry/vfs/mount_test.go +++ b/pkg/sentry/vfs/mount_test.go @@ -62,13 +62,14 @@ var benchNumMounts = []int{1 << 2, 1 << 5, 1 << 8} // For all of the following: // -// - BenchmarkMountTableFoo tests usage pattern "Foo" for mountTable. +// - BenchmarkMountTableFoo tests usage pattern "Foo" for mountTable. +// +// - BenchmarkMountMapFoo tests usage pattern "Foo" for a // -// - BenchmarkMountMapFoo tests usage pattern "Foo" for a // sync.RWMutex-protected map. (Mutator benchmarks do not use a RWMutex, since // mountTable also requires external synchronization between mutators.) // -// - BenchmarkMountSyncMapFoo tests usage pattern "Foo" for a sync.Map. +// - BenchmarkMountSyncMapFoo tests usage pattern "Foo" for a sync.Map. // // ParallelLookup is by far the most common and performance-sensitive operation // for this application. NegativeLookup is also important, but less so (only diff --git a/pkg/sentry/vfs/mount_unsafe.go b/pkg/sentry/vfs/mount_unsafe.go index e7eaa838b..9499d6547 100644 --- a/pkg/sentry/vfs/mount_unsafe.go +++ b/pkg/sentry/vfs/mount_unsafe.go @@ -240,8 +240,8 @@ func (mt *mountTable) Insert(mount *Mount) { // insertSeqed inserts the given mount into mt. // // Preconditions: -// * mt.seq must be in a writer critical section. -// * mt must not already contain a Mount with the same mount point and parent. +// - mt.seq must be in a writer critical section. +// - mt must not already contain a Mount with the same mount point and parent. func (mt *mountTable) insertSeqed(mount *Mount) { hash := mount.key.hash() @@ -293,10 +293,10 @@ func (mt *mountTable) insertSeqed(mount *Mount) { } // Preconditions: -// * There are no concurrent mutators of the table (slots, cap). -// * If the table is visible to readers, then mt.seq must be in a writer -// critical section. -// * cap must be a power of 2. +// - There are no concurrent mutators of the table (slots, cap). +// - If the table is visible to readers, then mt.seq must be in a writer +// critical section. +// - cap must be a power of 2. func mtInsertLocked(slots unsafe.Pointer, cap uintptr, value unsafe.Pointer, hash uintptr) { mask := cap - 1 off := (hash & mask) * mountSlotBytes @@ -339,8 +339,8 @@ func (mt *mountTable) Remove(mount *Mount) { // removeSeqed removes the given mount from mt. // // Preconditions: -// * mt.seq must be in a writer critical section. -// * mt must contain mount. +// - mt.seq must be in a writer critical section. +// - mt must contain mount. func (mt *mountTable) removeSeqed(mount *Mount) { hash := mount.key.hash() tcap := uintptr(1) << (mt.size.RacyLoad() & mtSizeOrderMask) diff --git a/pkg/sentry/vfs/pathname.go b/pkg/sentry/vfs/pathname.go index 7cc68a157..66d385973 100644 --- a/pkg/sentry/vfs/pathname.go +++ b/pkg/sentry/vfs/pathname.go @@ -185,11 +185,11 @@ loop: // As of this writing, we do not have equivalents to: // -// - d_absolute_path(), which returns EINVAL if (effectively) any call to -// FilesystemImpl.PrependPath() would return PrependPathAtNonMountRootError. +// - d_absolute_path(), which returns EINVAL if (effectively) any call to +// FilesystemImpl.PrependPath() would return PrependPathAtNonMountRootError. // -// - dentry_path(), which does not walk up mounts (and only returns the path -// relative to Filesystem root), but also appends "//deleted" for disowned -// Dentries. +// - dentry_path(), which does not walk up mounts (and only returns the path +// relative to Filesystem root), but also appends "//deleted" for disowned +// Dentries. // // These should be added as necessary. diff --git a/pkg/sentry/vfs/permissions.go b/pkg/sentry/vfs/permissions.go index 953d31876..16e653a23 100644 --- a/pkg/sentry/vfs/permissions.go +++ b/pkg/sentry/vfs/permissions.go @@ -132,14 +132,14 @@ func MayLink(creds *auth.Credentials, mode linux.FileMode, kuid auth.KUID, kgid // with the given OpenOptions.Flags. Note that this is NOT the same thing as // the set of accesses permitted for the opened file: // -// - O_TRUNC causes MayWrite to be set in the returned AccessTypes (since it -// mutates the file), but does not permit writing to the open file description -// thereafter. +// - O_TRUNC causes MayWrite to be set in the returned AccessTypes (since it +// mutates the file), but does not permit writing to the open file description +// thereafter. // -// - "Linux reserves the special, nonstandard access mode 3 (binary 11) in -// flags to mean: check for read and write permission on the file and return a -// file descriptor that can't be used for reading or writing." - open(2). Thus -// AccessTypesForOpenFlags returns MayRead|MayWrite in this case. +// - "Linux reserves the special, nonstandard access mode 3 (binary 11) in +// flags to mean: check for read and write permission on the file and return a +// file descriptor that can't be used for reading or writing." - open(2). Thus +// AccessTypesForOpenFlags returns MayRead|MayWrite in this case. // // Use May{Read,Write}FileWithOpenFlags() for these checks instead. func AccessTypesForOpenFlags(opts *OpenOptions) AccessTypes { @@ -292,11 +292,11 @@ func CheckLimit(ctx context.Context, offset, size int64) (int64, error) { // CheckXattrPermissions checks permissions for extended attribute access. // This is analogous to fs/xattr.c:xattr_permission(). Some key differences: -// * Does not check for read-only filesystem property. -// * Does not check inode immutability or append only mode. In both cases EPERM -// must be returned by filesystem implementations. -// * Does not do inode permission checks. Filesystem implementations should -// handle inode permission checks as they may differ across implementations. +// - Does not check for read-only filesystem property. +// - Does not check inode immutability or append only mode. In both cases EPERM +// must be returned by filesystem implementations. +// - Does not do inode permission checks. Filesystem implementations should +// handle inode permission checks as they may differ across implementations. func CheckXattrPermissions(creds *auth.Credentials, ats AccessTypes, mode linux.FileMode, kuid auth.KUID, name string) error { switch { case strings.HasPrefix(name, linux.XATTR_TRUSTED_PREFIX): diff --git a/pkg/sentry/vfs/resolving_path.go b/pkg/sentry/vfs/resolving_path.go index 40aff2927..028801956 100644 --- a/pkg/sentry/vfs/resolving_path.go +++ b/pkg/sentry/vfs/resolving_path.go @@ -307,6 +307,7 @@ func (rp *ResolvingPath) CheckMount(ctx context.Context, d *Dentry) error { // // If path is terminated with '/', the '/' is considered the last element and // any symlink before that is followed: +// // - For most non-creating walks, the last path component is handled by // fs/namei.c:lookup_last(), which sets LOOKUP_FOLLOW if the first byte // after the path component is non-NULL (which is only possible if it's '/') diff --git a/pkg/sentry/vfs/vfs.go b/pkg/sentry/vfs/vfs.go index 00f8efce9..acf03fb27 100644 --- a/pkg/sentry/vfs/vfs.go +++ b/pkg/sentry/vfs/vfs.go @@ -16,19 +16,19 @@ // // Lock order: // -// EpollInstance.interestMu -// FileDescription.epollMu -// Locks acquired by FilesystemImpl/FileDescriptionImpl methods -// VirtualFilesystem.mountMu -// Dentry.mu -// Locks acquired by FilesystemImpls between Prepare{Delete,Rename}Dentry and Commit{Delete,Rename*}Dentry -// VirtualFilesystem.filesystemsMu -// fdnotifier.notifier.mu -// EpollInstance.readyMu -// Inotify.mu -// Watches.mu -// Inotify.evMu -// VirtualFilesystem.fsTypesMu +// EpollInstance.interestMu +// FileDescription.epollMu +// Locks acquired by FilesystemImpl/FileDescriptionImpl methods +// VirtualFilesystem.mountMu +// Dentry.mu +// Locks acquired by FilesystemImpls between Prepare{Delete,Rename}Dentry and Commit{Delete,Rename*}Dentry +// VirtualFilesystem.filesystemsMu +// fdnotifier.notifier.mu +// EpollInstance.readyMu +// Inotify.mu +// Watches.mu +// Inotify.evMu +// VirtualFilesystem.fsTypesMu // // Locking Dentry.mu in multiple Dentries requires holding // VirtualFilesystem.mountMu. Locking EpollInstance.interestMu in multiple @@ -383,10 +383,10 @@ func (vfs *VirtualFilesystem) OpenAt(ctx context.Context, creds *auth.Credential // Remove: // - // - O_CLOEXEC, which affects file descriptors and therefore must be - // handled outside of VFS. + // - O_CLOEXEC, which affects file descriptors and therefore must be + // handled outside of VFS. // - // - Unknown flags. + // - Unknown flags. opts.Flags &= linux.O_ACCMODE | linux.O_CREAT | linux.O_EXCL | linux.O_NOCTTY | linux.O_TRUNC | linux.O_APPEND | linux.O_NONBLOCK | linux.O_DSYNC | linux.O_ASYNC | linux.O_DIRECT | linux.O_LARGEFILE | linux.O_DIRECTORY | linux.O_NOFOLLOW | linux.O_NOATIME | linux.O_SYNC | linux.O_PATH | linux.O_TMPFILE // Linux's __O_SYNC (which we call linux.O_SYNC) implies O_DSYNC. if opts.Flags&linux.O_SYNC != 0 { diff --git a/pkg/sentry/watchdog/watchdog.go b/pkg/sentry/watchdog/watchdog.go index e8f7d1f01..cabe58b93 100644 --- a/pkg/sentry/watchdog/watchdog.go +++ b/pkg/sentry/watchdog/watchdog.go @@ -22,11 +22,10 @@ // without blocking are considered stuck and are reported. // // When a stuck task is detected, the watchdog can take one of the following actions: -// 1. LogWarning: Logs a warning message followed by a stack dump of all goroutines. -// If a tasks continues to be stuck, the message will repeat every minute, unless -// a new stuck task is detected -// 2. Panic: same as above, followed by panic() -// +// 1. LogWarning: Logs a warning message followed by a stack dump of all goroutines. +// If a tasks continues to be stuck, the message will repeat every minute, unless +// a new stuck task is detected +// 2. Panic: same as above, followed by panic() package watchdog import ( diff --git a/pkg/shim/service.go b/pkg/shim/service.go index 1ac6c5fa4..80ce0c0af 100644 --- a/pkg/shim/service.go +++ b/pkg/shim/service.go @@ -136,11 +136,11 @@ func New(ctx context.Context, id string, publisher shim.Publisher, cancel func() // service is the shim implementation of a remote shim over GRPC. It runs in 2 // different modes: -// 1. Service: process runs for the life time of the container and receives -// calls described in shimapi.TaskService interface. -// 2. Tool: process is short lived and runs only to perform the requested -// operations and then exits. It implements the direct functions in -// shim.Shim interface. +// 1. Service: process runs for the life time of the container and receives +// calls described in shimapi.TaskService interface. +// 2. Tool: process is short lived and runs only to perform the requested +// operations and then exits. It implements the direct functions in +// shim.Shim interface. // // When the service is running, it saves a json file with state information so // that commands sent to the tool can load the state and perform the operation. @@ -1105,8 +1105,7 @@ func newInit(path, workDir, namespace string, platform stdio.Platform, r *proc.C // path. If found, it's set as an annotation in the spec. This is done so that // the sandbox joins the pod cgroup. Otherwise, the sandbox would join the pause // container cgroup. Returns true if the spec was modified. Ex.: -// /kubepods/burstable/pod123/container123 => kubepods/burstable/pod123 -// +// /kubepods/burstable/pod123/container123 => kubepods/burstable/pod123 func setPodCgroup(spec *specs.Spec) bool { if !utils.IsSandbox(spec) { return false diff --git a/pkg/shim/utils/volumes.go b/pkg/shim/utils/volumes.go index f8090109d..5dd7abc63 100644 --- a/pkg/shim/utils/volumes.go +++ b/pkg/shim/utils/volumes.go @@ -33,12 +33,14 @@ const ( var kubeletPodsDir = "/var/lib/kubelet/pods" // volumeName gets volume name from volume annotation key, example: +// // dev.gvisor.spec.mount.NAME.share func volumeName(k string) string { return strings.SplitN(strings.TrimPrefix(k, volumeKeyPrefix), ".", 2)[0] } // volumeFieldName gets volume field name from volume annotation key, example: +// // `type` is the field of dev.gvisor.spec.mount.NAME.type func volumeFieldName(k string) string { parts := strings.Split(strings.TrimPrefix(k, volumeKeyPrefix), ".") diff --git a/pkg/sleep/sleep_unsafe.go b/pkg/sleep/sleep_unsafe.go index 3457a3f06..822c0f423 100644 --- a/pkg/sleep/sleep_unsafe.go +++ b/pkg/sleep/sleep_unsafe.go @@ -166,6 +166,7 @@ func (s *Sleeper) AddWaker(w *Waker) { // block, then we will need to explicitly wake a runtime P. // // Precondition: wakepOrSleep may be true iff block is true. +// //go:nosplit func (s *Sleeper) nextWaker(block, wakepOrSleep bool) *Waker { // Attempt to replenish the local list if it's currently empty. @@ -248,6 +249,7 @@ func commitSleep(g uintptr, waitingG unsafe.Pointer) bool { // fetch is the backing implementation for Fetch and AssertAndFetch. // // Preconditions are the same as nextWaker. +// //go:nosplit func (s *Sleeper) fetch(block, wakepOrSleep bool) *Waker { for { @@ -272,7 +274,7 @@ func (s *Sleeper) fetch(block, wakepOrSleep bool) *Waker { // asserted waker; if false, nil will be returned. // // N.B. This method is *not* thread-safe. Only one goroutine at a time is -// allowed to call this method. +// allowed to call this method. func (s *Sleeper) Fetch(block bool) *Waker { return s.fetch(block, false /* wakepOrSleep */) } @@ -282,8 +284,10 @@ func (s *Sleeper) Fetch(block bool) *Waker { // non-blocking operation. // // N.B. Like Fetch, this method is *not* thread-safe. This will also yield the current -// P to the next goroutine, avoiding associated scheduled overhead. +// P to the next goroutine, avoiding associated scheduled overhead. +// // +checkescape:all +// //go:nosplit func (s *Sleeper) AssertAndFetch(n *Waker) *Waker { n.assert(false /* wakep */) @@ -326,6 +330,7 @@ func (s *Sleeper) Done() { // enqueueAssertedWaker enqueues an asserted waker to the "ready" circular list // of wakers that want to notify the sleeper. +// //go:nosplit func (s *Sleeper) enqueueAssertedWaker(w *Waker, wakep bool) { // Add the new waker to the front of the list. @@ -412,6 +417,7 @@ func (w *Waker) loadS(ws wakerState) { } // assert is the implementation for Assert. +// //go:nosplit func (w *Waker) assert(wakep bool) { // Nothing to do if the waker is already asserted. This check allows us diff --git a/pkg/state/decode_unsafe.go b/pkg/state/decode_unsafe.go index f1208e2a2..a2fdf117a 100644 --- a/pkg/state/decode_unsafe.go +++ b/pkg/state/decode_unsafe.go @@ -35,9 +35,9 @@ func reflectValueRWAddr(obj reflect.Value) reflect.Value { // the use of unexported struct fields. // // Preconditions: -// * arr.Kind() == reflect.Array. -// * i, j, k >= 0. -// * i <= j <= k <= arr.Len(). +// - arr.Kind() == reflect.Array. +// - i, j, k >= 0. +// - i <= j <= k <= arr.Len(). func reflectValueRWSlice3(arr reflect.Value, i, j, k int) reflect.Value { if arr.Kind() != reflect.Array { panic(fmt.Sprintf("arr has kind %v, wanted %v", arr.Kind(), reflect.Array)) diff --git a/pkg/state/encode.go b/pkg/state/encode.go index 560e7c2a3..157ac0dd2 100644 --- a/pkg/state/encode.go +++ b/pkg/state/encode.go @@ -112,13 +112,13 @@ type encodeState struct { // // isSameSizeParent deals with objects like this: // -// struct child { -// // fields.. -// } +// struct child { +// // fields.. +// } // -// struct parent { -// c child -// } +// struct parent { +// c child +// } // // var p parent // record(&p.c) @@ -127,9 +127,9 @@ type encodeState struct { // // Or like this: // -// struct child { -// // fields -// } +// struct child { +// // fields +// } // // var arr [1]parent // record(&arr[0]) diff --git a/pkg/state/encode_unsafe.go b/pkg/state/encode_unsafe.go index e0dad83b4..78e36e76c 100644 --- a/pkg/state/encode_unsafe.go +++ b/pkg/state/encode_unsafe.go @@ -25,7 +25,6 @@ import ( // // x := make([]Foo, l, c) // a := ([l]Foo*)(unsafe.Pointer(x[0])) -// func arrayFromSlice(obj reflect.Value) reflect.Value { return reflect.NewAt( reflect.ArrayOf(obj.Cap(), obj.Type().Elem()), diff --git a/pkg/state/state.go b/pkg/state/state.go index 6b8540f03..ff4b30c36 100644 --- a/pkg/state/state.go +++ b/pkg/state/state.go @@ -16,33 +16,33 @@ // graphs. For most types, it provides a set of default saving / loading logic // that will be invoked automatically if custom logic is not defined. // -// Kind Support -// ---- ------- -// Bool default -// Int default -// Int8 default -// Int16 default -// Int32 default -// Int64 default -// Uint default -// Uint8 default -// Uint16 default -// Uint32 default -// Uint64 default -// Float32 default -// Float64 default -// Complex64 default -// Complex128 default -// Array default -// Chan custom -// Func custom -// Interface default -// Map default -// Ptr default -// Slice default -// String default -// Struct custom (*) Unless zero-sized. -// UnsafePointer custom +// Kind Support +// ---- ------- +// Bool default +// Int default +// Int8 default +// Int16 default +// Int32 default +// Int64 default +// Uint default +// Uint8 default +// Uint16 default +// Uint32 default +// Uint64 default +// Float32 default +// Float64 default +// Complex64 default +// Complex128 default +// Array default +// Chan custom +// Func custom +// Interface default +// Map default +// Ptr default +// Slice default +// String default +// Struct custom (*) Unless zero-sized. +// UnsafePointer custom // // See README.md for an overview of how encoding and decoding works. package state @@ -131,30 +131,30 @@ type Sink struct { // // You should pass always pointers to the object you are saving. For example: // -// type X struct { -// A int -// B *int -// } -// -// func (x *X) StateTypeInfo(m Sink) state.TypeInfo { -// return state.TypeInfo{ -// Name: "pkg.X", -// Fields: []string{ -// "A", -// "B", -// }, +// type X struct { +// A int +// B *int // } -// } // -// func (x *X) StateSave(m Sink) { -// m.Save(0, &x.A) // Field is A. -// m.Save(1, &x.B) // Field is B. -// } +// func (x *X) StateTypeInfo(m Sink) state.TypeInfo { +// return state.TypeInfo{ +// Name: "pkg.X", +// Fields: []string{ +// "A", +// "B", +// }, +// } +// } // -// func (x *X) StateLoad(m Source) { -// m.Load(0, &x.A) // Field is A. -// m.Load(1, &x.B) // Field is B. -// } +// func (x *X) StateSave(m Sink) { +// m.Save(0, &x.A) // Field is A. +// m.Save(1, &x.B) // Field is B. +// } +// +// func (x *X) StateLoad(m Source) { +// m.Load(0, &x.A) // Field is A. +// m.Load(1, &x.B) // Field is B. +// } func (s Sink) Save(slot int, objPtr interface{}) { s.internal.save(slot, reflect.ValueOf(objPtr).Elem()) } @@ -166,15 +166,15 @@ func (s Sink) Save(slot int, objPtr interface{}) { // // For example, if we want to cast external package type P.Foo to int64: // -// func (x *X) StateSave(m Sink) { -// m.SaveValue(0, "A", int64(x.A)) -// } +// func (x *X) StateSave(m Sink) { +// m.SaveValue(0, "A", int64(x.A)) +// } // -// func (x *X) StateLoad(m Source) { -// m.LoadValue(0, new(int64), func(x interface{}) { -// x.A = P.Foo(x.(int64)) -// }) -// } +// func (x *X) StateLoad(m Source) { +// m.LoadValue(0, new(int64), func(x interface{}) { +// x.A = P.Foo(x.(int64)) +// }) +// } func (s Sink) SaveValue(slot int, obj interface{}) { s.internal.save(slot, reflect.ValueOf(obj)) } diff --git a/pkg/sync/atomicptrmap/generic_atomicptrmap_unsafe.go b/pkg/sync/atomicptrmap/generic_atomicptrmap_unsafe.go index 3e98cb309..1b7212c86 100644 --- a/pkg/sync/atomicptrmap/generic_atomicptrmap_unsafe.go +++ b/pkg/sync/atomicptrmap/generic_atomicptrmap_unsafe.go @@ -84,13 +84,13 @@ type AtomicPtrMap struct { // AtomicPtrMap is implemented as a hash table with the following // properties: // - // * Collisions are resolved with quadratic probing. Of the two major - // alternatives, Robin Hood linear probing makes it difficult for writers - // to execute in parallel, and bucketing is less effective in Go due to - // lack of SIMD. + // * Collisions are resolved with quadratic probing. Of the two major + // alternatives, Robin Hood linear probing makes it difficult for writers + // to execute in parallel, and bucketing is less effective in Go due to + // lack of SIMD. // - // * The table is optionally divided into shards indexed by hash to further - // reduce unnecessary synchronization. + // * The table is optionally divided into shards indexed by hash to further + // reduce unnecessary synchronization. shards [1 << ShardOrder]apmShard } @@ -150,18 +150,18 @@ const ( type apmSlot struct { // slot states are indicated by val: // - // * Empty: val == nil; key is meaningless. May transition to full or - // evacuated with dirtyMu locked. + // * Empty: val == nil; key is meaningless. May transition to full or + // evacuated with dirtyMu locked. // - // * Full: val != nil, tombstone(), or evacuated(); key is immutable. val - // is the Value mapped to key. May transition to deleted or evacuated. + // * Full: val != nil, tombstone(), or evacuated(); key is immutable. val + // is the Value mapped to key. May transition to deleted or evacuated. // - // * Deleted: val == tombstone(); key is still immutable. key is mapped to - // no Value. May transition to full or evacuated. + // * Deleted: val == tombstone(); key is still immutable. key is mapped to + // no Value. May transition to full or evacuated. // - // * Evacuated: val == evacuated(); key is immutable. Set by rehashing on - // slots that have already been moved, requiring readers to wait for - // rehashing to complete and use the new table. Terminal state. + // * Evacuated: val == evacuated(); key is immutable. Set by rehashing on + // slots that have already been moved, requiring readers to wait for + // rehashing to complete and use the new table. Terminal state. // // Note that once val is non-nil, it cannot become nil again. That is, the // transition from empty to non-empty is irreversible for a given slot; @@ -339,6 +339,7 @@ retry: } // rehash is marked nosplit to avoid preemption during table copying. +// //go:nosplit func (shard *apmShard) rehash(oldSlots unsafe.Pointer) { shard.rehashMu.Lock() @@ -351,14 +352,14 @@ func (shard *apmShard) rehash(oldSlots unsafe.Pointer) { // Determine the size of the new table. Constraints: // - // * The size of the table must be a power of two to ensure that every slot - // is visitable by every probe sequence under quadratic probing with - // triangular numbers. + // * The size of the table must be a power of two to ensure that every slot + // is visitable by every probe sequence under quadratic probing with + // triangular numbers. // - // * The size of the table cannot decrease because even if shard.count is - // currently smaller than shard.dirty, concurrent stores that reuse - // existing slots can drive shard.count back up to a maximum of - // shard.dirty. + // * The size of the table cannot decrease because even if shard.count is + // currently smaller than shard.dirty, concurrent stores that reuse + // existing slots can drive shard.count back up to a maximum of + // shard.dirty. newSize := uintptr(8) // arbitrary initial size if oldSlots != nil { oldSize := shard.mask + 1 @@ -463,11 +464,11 @@ func (shard *apmShard) doRange(f func(key Key, val *Value) bool) bool { // RangeRepeatable is like Range, but: // -// * RangeRepeatable may visit the same Key multiple times in the presence of -// concurrent mutators, possibly passing different Values to f in different -// calls. +// - RangeRepeatable may visit the same Key multiple times in the presence of +// concurrent mutators, possibly passing different Values to f in different +// calls. // -// * It is safe for f to call other methods on m. +// - It is safe for f to call other methods on m. func (m *AtomicPtrMap) RangeRepeatable(f func(key Key, val *Value) bool) { for si := 0; si < len(m.shards); si++ { shard := &m.shards[si] diff --git a/pkg/sync/gate_unsafe.go b/pkg/sync/gate_unsafe.go index ae32287ef..1f7a03309 100644 --- a/pkg/sync/gate_unsafe.go +++ b/pkg/sync/gate_unsafe.go @@ -30,12 +30,13 @@ import ( // // Gate is similar to WaitGroup: // -// - Gate.Enter() is analogous to WaitGroup.Add(1), but may be called even if -// the Gate counter is 0 and fails if Gate.Close() has been called. +// - Gate.Enter() is analogous to WaitGroup.Add(1), but may be called even if +// the Gate counter is 0 and fails if Gate.Close() has been called. // -// - Gate.Leave() is equivalent to WaitGroup.Done(). +// - Gate.Leave() is equivalent to WaitGroup.Done(). +// +// - Gate.Close() is analogous to WaitGroup.Wait(), but also causes future // -// - Gate.Close() is analogous to WaitGroup.Wait(), but also causes future // calls to Gate.Enter() to fail and may only be called once, from a single // goroutine. // @@ -64,7 +65,6 @@ import ( // // // Clean up the object. // [...] -// type Gate struct { userCount int32 closingG uintptr @@ -87,6 +87,7 @@ func (g *Gate) Enter() bool { // leaveAfterFailedEnter is identical to Leave, but is marked noinline to // prevent it from being inlined into Enter, since as of this writing inlining // Leave into Enter prevents Enter from being inlined into its callers. +// //go:noinline func (g *Gate) leaveAfterFailedEnter() { if atomic.AddInt32(&g.userCount, -1) == math.MinInt32 { diff --git a/pkg/sync/locking/lockdep_norace.go b/pkg/sync/locking/lockdep_norace.go index be6082e46..5a3b7e9ad 100644 --- a/pkg/sync/locking/lockdep_norace.go +++ b/pkg/sync/locking/lockdep_norace.go @@ -32,9 +32,11 @@ func NewMutexClass(t reflect.Type) *MutexClass { } // AddGLock is no-op without the lockdep tag. +// //go:inline func AddGLock(class *MutexClass, subclass uint32) {} // DelGLock is no-op without the lockdep tag. +// //go:inline func DelGLock(class *MutexClass, subclass uint32) {} diff --git a/pkg/sync/locking/locking.go b/pkg/sync/locking/locking.go index 45647d170..1b99bc313 100644 --- a/pkg/sync/locking/locking.go +++ b/pkg/sync/locking/locking.go @@ -15,10 +15,10 @@ // Package locking implements lock primitives with the correctness validator. // // All mutexes are divided on classes and the validator check following conditions: -// * Mutexes of the same class are not taken more than once except cases when -// that is expected. -// * Mutexes are never locked in a reverse order. Lock dependencies are tracked -// on the class level. +// - Mutexes of the same class are not taken more than once except cases when +// that is expected. +// - Mutexes are never locked in a reverse order. Lock dependencies are tracked +// on the class level. // // The validator is implemented in a very straightforward way. For each mutex // class, we maintain the ancestors list of all classes that have ever been diff --git a/pkg/sync/mutex_unsafe.go b/pkg/sync/mutex_unsafe.go index c4111cc68..079b39b79 100644 --- a/pkg/sync/mutex_unsafe.go +++ b/pkg/sync/mutex_unsafe.go @@ -83,8 +83,9 @@ func (m *Mutex) Lock() { // Unlock unlocks m. // // Preconditions: -// * m is locked. -// * m was locked by this goroutine. +// - m is locked. +// - m was locked by this goroutine. +// // +checklocksignore func (m *Mutex) Unlock() { noteUnlock(unsafe.Pointer(m)) diff --git a/pkg/sync/rwmutex_unsafe.go b/pkg/sync/rwmutex_unsafe.go index 7829b06db..24400bb71 100644 --- a/pkg/sync/rwmutex_unsafe.go +++ b/pkg/sync/rwmutex_unsafe.go @@ -6,10 +6,10 @@ // This is mostly copied from the standard library's sync/rwmutex.go. // // Happens-before relationships indicated to the race detector: -// - Unlock -> Lock (via writerSem) -// - Unlock -> RLock (via readerSem) -// - RUnlock -> Lock (via writerSem) -// - DowngradeLock -> RLock (via readerSem) +// - Unlock -> Lock (via writerSem) +// - Unlock -> RLock (via readerSem) +// - RUnlock -> Lock (via writerSem) +// - DowngradeLock -> RLock (via readerSem) package sync @@ -84,7 +84,8 @@ func (rw *CrossGoroutineRWMutex) RLock() { // RUnlock undoes a single RLock call. // // Preconditions: -// * rw is locked for reading. +// - rw is locked for reading. +// // +checklocksignore func (rw *CrossGoroutineRWMutex) RUnlock() { if RaceEnabled { @@ -159,7 +160,8 @@ func (rw *CrossGoroutineRWMutex) Lock() { // Unlock unlocks rw for writing. // // Preconditions: -// * rw is locked for writing. +// - rw is locked for writing. +// // +checklocksignore func (rw *CrossGoroutineRWMutex) Unlock() { if RaceEnabled { @@ -186,7 +188,8 @@ func (rw *CrossGoroutineRWMutex) Unlock() { // DowngradeLock atomically unlocks rw for writing and locks it for reading. // // Preconditions: -// * rw is locked for writing. +// - rw is locked for writing. +// // +checklocksignore func (rw *CrossGoroutineRWMutex) DowngradeLock() { if RaceEnabled { @@ -257,8 +260,9 @@ func (rw *RWMutex) RLock() { // RUnlock undoes a single RLock call. // // Preconditions: -// * rw is locked for reading. -// * rw was locked by this goroutine. +// - rw is locked for reading. +// - rw was locked by this goroutine. +// // +checklocksignore func (rw *RWMutex) RUnlock() { rw.m.RUnlock() @@ -289,8 +293,9 @@ func (rw *RWMutex) Lock() { // Unlock unlocks rw for writing. // // Preconditions: -// * rw is locked for writing. -// * rw was locked by this goroutine. +// - rw is locked for writing. +// - rw was locked by this goroutine. +// // +checklocksignore func (rw *RWMutex) Unlock() { rw.m.Unlock() @@ -300,7 +305,8 @@ func (rw *RWMutex) Unlock() { // DowngradeLock atomically unlocks rw for writing and locks it for reading. // // Preconditions: -// * rw is locked for writing. +// - rw is locked for writing. +// // +checklocksignore func (rw *RWMutex) DowngradeLock() { // No note change for DowngradeLock. diff --git a/pkg/sync/seqcount.go b/pkg/sync/seqcount.go index 9bf4a1853..9adc95322 100644 --- a/pkg/sync/seqcount.go +++ b/pkg/sync/seqcount.go @@ -15,19 +15,19 @@ import ( // // Compared to sync/atomic.Value: // -// - Mutation of SeqCount-protected data does not require memory allocation, -// whereas atomic.Value generally does. This is a significant advantage when -// writes are common. +// - Mutation of SeqCount-protected data does not require memory allocation, +// whereas atomic.Value generally does. This is a significant advantage when +// writes are common. // -// - Atomic reads of SeqCount-protected data require copying. This is a -// disadvantage when atomic reads are common. +// - Atomic reads of SeqCount-protected data require copying. This is a +// disadvantage when atomic reads are common. // -// - SeqCount may be more flexible: correct use of SeqCount.ReadOk allows other -// operations to be made atomic with reads of SeqCount-protected data. +// - SeqCount may be more flexible: correct use of SeqCount.ReadOk allows other +// operations to be made atomic with reads of SeqCount-protected data. // -// - SeqCount is more cumbersome to use; atomic reads of SeqCount-protected -// data require instantiating function templates using go_generics (see -// seqatomic.go). +// - SeqCount is more cumbersome to use; atomic reads of SeqCount-protected +// data require instantiating function templates using go_generics (see +// seqatomic.go). type SeqCount struct { // epoch is incremented by BeginWrite and EndWrite, such that epoch is odd // if a writer critical section is active, and a read from data protected @@ -41,16 +41,16 @@ type SeqCountEpoch uint32 // We assume that: // -// - All functions in sync/atomic that perform a memory read are at least a -// read fence: memory reads before calls to such functions cannot be reordered -// after the call, and memory reads after calls to such functions cannot be -// reordered before the call, even if those reads do not use sync/atomic. +// - All functions in sync/atomic that perform a memory read are at least a +// read fence: memory reads before calls to such functions cannot be reordered +// after the call, and memory reads after calls to such functions cannot be +// reordered before the call, even if those reads do not use sync/atomic. // -// - All functions in sync/atomic that perform a memory write are at least a -// write fence: memory writes before calls to such functions cannot be -// reordered after the call, and memory writes after calls to such functions -// cannot be reordered before the call, even if those writes do not use -// sync/atomic. +// - All functions in sync/atomic that perform a memory write are at least a +// write fence: memory writes before calls to such functions cannot be +// reordered after the call, and memory writes after calls to such functions +// cannot be reordered before the call, even if those writes do not use +// sync/atomic. // // As of this writing, the Go memory model completely fails to describe // sync/atomic, but these properties are implied by @@ -62,13 +62,13 @@ type SeqCountEpoch uint32 // detected by ReadOk at the end of the reader critical section. Thus, the // low-level structure of readers is generally: // -// for { -// epoch := seq.BeginRead() -// // do something idempotent with seq-protected data -// if seq.ReadOk(epoch) { -// break -// } -// } +// for { +// epoch := seq.BeginRead() +// // do something idempotent with seq-protected data +// if seq.ReadOk(epoch) { +// break +// } +// } // // However, since reader critical sections may race with writer critical // sections, the Go race detector will (accurately) flag data races in readers diff --git a/pkg/syncevent/broadcaster.go b/pkg/syncevent/broadcaster.go index dabf08895..bb1144de2 100644 --- a/pkg/syncevent/broadcaster.go +++ b/pkg/syncevent/broadcaster.go @@ -112,8 +112,8 @@ func (b *Broadcaster) SubscribeEvents(r *Receiver, filter Set) SubscriptionID { } // Preconditions: -// * table must not be full. -// * len(table) is a power of 2. +// - table must not be full. +// - len(table) is a power of 2. func broadcasterTableInsert(table []broadcasterSlot, id SubscriptionID, r *Receiver, filter Set) { entry := broadcasterSlot{ receiver: r, diff --git a/pkg/syncevent/source.go b/pkg/syncevent/source.go index d3d0f34c5..b924aeee5 100644 --- a/pkg/syncevent/source.go +++ b/pkg/syncevent/source.go @@ -20,10 +20,10 @@ type Source interface { // given subset of events. // // Preconditions: - // * r != nil. - // * The ReceiverCallback for r must not take locks that are ordered - // prior to the Source; for example, it cannot call any Source - // methods. + // * r != nil. + // * The ReceiverCallback for r must not take locks that are ordered + // prior to the Source; for example, it cannot call any Source + // methods. SubscribeEvents(r *Receiver, filter Set) SubscriptionID // UnsubscribeEvents causes the Source to stop notifying the Receiver diff --git a/pkg/syncevent/syncevent_example_test.go b/pkg/syncevent/syncevent_example_test.go index 2f82b57ce..4cb08d784 100644 --- a/pkg/syncevent/syncevent_example_test.go +++ b/pkg/syncevent/syncevent_example_test.go @@ -98,12 +98,12 @@ func Example_ioReadinessInterrputible() { // Note that, in a concurrent context, the I/O object might become // ready and then not ready again. To handle this: // - // - evReady must be acknowledged before calling doIO() again (rather - // than after), so that if the I/O object becomes ready *again* after - // the call to doIO(), the readiness event is not lost. + // - evReady must be acknowledged before calling doIO() again (rather + // than after), so that if the I/O object becomes ready *again* after + // the call to doIO(), the readiness event is not lost. // - // - We must loop instead of just calling doIO() once after receiving - // evReady. + // - We must loop instead of just calling doIO() once after receiving + // evReady. w.Ack(evReady) } } diff --git a/pkg/syncevent/waiter_unsafe.go b/pkg/syncevent/waiter_unsafe.go index 04bae3100..0b6059248 100644 --- a/pkg/syncevent/waiter_unsafe.go +++ b/pkg/syncevent/waiter_unsafe.go @@ -29,15 +29,15 @@ type Waiter struct { // g is one of: // - // - 0: No goroutine is blocking in Wait. + // - 0: No goroutine is blocking in Wait. // - // - preparingG: A goroutine is in Wait preparing to sleep, but hasn't yet - // completed waiterUnlock(). Thus the wait can only be interrupted by - // replacing the value of g with 0 (the G may not be in state Gwaiting yet, - // so we can't call goready.) + // - preparingG: A goroutine is in Wait preparing to sleep, but hasn't yet + // completed waiterUnlock(). Thus the wait can only be interrupted by + // replacing the value of g with 0 (the G may not be in state Gwaiting yet, + // so we can't call goready.) // - // - Otherwise: g is a pointer to the runtime.g in state Gwaiting for the - // goroutine blocked in Wait, which can only be woken by calling goready. + // - Otherwise: g is a pointer to the runtime.g in state Gwaiting for the + // goroutine blocked in Wait, which can only be woken by calling goready. g uintptr `state:"zerovalue"` } diff --git a/pkg/tcpip/hash/jenkins/jenkins.go b/pkg/tcpip/hash/jenkins/jenkins.go index 33ff22a7b..89b20f021 100644 --- a/pkg/tcpip/hash/jenkins/jenkins.go +++ b/pkg/tcpip/hash/jenkins/jenkins.go @@ -16,7 +16,6 @@ // functions created by by Bob Jenkins. // // See https://en.wikipedia.org/wiki/Jenkins_hash_function#cite_note-dobbsx-1 -// package jenkins import ( diff --git a/pkg/tcpip/hash/jenkins/jenkins_test.go b/pkg/tcpip/hash/jenkins/jenkins_test.go index 4c78b5808..a219150e7 100644 --- a/pkg/tcpip/hash/jenkins/jenkins_test.go +++ b/pkg/tcpip/hash/jenkins/jenkins_test.go @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, diff --git a/pkg/tcpip/header/igmp.go b/pkg/tcpip/header/igmp.go index 5c5be1b9d..af5b5a3d6 100644 --- a/pkg/tcpip/header/igmp.go +++ b/pkg/tcpip/header/igmp.go @@ -76,10 +76,10 @@ type IGMPType byte const ( // IGMPMembershipQuery indicates that the message type is Membership Query. // "There are two sub-types of Membership Query messages: - // - General Query, used to learn which groups have members on an - // attached network. - // - Group-Specific Query, used to learn if a particular group - // has any members on an attached network. + // - General Query, used to learn which groups have members on an + // attached network. + // - Group-Specific Query, used to learn if a particular group + // has any members on an attached network. // These two messages are differentiated by the Group Address, as // described in section 1.4 ." IGMPMembershipQuery IGMPType = 0x11 diff --git a/pkg/tcpip/header/ipv4.go b/pkg/tcpip/header/ipv4.go index 87f6e5b59..6c6ecd1ff 100644 --- a/pkg/tcpip/header/ipv4.go +++ b/pkg/tcpip/header/ipv4.go @@ -24,21 +24,22 @@ import ( // RFC 971 defines the fields of the IPv4 header on page 11 using the following // diagram: ("Figure 4") -// 0 1 2 3 -// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// |Version| IHL |Type of Service| Total Length | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | Identification |Flags| Fragment Offset | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | Time to Live | Protocol | Header Checksum | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | Source Address | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | Destination Address | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | Options | Padding | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |Version| IHL |Type of Service| Total Length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Identification |Flags| Fragment Offset | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Time to Live | Protocol | Header Checksum | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Source Address | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Destination Address | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Options | Padding | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ const ( versIHL = 0 tos = 1 @@ -230,19 +231,19 @@ func IPVersion(b []byte) int { // RFC 791 page 11 shows the header length (IHL) is in the lower 4 bits // of the first byte, and is counted in multiples of 4 bytes. // -// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// |Version| IHL |Type of Service| Total Length | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// (...) -// Version: 4 bits -// The Version field indicates the format of the internet header. This -// document describes version 4. +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |Version| IHL |Type of Service| Total Length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// (...) +// Version: 4 bits +// The Version field indicates the format of the internet header. This +// document describes version 4. // -// IHL: 4 bits -// Internet Header Length is the length of the internet header in 32 -// bit words, and thus points to the beginning of the data. Note that -// the minimum value for a correct header is 5. +// IHL: 4 bits +// Internet Header Length is the length of the internet header in 32 +// bit words, and thus points to the beginning of the data. Note that +// the minimum value for a correct header is 5. const ( ipVersionShift = 4 ipIHLMask = 0x0f @@ -328,8 +329,9 @@ func (b IPv4) SetDestinationAddressWithChecksumUpdate(new tcpip.Address) { // padIPv4OptionsLength returns the total length for IPv4 options of length l // after applying padding according to RFC 791: -// The internet header padding is used to ensure that the internet -// header ends on a 32 bit boundary. +// +// The internet header padding is used to ensure that the internet +// header ends on a 32 bit boundary. func padIPv4OptionsLength(length uint8) uint8 { return (length + IPv4IHLStride - 1) & ^uint8(IPv4IHLStride-1) } @@ -668,10 +670,10 @@ func (i *IPv4OptionIterator) Finalize() IPv4Options { // Next returns the next IP option in the buffer/list of IP options. // It returns -// - A slice of bytes holding the next option or nil if there is error. -// - A boolean which is true if parsing of all the options is complete. -// Undefined in the case of error. -// - An error indication which is non-nil if an error condition was found. +// - A slice of bytes holding the next option or nil if there is error. +// - A boolean which is true if parsing of all the options is complete. +// Undefined in the case of error. +// - An error indication which is non-nil if an error condition was found. func (i *IPv4OptionIterator) Next() (IPv4Option, bool, *IPv4OptParameterProblem) { // The opts slice gets shorter as we process the options. When we have no // bytes left we are done. @@ -805,7 +807,6 @@ func (i *IPv4OptionIterator) Next() (IPv4Option, bool, *IPv4OptParameterProblem) // option Flags field. type IPv4OptTSFlags uint8 -// // Timestamp option specific related constants. const ( // IPv4OptionTimestampHdrLength is the length of the timestamp option header. @@ -918,23 +919,24 @@ func (ts *IPv4OptionTimestamp) UpdateTimestamp(addr tcpip.Address, clock tcpip.C // RecordRoute option specific related constants. // // from RFC 791 page 20: -// Record Route // -// +--------+--------+--------+---------//--------+ -// |00000111| length | pointer| route data | -// +--------+--------+--------+---------//--------+ -// Type=7 +// Record Route // -// The record route option provides a means to record the route of -// an internet datagram. +// +--------+--------+--------+---------//--------+ +// |00000111| length | pointer| route data | +// +--------+--------+--------+---------//--------+ +// Type=7 // -// The option begins with the option type code. The second octet -// is the option length which includes the option type code and the -// length octet, the pointer octet, and length-3 octets of route -// data. The third octet is the pointer into the route data -// indicating the octet which begins the next area to store a route -// address. The pointer is relative to this option, and the -// smallest legal value for the pointer is 4. +// The record route option provides a means to record the route of +// an internet datagram. +// +// The option begins with the option type code. The second octet +// is the option length which includes the option type code and the +// length octet, the pointer octet, and length-3 octets of route +// data. The third octet is the pointer into the route data +// indicating the octet which begins the next area to store a route +// address. The pointer is relative to this option, and the +// smallest legal value for the pointer is 4. const ( // IPv4OptionRecordRouteHdrLength is the length of the Record Route option // header. @@ -978,20 +980,20 @@ func (rr *IPv4OptionRecordRoute) Contents() []byte { return *rr } // // from RFC 2113 section 2.1: // -// +--------+--------+--------+--------+ -// |10010100|00000100| 2 octet value | -// +--------+--------+--------+--------+ +// +--------+--------+--------+--------+ +// |10010100|00000100| 2 octet value | +// +--------+--------+--------+--------+ // -// Type: -// Copied flag: 1 (all fragments must carry the option) -// Option class: 0 (control) -// Option number: 20 (decimal) +// Type: +// Copied flag: 1 (all fragments must carry the option) +// Option class: 0 (control) +// Option number: 20 (decimal) // -// Length: 4 +// Length: 4 // -// Value: A two octet code with the following values: -// 0 - Router shall examine packet -// 1-65535 - Reserved +// Value: A two octet code with the following values: +// 0 - Router shall examine packet +// 1-65535 - Reserved const ( // IPv4OptionRouterAlertLength is the length of a Router Alert option. IPv4OptionRouterAlertLength = 4 diff --git a/pkg/tcpip/header/ipv6.go b/pkg/tcpip/header/ipv6.go index c3a0407ac..d7ae19184 100644 --- a/pkg/tcpip/header/ipv6.go +++ b/pkg/tcpip/header/ipv6.go @@ -537,26 +537,26 @@ type IPv6MulticastScope uint8 // The various values for IPv6 multicast scopes, as per RFC 7346 section 2: // -// +------+--------------------------+-------------------------+ -// | scop | NAME | REFERENCE | -// +------+--------------------------+-------------------------+ -// | 0 | Reserved | [RFC4291], RFC 7346 | -// | 1 | Interface-Local scope | [RFC4291], RFC 7346 | -// | 2 | Link-Local scope | [RFC4291], RFC 7346 | -// | 3 | Realm-Local scope | [RFC4291], RFC 7346 | -// | 4 | Admin-Local scope | [RFC4291], RFC 7346 | -// | 5 | Site-Local scope | [RFC4291], RFC 7346 | -// | 6 | Unassigned | | -// | 7 | Unassigned | | -// | 8 | Organization-Local scope | [RFC4291], RFC 7346 | -// | 9 | Unassigned | | -// | A | Unassigned | | -// | B | Unassigned | | -// | C | Unassigned | | -// | D | Unassigned | | -// | E | Global scope | [RFC4291], RFC 7346 | -// | F | Reserved | [RFC4291], RFC 7346 | -// +------+--------------------------+-------------------------+ +// +------+--------------------------+-------------------------+ +// | scop | NAME | REFERENCE | +// +------+--------------------------+-------------------------+ +// | 0 | Reserved | [RFC4291], RFC 7346 | +// | 1 | Interface-Local scope | [RFC4291], RFC 7346 | +// | 2 | Link-Local scope | [RFC4291], RFC 7346 | +// | 3 | Realm-Local scope | [RFC4291], RFC 7346 | +// | 4 | Admin-Local scope | [RFC4291], RFC 7346 | +// | 5 | Site-Local scope | [RFC4291], RFC 7346 | +// | 6 | Unassigned | | +// | 7 | Unassigned | | +// | 8 | Organization-Local scope | [RFC4291], RFC 7346 | +// | 9 | Unassigned | | +// | A | Unassigned | | +// | B | Unassigned | | +// | C | Unassigned | | +// | D | Unassigned | | +// | E | Global scope | [RFC4291], RFC 7346 | +// | F | Reserved | [RFC4291], RFC 7346 | +// +------+--------------------------+-------------------------+ const ( IPv6Reserved0MulticastScope = IPv6MulticastScope(0x0) IPv6InterfaceLocalMulticastScope = IPv6MulticastScope(0x1) diff --git a/pkg/tcpip/header/mld.go b/pkg/tcpip/header/mld.go index ffe03c76a..131fca24b 100644 --- a/pkg/tcpip/header/mld.go +++ b/pkg/tcpip/header/mld.go @@ -46,21 +46,21 @@ const ( // As per RFC 2710 section 3, MLD messages have the following format (MLD only // holds the bytes after the first four bytes in the diagram below): // -// 0 1 2 3 -// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | Type | Code | Checksum | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | Maximum Response Delay | Reserved | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | | -// + + -// | | -// + Multicast Address + -// | | -// + + -// | | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Type | Code | Checksum | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Maximum Response Delay | Reserved | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | | +// + + +// | | +// + Multicast Address + +// | | +// + + +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ type MLD []byte // MaximumResponseDelay returns the Maximum Response Delay. diff --git a/pkg/tcpip/header/ndp_options.go b/pkg/tcpip/header/ndp_options.go index a647ea968..06954e0e3 100644 --- a/pkg/tcpip/header/ndp_options.go +++ b/pkg/tcpip/header/ndp_options.go @@ -666,7 +666,8 @@ func (o NDPPrefixInformation) Subnet() tcpip.Subnet { // To make sure that the option meets its minimum length and does not end in the // middle of a DNS server's IPv6 address, the length of a valid // NDPRecursiveDNSServer must meet the following constraint: -// (Length - ndpRecursiveDNSServerAddressesOffset) % IPv6AddressSize == 0 +// +// (Length - ndpRecursiveDNSServerAddressesOffset) % IPv6AddressSize == 0 type NDPRecursiveDNSServer []byte // Type returns the type of an NDP Recursive DNS Server option. @@ -944,32 +945,32 @@ func isDigit(b byte) bool { // As per RFC 4191 section 2.3, // -// 2.3. Route Information Option +// 2.3. Route Information Option // -// 0 1 2 3 -// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | Type | Length | Prefix Length |Resvd|Prf|Resvd| -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | Route Lifetime | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | Prefix (Variable Length) | -// . . -// . . -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Type | Length | Prefix Length |Resvd|Prf|Resvd| +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Route Lifetime | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Prefix (Variable Length) | +// . . +// . . +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // -// Fields: +// Fields: // -// Type 24 +// Type 24 // // -// Length 8-bit unsigned integer. The length of the option -// (including the Type and Length fields) in units of 8 -// octets. The Length field is 1, 2, or 3 depending on the -// Prefix Length. If Prefix Length is greater than 64, then -// Length must be 3. If Prefix Length is greater than 0, -// then Length must be 2 or 3. If Prefix Length is zero, -// then Length must be 1, 2, or 3. +// Length 8-bit unsigned integer. The length of the option +// (including the Type and Length fields) in units of 8 +// octets. The Length field is 1, 2, or 3 depending on the +// Prefix Length. If Prefix Length is greater than 64, then +// Length must be 3. If Prefix Length is greater than 0, +// then Length must be 2 or 3. If Prefix Length is zero, +// then Length must be 1, 2, or 3. const ( ndpRouteInformationType = ndpOptionIdentifier(24) ndpRouteInformationMaxLength = 22 diff --git a/pkg/tcpip/header/ndp_router_advert.go b/pkg/tcpip/header/ndp_router_advert.go index 7d6efa083..ef22b66f3 100644 --- a/pkg/tcpip/header/ndp_router_advert.go +++ b/pkg/tcpip/header/ndp_router_advert.go @@ -27,22 +27,22 @@ var _ fmt.Stringer = NDPRoutePreference(0) // // As per RFC 4191 section 2.1, // -// Default router preferences and preferences for more-specific routes -// are encoded the same way. +// Default router preferences and preferences for more-specific routes +// are encoded the same way. // -// Preference values are encoded as a two-bit signed integer, as -// follows: +// Preference values are encoded as a two-bit signed integer, as +// follows: // -// 01 High -// 00 Medium (default) -// 11 Low -// 10 Reserved - MUST NOT be sent +// 01 High +// 00 Medium (default) +// 11 Low +// 10 Reserved - MUST NOT be sent // -// Note that implementations can treat the value as a two-bit signed -// integer. +// Note that implementations can treat the value as a two-bit signed +// integer. // -// Having just three values reinforces that they are not metrics and -// more values do not appear to be necessary for reasonable scenarios. +// Having just three values reinforces that they are not metrics and +// more values do not appear to be necessary for reasonable scenarios. type NDPRoutePreference uint8 const ( @@ -91,19 +91,19 @@ type NDPRouterAdvert []byte // As per RFC 4191 section 2.2, // -// 0 1 2 3 -// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | Type | Code | Checksum | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | Cur Hop Limit |M|O|H|Prf|Resvd| Router Lifetime | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | Reachable Time | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | Retrans Timer | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | Options ... -// +-+-+-+-+-+-+-+-+-+-+-+- +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Type | Code | Checksum | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Cur Hop Limit |M|O|H|Prf|Resvd| Router Lifetime | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Reachable Time | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Retrans Timer | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Options ... +// +-+-+-+-+-+-+-+-+-+-+-+- const ( // NDPRAMinimumSize is the minimum size of a valid NDP Router // Advertisement message (body of an ICMPv6 packet). diff --git a/pkg/tcpip/header/parse/parse.go b/pkg/tcpip/header/parse/parse.go index 80a9ad6be..c4ac9372f 100644 --- a/pkg/tcpip/header/parse/parse.go +++ b/pkg/tcpip/header/parse/parse.go @@ -81,9 +81,9 @@ func IPv6(pkt *stack.PacketBuffer) (proto tcpip.TransportProtocolNumber, fragID // Create a VV to parse the packet. We don't plan to modify anything here. // dataVV consists of: - // - Any IPv6 header bytes after the first 40 (i.e. extensions). - // - The transport header, if present. - // - Any other payload data. + // - Any IPv6 header bytes after the first 40 (i.e. extensions). + // - The transport header, if present. + // - Any other payload data. views := [8]buffer.View{} dataVV := buffer.NewVectorisedView(0, views[:0]) dataVV.AppendViews(pkt.Data().Views()) diff --git a/pkg/tcpip/link/fdbased/endpoint.go b/pkg/tcpip/link/fdbased/endpoint.go index e58b1e9ae..6d4bad4b2 100644 --- a/pkg/tcpip/link/fdbased/endpoint.go +++ b/pkg/tcpip/link/fdbased/endpoint.go @@ -665,9 +665,9 @@ func (e *endpoint) sendBatch(batchFDInfo fdInfo, pkts []*stack.PacketBuffer) (in // // Being a batch API, each packet in pkts should have the following // fields populated: -// - pkt.EgressRoute -// - pkt.GSOOptions -// - pkt.NetworkProtocolNumber +// - pkt.EgressRoute +// - pkt.GSOOptions +// - pkt.NetworkProtocolNumber func (e *endpoint) WritePackets(pkts stack.PacketBufferList) (int, tcpip.Error) { // Preallocate to avoid repeated reallocation as we append to batch. // batchSz is 47 because when SWGSO is in use then a single 65KB TCP diff --git a/pkg/tcpip/link/fdbased/mmap.go b/pkg/tcpip/link/fdbased/mmap.go index 2a8073a29..07391dae7 100644 --- a/pkg/tcpip/link/fdbased/mmap.go +++ b/pkg/tcpip/link/fdbased/mmap.go @@ -43,11 +43,12 @@ const ( // Memory allocated for the ring buffer: tpBlockSize * tpBlockNR = 2 MiB // // NOTE: -// Frames need to be aligned at 16 byte boundaries. -// BlockSize needs to be page aligned. // -// For details see PACKET_MMAP setting constraints in -// https://www.kernel.org/doc/Documentation/networking/packet_mmap.txt +// Frames need to be aligned at 16 byte boundaries. +// BlockSize needs to be page aligned. +// +// For details see PACKET_MMAP setting constraints in +// https://www.kernel.org/doc/Documentation/networking/packet_mmap.txt const ( tpFrameSize = 65536 + 128 tpBlockSize = tpFrameSize * 32 diff --git a/pkg/tcpip/link/qdisc/fifo/fifo.go b/pkg/tcpip/link/qdisc/fifo/fifo.go index 2cd315037..33a7a3455 100644 --- a/pkg/tcpip/link/qdisc/fifo/fifo.go +++ b/pkg/tcpip/link/qdisc/fifo/fifo.go @@ -128,9 +128,9 @@ func (qd *queueDispatcher) dispatchLoop() { // WritePacket implements stack.QueueingDiscipline.WritePacket. // // The packet must have the following fields populated: -// - pkt.EgressRoute -// - pkt.GSOOptions -// - pkt.NetworkProtocolNumber +// - pkt.EgressRoute +// - pkt.GSOOptions +// - pkt.NetworkProtocolNumber func (d *discipline) WritePacket(pkt *stack.PacketBuffer) tcpip.Error { if d.closed.Load() == qDiscClosed { return &tcpip.ErrClosedForSend{} diff --git a/pkg/tcpip/network/internal/ip/generic_multicast_protocol.go b/pkg/tcpip/network/internal/ip/generic_multicast_protocol.go index 671dfbf32..3d196e85a 100644 --- a/pkg/tcpip/network/internal/ip/generic_multicast_protocol.go +++ b/pkg/tcpip/network/internal/ip/generic_multicast_protocol.go @@ -30,19 +30,19 @@ type hostState int // (RFC 2710 section 5). Even though the states are generic across both IGMPv2 // and MLDv1, IGMPv2 terminology will be used. // -// ______________receive query______________ -// | | -// | _____send or receive report_____ | -// | | | | -// V | V | -// +-------+ +-----------+ +------------+ +-------------------+ +--------+ | -// | Non-M | | Pending-M | | Delaying-M | | Queued Delaying-M | | Idle-M | - -// +-------+ +-----------+ +------------+ +-------------------+ +--------+ -// | ^ | ^ | ^ | ^ -// | | | | | | | | -// ---------- ------- ---------- ------------- -// initialize new send inital fail to send send or receive -// group membership report delayed report report +// ______________receive query______________ +// | | +// | _____send or receive report_____ | +// | | | | +// V | V | +// +-------+ +-----------+ +------------+ +-------------------+ +--------+ | +// | Non-M | | Pending-M | | Delaying-M | | Queued Delaying-M | | Idle-M | - +// +-------+ +-----------+ +------------+ +-------------------+ +--------+ +// | ^ | ^ | ^ | ^ +// | | | | | | | | +// ---------- ------- ---------- ------------- +// initialize new send inital fail to send send or receive +// group membership report delayed report report // // Not shown in the diagram above, but any state may transition into the non // member state when a group is left. diff --git a/pkg/tcpip/network/ipv6/ipv6.go b/pkg/tcpip/network/ipv6/ipv6.go index bc02b9e57..834c475f0 100644 --- a/pkg/tcpip/network/ipv6/ipv6.go +++ b/pkg/tcpip/network/ipv6/ipv6.go @@ -72,16 +72,16 @@ const ( // // A more human-readable version: // -// Prefix Precedence Label -// ::1/128 50 0 -// ::/0 40 1 -// ::ffff:0:0/96 35 4 -// 2002::/16 30 2 -// 2001::/32 5 5 -// fc00::/7 3 13 -// ::/96 1 3 -// fec0::/10 1 11 -// 3ffe::/16 1 12 +// Prefix Precedence Label +// ::1/128 50 0 +// ::/0 40 1 +// ::ffff:0:0/96 35 4 +// 2002::/16 30 2 +// 2001::/32 5 5 +// fc00::/7 3 13 +// ::/96 1 3 +// fec0::/10 1 11 +// 3ffe::/16 1 12 // // The table is sorted by prefix length so longest-prefix match can be easily // achieved. @@ -91,27 +91,27 @@ const ( // // As per RFC 4291 section 2.5.5.1 (for ::/96), // -// The "IPv4-Compatible IPv6 address" is now deprecated because the -// current IPv6 transition mechanisms no longer use these addresses. -// New or updated implementations are not required to support this -// address type. +// The "IPv4-Compatible IPv6 address" is now deprecated because the +// current IPv6 transition mechanisms no longer use these addresses. +// New or updated implementations are not required to support this +// address type. // // As per RFC 3879 section 4 (for fec0::/10), // -// This document formally deprecates the IPv6 site-local unicast prefix -// defined in [RFC3513], i.e., 1111111011 binary or FEC0::/10. +// This document formally deprecates the IPv6 site-local unicast prefix +// defined in [RFC3513], i.e., 1111111011 binary or FEC0::/10. // // As per RFC 3701 section 1 (for 3ffe::/16), // -// As clearly stated in [TEST-NEW], the addresses for the 6bone are -// temporary and will be reclaimed in the future. It further states -// that all users of these addresses (within the 3FFE::/16 prefix) will -// be required to renumber at some time in the future. +// As clearly stated in [TEST-NEW], the addresses for the 6bone are +// temporary and will be reclaimed in the future. It further states +// that all users of these addresses (within the 3FFE::/16 prefix) will +// be required to renumber at some time in the future. // // and section 2, // -// Thus after the pTLA allocation cutoff date January 1, 2004, it is -// REQUIRED that no new 6bone 3FFE pTLAs be allocated. +// Thus after the pTLA allocation cutoff date January 1, 2004, it is +// REQUIRED that no new 6bone 3FFE pTLAs be allocated. // // MUST NOT BE MODIFIED. var policyTable = [...]struct { @@ -1148,9 +1148,9 @@ func (e *endpoint) processExtensionHeaders(h header.IPv6, pkt *stack.PacketBuffe // Create a VV to parse the packet. We don't plan to modify anything here. // vv consists of: - // - Any IPv6 header bytes after the first 40 (i.e. extensions). - // - The transport header, if present. - // - Any other payload data. + // - Any IPv6 header bytes after the first 40 (i.e. extensions). + // - The transport header, if present. + // - Any other payload data. vv := pkt.NetworkHeader().View()[header.IPv6MinimumSize:].ToVectorisedView() vv.AppendView(pkt.TransportHeader().View()) vv.AppendViews(pkt.Data().Views()) diff --git a/pkg/tcpip/stack/conntrack.go b/pkg/tcpip/stack/conntrack.go index 5bc0bf92c..dfca5cd2f 100644 --- a/pkg/tcpip/stack/conntrack.go +++ b/pkg/tcpip/stack/conntrack.go @@ -217,11 +217,11 @@ func (cn *conn) update(pkt *PacketBuffer, reply bool) { // // ConnTrack keeps all connections in a slice of buckets, each of which holds a // linked list of tuples. This gives us some desirable properties: -// - Each bucket has its own lock, lessening lock contention. -// - The slice is large enough that lists stay short (<10 elements on average). -// Thus traversal is fast. -// - During linked list traversal we reap expired connections. This amortizes -// the cost of reaping them and makes reapUnused faster. +// - Each bucket has its own lock, lessening lock contention. +// - The slice is large enough that lists stay short (<10 elements on average). +// Thus traversal is fast. +// - During linked list traversal we reap expired connections. This amortizes +// the cost of reaping them and makes reapUnused faster. // // Locks are ordered by their location in the buckets slice. That is, a // goroutine that locks buckets[i] can only lock buckets[j] s.t. i < j. @@ -980,13 +980,13 @@ func (ct *ConnTrack) bucket(id tupleID) int { // reapUnused deletes timed out entries from the conntrack map. The rules for // reaping are: -// - Each call to reapUnused traverses a fraction of the conntrack table. -// Specifically, it traverses len(ct.buckets)/fractionPerReaping. -// - After reaping, reapUnused decides when it should next run based on the -// ratio of expired connections to examined connections. If the ratio is -// greater than maxExpiredPct, it schedules the next run quickly. Otherwise it -// slightly increases the interval between runs. -// - maxFullTraversal caps the time it takes to traverse the entire table. +// - Each call to reapUnused traverses a fraction of the conntrack table. +// Specifically, it traverses len(ct.buckets)/fractionPerReaping. +// - After reaping, reapUnused decides when it should next run based on the +// ratio of expired connections to examined connections. If the ratio is +// greater than maxExpiredPct, it schedules the next run quickly. Otherwise it +// slightly increases the interval between runs. +// - maxFullTraversal caps the time it takes to traverse the entire table. // // reapUnused returns the next bucket that should be checked and the time after // which it should be called again. diff --git a/pkg/tcpip/stack/iptables.go b/pkg/tcpip/stack/iptables.go index 9860acbc1..2f2cfc438 100644 --- a/pkg/tcpip/stack/iptables.go +++ b/pkg/tcpip/stack/iptables.go @@ -279,6 +279,7 @@ type checkTable struct { // - Stack splitting, which can allocate. // - Calls to interfaces, which can allocate. // - Calls to dynamic functions, which can allocate. +// // +checkescape:hard func (it *IPTables) shouldSkipOrPopulateTables(tables []checkTable, pkt *PacketBuffer) bool { switch pkt.NetworkProtocolNumber { @@ -605,8 +606,8 @@ func (it *IPTables) startReaper(interval time.Duration) { } // Preconditions: -// * pkt is a IPv4 packet of at least length header.IPv4MinimumSize. -// * pkt.NetworkHeader is not nil. +// - pkt is a IPv4 packet of at least length header.IPv4MinimumSize. +// - pkt.NetworkHeader is not nil. func (it *IPTables) checkChain(hook Hook, pkt *PacketBuffer, table Table, ruleIdx int, r *Route, addressEP AddressableEndpoint, inNicName, outNicName string) chainVerdict { // Start from ruleIdx and walk the list of rules until a rule gives us // a verdict. @@ -652,8 +653,8 @@ func (it *IPTables) checkChain(hook Hook, pkt *PacketBuffer, table Table, ruleId } // Preconditions: -// * pkt is a IPv4 packet of at least length header.IPv4MinimumSize. -// * pkt.NetworkHeader is not nil. +// - pkt is a IPv4 packet of at least length header.IPv4MinimumSize. +// - pkt.NetworkHeader is not nil. func (it *IPTables) checkRule(hook Hook, pkt *PacketBuffer, table Table, ruleIdx int, r *Route, addressEP AddressableEndpoint, inNicName, outNicName string) (RuleVerdict, int) { rule := table.Rules[ruleIdx] diff --git a/pkg/tcpip/stack/iptables_types.go b/pkg/tcpip/stack/iptables_types.go index 97f9e1f6c..febd573df 100644 --- a/pkg/tcpip/stack/iptables_types.go +++ b/pkg/tcpip/stack/iptables_types.go @@ -25,16 +25,16 @@ import ( // A Hook specifies one of the hooks built into the network stack. // -// Userspace app Userspace app -// ^ | -// | v -// [Input] [Output] -// ^ | -// | v -// | routing -// | | -// | v -// ----->[Prerouting]----->routing----->[Forward]---------[Postrouting]-----> +// Userspace app Userspace app +// ^ | +// | v +// [Input] [Output] +// ^ | +// | v +// | routing +// | | +// | v +// ----->[Prerouting]----->routing----->[Forward]---------[Postrouting]-----> type Hook uint const ( diff --git a/pkg/tcpip/stack/neighbor_entry.go b/pkg/tcpip/stack/neighbor_entry.go index b8ceeebf2..cd8c3e2f4 100644 --- a/pkg/tcpip/stack/neighbor_entry.go +++ b/pkg/tcpip/stack/neighbor_entry.go @@ -236,9 +236,9 @@ func (e *neighborEntry) removeLocked() { // TODO(https://gvisor.dev/issues/5583): test the case where this function is // called during resolution; that can happen in at least these scenarios: // - // - manual address removal during resolution + // - manual address removal during resolution // - // - neighbor cache eviction during resolution + // - neighbor cache eviction during resolution e.notifyCompletionLocked(&tcpip.ErrAborted{}) } diff --git a/pkg/tcpip/stack/nud.go b/pkg/tcpip/stack/nud.go index ca9822bca..a4ef39ac2 100644 --- a/pkg/tcpip/stack/nud.go +++ b/pkg/tcpip/stack/nud.go @@ -384,19 +384,19 @@ func (s *NUDState) ReachableTime() time.Duration { // This SHOULD automatically be invoked during certain situations, as per // RFC 4861 section 6.3.4: // -// If the received Reachable Time value is non-zero, the host SHOULD set its -// BaseReachableTime variable to the received value. If the new value -// differs from the previous value, the host SHOULD re-compute a new random -// ReachableTime value. ReachableTime is computed as a uniformly -// distributed random value between MIN_RANDOM_FACTOR and MAX_RANDOM_FACTOR -// times the BaseReachableTime. Using a random component eliminates the -// possibility that Neighbor Unreachability Detection messages will -// synchronize with each other. +// If the received Reachable Time value is non-zero, the host SHOULD set its +// BaseReachableTime variable to the received value. If the new value +// differs from the previous value, the host SHOULD re-compute a new random +// ReachableTime value. ReachableTime is computed as a uniformly +// distributed random value between MIN_RANDOM_FACTOR and MAX_RANDOM_FACTOR +// times the BaseReachableTime. Using a random component eliminates the +// possibility that Neighbor Unreachability Detection messages will +// synchronize with each other. // -// In most cases, the advertised Reachable Time value will be the same in -// consecutive Router Advertisements, and a host's BaseReachableTime rarely -// changes. In such cases, an implementation SHOULD ensure that a new -// random value gets re-computed at least once every few hours. +// In most cases, the advertised Reachable Time value will be the same in +// consecutive Router Advertisements, and a host's BaseReachableTime rarely +// changes. In such cases, an implementation SHOULD ensure that a new +// random value gets re-computed at least once every few hours. // // s.mu MUST be locked for writing. func (s *NUDState) recomputeReachableTimeLocked() { diff --git a/pkg/tcpip/stack/packet_buffer.go b/pkg/tcpip/stack/packet_buffer.go index c12777174..faff8b538 100644 --- a/pkg/tcpip/stack/packet_buffer.go +++ b/pkg/tcpip/stack/packet_buffer.go @@ -83,14 +83,14 @@ type PacketBufferOptions struct { // exposes a logically-contiguous byte storage. The underlying storage structure // is abstracted out, and should not be a concern here for most of the time. // -// |- reserved ->| -// |--->| consumed (incoming) -// 0 V V -// +--------+----+----+--------------------+ -// | | | | current data ... | (buf) -// +--------+----+----+--------------------+ -// ^ | -// |<---| pushed (outgoing) +// |- reserved ->| +// |--->| consumed (incoming) +// 0 V V +// +--------+----+----+--------------------+ +// | | | | current data ... | (buf) +// +--------+----+----+--------------------+ +// ^ | +// |<---| pushed (outgoing) // // When a PacketBuffer is created, a `reserved` header region can be specified, // which stack pushes headers in this region for an outgoing packet. There could diff --git a/pkg/tcpip/stack/registration.go b/pkg/tcpip/stack/registration.go index ac6c82300..9d09c49bb 100644 --- a/pkg/tcpip/stack/registration.go +++ b/pkg/tcpip/stack/registration.go @@ -750,10 +750,10 @@ type NetworkProtocol interface { // Parse sets pkt.NetworkHeader and trims pkt.Data appropriately. It // returns: - // - The encapsulated protocol, if present. - // - Whether there is an encapsulated transport protocol payload (e.g. ARP - // does not encapsulate anything). - // - Whether pkt.Data was large enough to parse and set pkt.NetworkHeader. + // - The encapsulated protocol, if present. + // - Whether there is an encapsulated transport protocol payload (e.g. ARP + // does not encapsulate anything). + // - Whether pkt.Data was large enough to parse and set pkt.NetworkHeader. Parse(pkt *PacketBuffer) (proto tcpip.TransportProtocolNumber, hasTransportHdr bool, ok bool) } diff --git a/pkg/tcpip/stack/stack.go b/pkg/tcpip/stack/stack.go index 43e7c2a48..413864df4 100644 --- a/pkg/tcpip/stack/stack.go +++ b/pkg/tcpip/stack/stack.go @@ -436,13 +436,13 @@ func (s *Stack) SetNetworkProtocolOption(network tcpip.NetworkProtocolNumber, op // NetworkProtocolOption allows retrieving individual protocol level option // values. This method returns an error if the protocol is not supported or -// option is not supported by the protocol implementation. -// e.g. -// var v ipv4.MyOption -// err := s.NetworkProtocolOption(tcpip.IPv4ProtocolNumber, &v) -// if err != nil { -// ... -// } +// option is not supported by the protocol implementation. E.g.: +// +// var v ipv4.MyOption +// err := s.NetworkProtocolOption(tcpip.IPv4ProtocolNumber, &v) +// if err != nil { +// ... +// } func (s *Stack) NetworkProtocolOption(network tcpip.NetworkProtocolNumber, option tcpip.GettableNetworkProtocolOption) tcpip.Error { netProto, ok := s.networkProtocols[network] if !ok { @@ -466,10 +466,11 @@ func (s *Stack) SetTransportProtocolOption(transport tcpip.TransportProtocolNumb // TransportProtocolOption allows retrieving individual protocol level option // values. This method returns an error if the protocol is not supported or // option is not supported by the protocol implementation. -// var v tcp.SACKEnabled -// if err := s.TransportProtocolOption(tcpip.TCPProtocolNumber, &v); err != nil { -// ... -// } +// +// var v tcp.SACKEnabled +// if err := s.TransportProtocolOption(tcpip.TCPProtocolNumber, &v); err != nil { +// ... +// } func (s *Stack) TransportProtocolOption(transport tcpip.TransportProtocolNumber, option tcpip.GettableTransportProtocolOption) tcpip.Error { transProtoState, ok := s.transportProtocols[transport] if !ok { diff --git a/pkg/tcpip/tests/integration/iptables_test.go b/pkg/tcpip/tests/integration/iptables_test.go index c7286d57e..e1e7820eb 100644 --- a/pkg/tcpip/tests/integration/iptables_test.go +++ b/pkg/tcpip/tests/integration/iptables_test.go @@ -1600,17 +1600,17 @@ func TestNAT(t *testing.T) { netProto tcpip.NetworkProtocolNumber // Setups up the stacks in such a way that: // - // - Host2 is the client for all tests. - // - When performing SNAT only: + // - Host2 is the client for all tests. + // - When performing SNAT only: // + Host1 is the server. // + NAT will transform client-originating packets' source addresses to // the router's NIC1's address before reaching Host1. - // - When performing DNAT only: + // - When performing DNAT only: // + Router is the server. // + Client will send packets directed to Host1. // + NAT will transform client-originating packets' destination addresses // to the router's NIC2's address. - // - When performing Twice-NAT: + // - When performing Twice-NAT: // + Host1 is the server. // + Client will send packets directed to router's NIC2. // + NAT will transform client originating packets' destination addresses diff --git a/pkg/tcpip/tests/integration/istio_test.go b/pkg/tcpip/tests/integration/istio_test.go index 3a66b3724..cd74bd6d1 100644 --- a/pkg/tcpip/tests/integration/istio_test.go +++ b/pkg/tcpip/tests/integration/istio_test.go @@ -42,31 +42,31 @@ import ( // an istio like environment. // // A diagram depicting the setup is shown below. -// +-----------------------------------------------------------------------+ -// | +-------------------------------------------------+ | -// | + ----------+ | + -----------------+ PROXY +----------+ | | -// | | clientEP | | | serverListeningEP|--accepted-> | serverEP |-+ | | -// | + ----------+ | + -----------------+ +----------+ | | | -// | | -------|-------------+ +----------+ | | | -// | | | | | proxyEP |-+ | | -// | +-----redirect | +----------+ | | -// | + ------------+---|------+---+ | -// | | | -// | Local Stack. | | -// +-------------------------------------------------------|---------------+ -// | -// +-----------------------------------------------------------------------+ -// | remoteStack | | -// | +-------------SYN ---------------| | -// | | | | -// | +-------------------|--------------------------------|-_---+ | -// | | + -----------------+ + ----------+ | | | -// | | | remoteListeningEP|--accepted--->| remoteEP |<++ | | -// | | + -----------------+ + ----------+ | | -// | | Remote HTTP Server | | -// | +----------------------------------------------------------+ | -// +-----------------------------------------------------------------------+ // +// +-----------------------------------------------------------------------+ +// | +-------------------------------------------------+ | +// | + ----------+ | + -----------------+ PROXY +----------+ | | +// | | clientEP | | | serverListeningEP|--accepted-> | serverEP |-+ | | +// | + ----------+ | + -----------------+ +----------+ | | | +// | | -------|-------------+ +----------+ | | | +// | | | | | proxyEP |-+ | | +// | +-----redirect | +----------+ | | +// | + ------------+---|------+---+ | +// | | | +// | Local Stack. | | +// +-------------------------------------------------------|---------------+ +// | +// +-----------------------------------------------------------------------+ +// | remoteStack | | +// | +-------------SYN ---------------| | +// | | | | +// | +-------------------|--------------------------------|-_---+ | +// | | + -----------------+ + ----------+ | | | +// | | | remoteListeningEP|--accepted--->| remoteEP |<++ | | +// | | + -----------------+ + ----------+ | | +// | | Remote HTTP Server | | +// | +----------------------------------------------------------+ | +// +-----------------------------------------------------------------------+ type testContext struct { // localServerListener is the listening port for the server which will proxy // all traffic to the remote EP. diff --git a/pkg/tcpip/tests/integration/link_resolution_test.go b/pkg/tcpip/tests/integration/link_resolution_test.go index a6f4b4b57..93ffab25b 100644 --- a/pkg/tcpip/tests/integration/link_resolution_test.go +++ b/pkg/tcpip/tests/integration/link_resolution_test.go @@ -1444,11 +1444,11 @@ func TestTCPConfirmNeighborReachability(t *testing.T) { // Incoming TCP segments are handled in // tcp.(*endpoint).handleSegmentLocked: // - // - tcp.(*endpoint).rcv.handleRcvdSegment puts the segment on the - // segment queue and notifies waiting readers (such as this channel) + // - tcp.(*endpoint).rcv.handleRcvdSegment puts the segment on the + // segment queue and notifies waiting readers (such as this channel) // - // - tcp.(*endpoint).snd.handleRcvdSegment sends an ACK for the segment - // and notifies the NUD machinery that the peer is reachable + // - tcp.(*endpoint).snd.handleRcvdSegment sends an ACK for the segment + // and notifies the NUD machinery that the peer is reachable // // Thus we must permit a delay between the readable signal and the // expected NUD event. diff --git a/pkg/tcpip/timer.go b/pkg/tcpip/timer.go index f1dd7c310..b80b34581 100644 --- a/pkg/tcpip/timer.go +++ b/pkg/tcpip/timer.go @@ -31,19 +31,20 @@ import ( // earlyReturn signal (T1 creates, stops and resets a Cancellable timer under a // lock L; T2, T3, T4 and T5 are goroutines that handle the first (A), second // (B), third (C), and fourth (D) instance of the timer firing, respectively): -// T1: Obtain L -// T1: Create a new Job w/ lock L (create instance A) -// T2: instance A fires, blocked trying to obtain L. -// T1: Attempt to stop instance A (set earlyReturn = true) -// T1: Schedule timer (create instance B) -// T3: instance B fires, blocked trying to obtain L. -// T1: Attempt to stop instance B (set earlyReturn = true) -// T1: Schedule timer (create instance C) -// T4: instance C fires, blocked trying to obtain L. -// T1: Attempt to stop instance C (set earlyReturn = true) -// T1: Schedule timer (create instance D) -// T5: instance D fires, blocked trying to obtain L. -// T1: Release L +// +// T1: Obtain L +// T1: Create a new Job w/ lock L (create instance A) +// T2: instance A fires, blocked trying to obtain L. +// T1: Attempt to stop instance A (set earlyReturn = true) +// T1: Schedule timer (create instance B) +// T3: instance B fires, blocked trying to obtain L. +// T1: Attempt to stop instance B (set earlyReturn = true) +// T1: Schedule timer (create instance C) +// T4: instance C fires, blocked trying to obtain L. +// T1: Attempt to stop instance C (set earlyReturn = true) +// T1: Schedule timer (create instance D) +// T5: instance D fires, blocked trying to obtain L. +// T1: Release L // // Now that T1 has released L, any of the 4 timer instances can take L and // check earlyReturn. If the timers simply check earlyReturn and then do @@ -168,35 +169,35 @@ func (j *Job) Schedule(d time.Duration) { // NewJob returns a new Job that can be used to schedule f to run in its own // gorountine. l will be locked before calling f then unlocked after f returns. // -// var clock tcpip.StdClock -// var mu sync.Mutex -// message := "foo" -// job := tcpip.NewJob(&clock, &mu, func() { -// fmt.Println(message) -// }) -// job.Schedule(time.Second) +// var clock tcpip.StdClock +// var mu sync.Mutex +// message := "foo" +// job := tcpip.NewJob(&clock, &mu, func() { +// fmt.Println(message) +// }) +// job.Schedule(time.Second) // -// mu.Lock() -// message = "bar" -// mu.Unlock() +// mu.Lock() +// message = "bar" +// mu.Unlock() // -// // Output: bar +// // Output: bar // // f MUST NOT attempt to lock l. // // l MUST be locked prior to calling the returned job's Cancel(). // -// var clock tcpip.StdClock -// var mu sync.Mutex -// message := "foo" -// job := tcpip.NewJob(&clock, &mu, func() { -// fmt.Println(message) -// }) -// job.Schedule(time.Second) +// var clock tcpip.StdClock +// var mu sync.Mutex +// message := "foo" +// job := tcpip.NewJob(&clock, &mu, func() { +// fmt.Println(message) +// }) +// job.Schedule(time.Second) // -// mu.Lock() -// job.Cancel() -// mu.Unlock() +// mu.Lock() +// job.Cancel() +// mu.Unlock() func NewJob(c Clock, l sync.Locker, f func()) *Job { return &Job{ clock: c, diff --git a/pkg/tcpip/transport/packet/endpoint.go b/pkg/tcpip/transport/packet/endpoint.go index 7afc88c1a..14b0b0767 100644 --- a/pkg/tcpip/transport/packet/endpoint.go +++ b/pkg/tcpip/transport/packet/endpoint.go @@ -15,8 +15,8 @@ // Package packet provides the implementation of packet sockets (see // packet(7)). Packet sockets allow applications to: // -// * manually write and inspect link, network, and transport headers -// * receive all traffic of a given network protocol, or all protocols +// - manually write and inspect link, network, and transport headers +// - receive all traffic of a given network protocol, or all protocols // // Packet sockets are similar to raw sockets, but provide even more power to // users, letting them effectively talk directly to the network device. @@ -54,8 +54,9 @@ type packet struct { // to have goroutines make concurrent calls into the endpoint. // // Lock order: -// endpoint.mu -// endpoint.rcvMu +// +// endpoint.mu +// endpoint.rcvMu // // +stateify savable type endpoint struct { diff --git a/pkg/tcpip/transport/raw/endpoint.go b/pkg/tcpip/transport/raw/endpoint.go index 5ad5a781a..ba767abf5 100644 --- a/pkg/tcpip/transport/raw/endpoint.go +++ b/pkg/tcpip/transport/raw/endpoint.go @@ -15,9 +15,9 @@ // Package raw provides the implementation of raw sockets (see raw(7)). Raw // sockets allow applications to: // -// * manually write and inspect transport layer headers and payloads -// * receive all traffic of a given transport protocol (e.g. ICMP or UDP) -// * optionally write and inspect network layer headers of packets +// - manually write and inspect transport layer headers and payloads +// - receive all traffic of a given transport protocol (e.g. ICMP or UDP) +// - optionally write and inspect network layer headers of packets // // Raw sockets don't have any notion of ports, and incoming packets are // demultiplexed solely by protocol number. Thus, a raw UDP endpoint will @@ -62,8 +62,9 @@ type rawPacket struct { // have goroutines make concurrent calls into the endpoint. // // Lock order: -// endpoint.mu -// endpoint.rcvMu +// +// endpoint.mu +// endpoint.rcvMu // // +stateify savable type endpoint struct { diff --git a/pkg/tcpip/transport/tcp/rack.go b/pkg/tcpip/transport/tcp/rack.go index b8d0bb653..c7d8f6638 100644 --- a/pkg/tcpip/transport/tcp/rack.go +++ b/pkg/tcpip/transport/tcp/rack.go @@ -122,15 +122,15 @@ func (rc *rackControl) update(seg *segment, ackSeg *segment) { // detectReorder detects if packet reordering has been observed. // See: https://tools.ietf.org/html/draft-ietf-tcpm-rack-08#section-7.2 -// * Step 3: Detect data segment reordering. -// To detect reordering, the sender looks for original data segments being -// delivered out of order. To detect such cases, the sender tracks the -// highest sequence selectively or cumulatively acknowledged in the RACK.fack -// variable. The name "fack" stands for the most "Forward ACK" (this term is -// adopted from [FACK]). If a never retransmitted segment that's below -// RACK.fack is (selectively or cumulatively) acknowledged, it has been -// delivered out of order. The sender sets RACK.reord to TRUE if such segment -// is identified. +// - Step 3: Detect data segment reordering. +// To detect reordering, the sender looks for original data segments being +// delivered out of order. To detect such cases, the sender tracks the +// highest sequence selectively or cumulatively acknowledged in the RACK.fack +// variable. The name "fack" stands for the most "Forward ACK" (this term is +// adopted from [FACK]). If a never retransmitted segment that's below +// RACK.fack is (selectively or cumulatively) acknowledged, it has been +// delivered out of order. The sender sets RACK.reord to TRUE if such segment +// is identified. func (rc *rackControl) detectReorder(seg *segment) { endSeq := seg.sequenceNumber.Add(seqnum.Size(seg.data.Size())) if rc.FACK.LessThan(endSeq) { @@ -273,13 +273,13 @@ func (s *sender) detectTLPRecovery(ack seqnum.Value, rcvdSeg *segment) { // updateRACKReorderWindow updates the reorder window. // See: https://tools.ietf.org/html/draft-ietf-tcpm-rack-08#section-7.2 -// * Step 4: Update RACK reordering window -// To handle the prevalent small degree of reordering, RACK.reo_wnd serves as -// an allowance for settling time before marking a packet lost. RACK starts -// initially with a conservative window of min_RTT/4. If no reordering has -// been observed RACK uses reo_wnd of zero during loss recovery, in order to -// retransmit quickly, or when the number of DUPACKs exceeds the classic -// DUPACKthreshold. +// - Step 4: Update RACK reordering window +// To handle the prevalent small degree of reordering, RACK.reo_wnd serves as +// an allowance for settling time before marking a packet lost. RACK starts +// initially with a conservative window of min_RTT/4. If no reordering has +// been observed RACK uses reo_wnd of zero during loss recovery, in order to +// retransmit quickly, or when the number of DUPACKs exceeds the classic +// DUPACKthreshold. func (rc *rackControl) updateRACKReorderWindow() { dsackSeen := rc.DSACKSeen snd := rc.snd diff --git a/pkg/tcpip/transport/tcp/sack_scoreboard.go b/pkg/tcpip/transport/tcp/sack_scoreboard.go index 833a7b470..fb7f4e3ff 100644 --- a/pkg/tcpip/transport/tcp/sack_scoreboard.go +++ b/pkg/tcpip/transport/tcp/sack_scoreboard.go @@ -90,9 +90,9 @@ func (s *SACKScoreboard) Insert(r header.SACKBlock) { // There is some overlap at this point, merge the blocks and // delete the other one. // - // ----sS--------sE - // r.S---------------rE - // -------sE + // ----sS--------sE + // r.S---------------rE + // -------sE if sacked.End.LessThan(r.End) { // sacked is contained in the newly inserted range. // Delete this block. diff --git a/pkg/tcpip/transport/tcp/snd.go b/pkg/tcpip/transport/tcp/snd.go index 2c8d51a7c..0a6b32e9e 100644 --- a/pkg/tcpip/transport/tcp/snd.go +++ b/pkg/tcpip/transport/tcp/snd.go @@ -1251,15 +1251,15 @@ func checkDSACK(rcvdSeg *segment) bool { // See: https://tools.ietf.org/html/rfc2883#section-5 DSACK is sent in // at most one SACK block. DSACK is detected in the below two cases: - // * If the SACK sequence space is less than this cumulative ACK, it is - // an indication that the segment identified by the SACK block has - // been received more than once by the receiver. - // * If the sequence space in the first SACK block is greater than the - // cumulative ACK, then the sender next compares the sequence space - // in the first SACK block with the sequence space in the second SACK - // block, if there is one. This comparison can determine if the first - // SACK block is reporting duplicate data that lies above the - // cumulative ACK. + // * If the SACK sequence space is less than this cumulative ACK, it is + // an indication that the segment identified by the SACK block has + // been received more than once by the receiver. + // * If the sequence space in the first SACK block is greater than the + // cumulative ACK, then the sender next compares the sequence space + // in the first SACK block with the sequence space in the second SACK + // block, if there is one. This comparison can determine if the first + // SACK block is reporting duplicate data that lies above the + // cumulative ACK. if sb.Start.LessThan(rcvdSeg.ackNumber) { return true } @@ -1406,17 +1406,17 @@ func (s *sender) handleRcvdSegment(rcvdSeg *segment) { // See: https://tools.ietf.org/html/draft-ietf-tcpm-rack-08 // section-7.2 - // * Step 2: Update RACK stats. - // If the ACK is not ignored as invalid, update the RACK.rtt - // to be the RTT sample calculated using this ACK, and - // continue. If this ACK or SACK was for the most recently - // sent packet, then record the RACK.xmit_ts timestamp and - // RACK.end_seq sequence implied by this ACK. - // * Step 3: Detect packet reordering. - // If the ACK selectively or cumulatively acknowledges an - // unacknowledged and also never retransmitted sequence below - // RACK.fack, then the corresponding packet has been - // reordered and RACK.reord is set to TRUE. + // * Step 2: Update RACK stats. + // If the ACK is not ignored as invalid, update the RACK.rtt + // to be the RTT sample calculated using this ACK, and + // continue. If this ACK or SACK was for the most recently + // sent packet, then record the RACK.xmit_ts timestamp and + // RACK.end_seq sequence implied by this ACK. + // * Step 3: Detect packet reordering. + // If the ACK selectively or cumulatively acknowledges an + // unacknowledged and also never retransmitted sequence below + // RACK.fack, then the corresponding packet has been + // reordered and RACK.reord is set to TRUE. if s.ep.tcpRecovery&tcpip.TCPRACKLossDetection != 0 { hasDSACK = s.walkSACK(rcvdSeg) } @@ -1583,8 +1583,8 @@ func (s *sender) handleRcvdSegment(rcvdSeg *segment) { if s.ep.SACKPermitted && s.ep.tcpRecovery&tcpip.TCPRACKLossDetection != 0 { // Update RACK reorder window. // See: https://tools.ietf.org/html/draft-ietf-tcpm-rack-08#section-7.2 - // * Upon receiving an ACK: - // * Step 4: Update RACK reordering window + // * Upon receiving an ACK: + // * Step 4: Update RACK reordering window s.rc.updateRACKReorderWindow() // After the reorder window is calculated, detect any loss by checking diff --git a/pkg/tcpip/transport/tcp/test/e2e/tcp_sack_test.go b/pkg/tcpip/transport/tcp/test/e2e/tcp_sack_test.go index e70ace16a..6e6c50c92 100644 --- a/pkg/tcpip/transport/tcp/test/e2e/tcp_sack_test.go +++ b/pkg/tcpip/transport/tcp/test/e2e/tcp_sack_test.go @@ -582,10 +582,10 @@ func TestSACKRecovery(t *testing.T) { } // TestRecoveryEntry tests the following two properties of entering recovery: -// - Fast SACK recovery is entered when SND.UNA is considered lost by the SACK -// scoreboard but dupack count is still below threshold. -// - Only enter recovery when at least one more byte of data beyond the highest -// byte that was outstanding when fast retransmit was last entered is acked. +// - Fast SACK recovery is entered when SND.UNA is considered lost by the SACK +// scoreboard but dupack count is still below threshold. +// - Only enter recovery when at least one more byte of data beyond the highest +// byte that was outstanding when fast retransmit was last entered is acked. func TestRecoveryEntry(t *testing.T) { c := context.New(t, uint32(mtu)) defer c.Cleanup() diff --git a/pkg/unet/unet.go b/pkg/unet/unet.go index 05d56538f..9510a07ea 100644 --- a/pkg/unet/unet.go +++ b/pkg/unet/unet.go @@ -511,7 +511,7 @@ func (s *ServerSocket) Listen() error { // This is always blocking. // // Preconditions: -// * ServerSocket is listening (Listen called). +// - ServerSocket is listening (Listen called). func (s *ServerSocket) Accept() (*Socket, error) { fd, ok := s.socket.enterFD() if !ok { diff --git a/pkg/urpc/urpc.go b/pkg/urpc/urpc.go index 0ef635a2f..44c974d0d 100644 --- a/pkg/urpc/urpc.go +++ b/pkg/urpc/urpc.go @@ -152,7 +152,6 @@ type registeredMethod struct { // idle -> processing, closed // processing -> idle, closeRequested // closeRequested -> closed -// type clientState int // See clientState. diff --git a/pkg/usermem/usermem.go b/pkg/usermem/usermem.go index f46a00e42..2594294a8 100644 --- a/pkg/usermem/usermem.go +++ b/pkg/usermem/usermem.go @@ -55,9 +55,9 @@ type IO interface { // non-nil error explaining why. // // Preconditions: - // * The caller must not hold mm.MemoryManager.mappingMu or any - // following locks in the lock order. - // * toZero >= 0. + // * The caller must not hold mm.MemoryManager.mappingMu or any + // following locks in the lock order. + // * toZero >= 0. ZeroOut(ctx context.Context, addr hostarch.Addr, toZero int64, opts IOOpts) (int64, error) // CopyOutFrom copies ars.NumBytes() bytes from src to the memory mapped at @@ -69,10 +69,10 @@ type IO interface { // CopyOutFrom calls src.ReadToBlocks at most once. // // Preconditions: - // * The caller must not hold mm.MemoryManager.mappingMu or any - // following locks in the lock order. - // * src.ReadToBlocks must not block on mm.MemoryManager.activeMu or - // any preceding locks in the lock order. + // * The caller must not hold mm.MemoryManager.mappingMu or any + // following locks in the lock order. + // * src.ReadToBlocks must not block on mm.MemoryManager.activeMu or + // any preceding locks in the lock order. CopyOutFrom(ctx context.Context, ars hostarch.AddrRangeSeq, src safemem.Reader, opts IOOpts) (int64, error) // CopyInTo copies ars.NumBytes() bytes from the memory mapped at ars to @@ -83,10 +83,10 @@ type IO interface { // CopyInTo calls dst.WriteFromBlocks at most once. // // Preconditions: - // * The caller must not hold mm.MemoryManager.mappingMu or any - // following locks in the lock order. - // * dst.WriteFromBlocks must not block on mm.MemoryManager.activeMu or - // any preceding locks in the lock order. + // * The caller must not hold mm.MemoryManager.mappingMu or any + // following locks in the lock order. + // * dst.WriteFromBlocks must not block on mm.MemoryManager.activeMu or + // any preceding locks in the lock order. CopyInTo(ctx context.Context, ars hostarch.AddrRangeSeq, dst safemem.Writer, opts IOOpts) (int64, error) // TODO(jamieliu): The requirement that CopyOutFrom/CopyInTo call src/dst @@ -99,9 +99,9 @@ type IO interface { // returns the previous value. // // Preconditions: - // * The caller must not hold mm.MemoryManager.mappingMu or any - // following locks in the lock order. - // * addr must be aligned to a 4-byte boundary. + // * The caller must not hold mm.MemoryManager.mappingMu or any + // following locks in the lock order. + // * addr must be aligned to a 4-byte boundary. SwapUint32(ctx context.Context, addr hostarch.Addr, new uint32, opts IOOpts) (uint32, error) // CompareAndSwapUint32 atomically compares the uint32 value at addr to @@ -109,17 +109,17 @@ type IO interface { // either case, the previous value stored in memory is returned. // // Preconditions: - // * The caller must not hold mm.MemoryManager.mappingMu or any - // following locks in the lock order. - // * addr must be aligned to a 4-byte boundary. + // * The caller must not hold mm.MemoryManager.mappingMu or any + // following locks in the lock order. + // * addr must be aligned to a 4-byte boundary. CompareAndSwapUint32(ctx context.Context, addr hostarch.Addr, old, new uint32, opts IOOpts) (uint32, error) // LoadUint32 atomically loads the uint32 value at addr and returns it. // // Preconditions: - // * The caller must not hold mm.MemoryManager.mappingMu or any - // following locks in the lock order. - // * addr must be aligned to a 4-byte boundary. + // * The caller must not hold mm.MemoryManager.mappingMu or any + // following locks in the lock order. + // * addr must be aligned to a 4-byte boundary. LoadUint32(ctx context.Context, addr hostarch.Addr, opts IOOpts) (uint32, error) } @@ -197,7 +197,7 @@ const ( // ENAMETOOLONG. // // Preconditions: Same as IO.CopyFromUser, plus: -// * maxlen >= 0. +// - maxlen >= 0. func CopyStringIn(ctx context.Context, uio IO, addr hostarch.Addr, maxlen int, opts IOOpts) (string, error) { initLen := maxlen if initLen > copyStringMaxInitBufLen { @@ -335,22 +335,22 @@ func isASCIIWhitespace(b byte) bool { // CopyInt32StringsInVec shares the following properties with Linux's // kernel/sysctl.c:proc_dointvec(write=1): // -// - If any read value overflows the range of int32, or any invalid characters -// are encountered during the read, CopyInt32StringsInVec returns EINVAL. +// - If any read value overflows the range of int32, or any invalid characters +// are encountered during the read, CopyInt32StringsInVec returns EINVAL. // -// - If, upon reaching the end of ars, fewer than len(dsts) values have been -// read, CopyInt32StringsInVec returns no error if at least 1 value was read -// and EINVAL otherwise. +// - If, upon reaching the end of ars, fewer than len(dsts) values have been +// read, CopyInt32StringsInVec returns no error if at least 1 value was read +// and EINVAL otherwise. // -// - Trailing whitespace after the last successfully read value is counted in -// the number of bytes read. +// - Trailing whitespace after the last successfully read value is counted in +// the number of bytes read. // // Unlike proc_dointvec(): // -// - CopyInt32StringsInVec does not implicitly limit ars.NumBytes() to -// PageSize-1; callers that require this must do so explicitly. +// - CopyInt32StringsInVec does not implicitly limit ars.NumBytes() to +// PageSize-1; callers that require this must do so explicitly. // -// - CopyInt32StringsInVec returns EINVAL if ars.NumBytes() == 0. +// - CopyInt32StringsInVec returns EINVAL if ars.NumBytes() == 0. // // Preconditions: Same as CopyInVec. func CopyInt32StringsInVec(ctx context.Context, uio IO, ars hostarch.AddrRangeSeq, dsts []int32, opts IOOpts) (int64, error) { @@ -425,13 +425,13 @@ type IOSequence struct { // Many clients of // IOSequence currently do something like: // -// if ioseq.NumBytes() == 0 { -// return 0, nil -// } -// if f.availableBytes == 0 { -// return 0, linuxerr.ErrWouldBlock -// } -// return ioseq.CopyOutFrom(..., reader) +// if ioseq.NumBytes() == 0 { +// return 0, nil +// } +// if f.availableBytes == 0 { +// return 0, linuxerr.ErrWouldBlock +// } +// return ioseq.CopyOutFrom(..., reader) // // In such cases, using s.Addrs.IsEmpty() will cause them to have the wrong // behavior for zero-length I/O. However, using s.NumBytes() == 0 instead means diff --git a/runsc/boot/fs.go b/runsc/boot/fs.go index 86bf04ca2..ae6f17246 100644 --- a/runsc/boot/fs.go +++ b/runsc/boot/fs.go @@ -1051,8 +1051,8 @@ func (c *containerMounter) createRestoreEnvironment(conf *config.Config) (*fs.Re // Technically we don't have to mount tmpfs at /tmp, as we could just rely on // the host /tmp, but this is a nice optimization, and fixes some apps that call // mknod in /tmp. It's unsafe to mount tmpfs if: -// 1. /tmp is mounted explicitly: we should not override user's wish -// 2. /tmp is not empty: mounting tmpfs would hide existing files in /tmp +// 1. /tmp is mounted explicitly: we should not override user's wish +// 2. /tmp is not empty: mounting tmpfs would hide existing files in /tmp // // Note that when there are submounts inside of '/tmp', directories for the // mount points must be present, making '/tmp' not empty anymore. diff --git a/runsc/boot/loader.go b/runsc/boot/loader.go index 12bf778e4..28cc346dc 100644 --- a/runsc/boot/loader.go +++ b/runsc/boot/loader.go @@ -228,7 +228,7 @@ type Args struct { // /sys/devices/virtual/dmi/id/product_name. ProductName string // PodInitConfigFD is the file descriptor to a file passed in the - // --pod-init-config flag + // --pod-init-config flag PodInitConfigFD int // SinkFDs is an ordered array of file descriptors to be used by seccheck // sinks configured from the --pod-init-config file. diff --git a/runsc/boot/vfs.go b/runsc/boot/vfs.go index fe7304826..28431f424 100644 --- a/runsc/boot/vfs.go +++ b/runsc/boot/vfs.go @@ -648,8 +648,8 @@ func parseVerityMountOptions(mopts []string) (string, verity.InternalFilesystemO // Technically we don't have to mount tmpfs at /tmp, as we could just rely on // the host /tmp, but this is a nice optimization, and fixes some apps that call // mknod in /tmp. It's unsafe to mount tmpfs if: -// 1. /tmp is mounted explicitly: we should not override user's wish -// 2. /tmp is not empty: mounting tmpfs would hide existing files in /tmp +// 1. /tmp is mounted explicitly: we should not override user's wish +// 2. /tmp is not empty: mounting tmpfs would hide existing files in /tmp // // Note that when there are submounts inside of '/tmp', directories for the // mount points must be present, making '/tmp' not empty anymore. diff --git a/runsc/cgroup/cgroup.go b/runsc/cgroup/cgroup.go index 0cc6bbfec..574799fdf 100644 --- a/runsc/cgroup/cgroup.go +++ b/runsc/cgroup/cgroup.go @@ -170,7 +170,8 @@ func fillFromAncestor(path string) (string, error) { } // countCpuset returns the number of CPU in a string formatted like: -// "0-2,7,12-14 # bits 0, 1, 2, 7, 12, 13, and 14 set" - man 7 cpuset +// +// "0-2,7,12-14 # bits 0, 1, 2, 7, 12, 13, and 14 set" - man 7 cpuset func countCpuset(cpuset string) (int, error) { var count int for _, p := range strings.Split(cpuset, ",") { @@ -321,13 +322,15 @@ type Cgroup interface { } // cgroupV1 represents a group inside all controllers. For example: -// Name='/foo/bar' maps to /sys/fs/cgroup//foo/bar on -// all controllers. +// +// Name='/foo/bar' maps to /sys/fs/cgroup//foo/bar on +// all controllers. // // If Name is relative, it uses the parent cgroup path to determine the // location. For example: -// Name='foo/bar' and Parent[ctrl]="/user.slice", then it will map to -// /sys/fs/cgroup//user.slice/foo/bar +// +// Name='foo/bar' and Parent[ctrl]="/user.slice", then it will map to +// /sys/fs/cgroup//user.slice/foo/bar type cgroupV1 struct { Name string `json:"name"` Parents map[string]string `json:"parents"` diff --git a/runsc/cgroup/cgroup_v2.go b/runsc/cgroup/cgroup_v2.go index b5cc59130..b2dccfa55 100644 --- a/runsc/cgroup/cgroup_v2.go +++ b/runsc/cgroup/cgroup_v2.go @@ -96,8 +96,8 @@ func (c *cgroupV2) createCgroupPaths() (bool, error) { // setup all known controllers for the current subtree // For example, given path /foo/bar and mount /sys/fs/cgroup, we need to write // the controllers to: - // * /sys/fs/cgroup/cgroup.subtree_control - // * /sys/fs/cgroup/foo/cgroup.subtree_control + // * /sys/fs/cgroup/cgroup.subtree_control + // * /sys/fs/cgroup/foo/cgroup.subtree_control val := "+" + strings.Join(c.Controllers, " +") elements := strings.Split(c.Path, "/") current := c.Mountpoint @@ -724,7 +724,7 @@ func convertMemorySwapToCgroupV2Value(memorySwap, memory int64) (int64, error) { return -1, nil } if memorySwap == -1 || memorySwap == 0 { - // -1 is "max", 0 is "unset", so treat as is + // -1 is "max", 0 is "unset", so treat as is. return memorySwap, nil } // sanity checks diff --git a/runsc/cgroup/cgroup_v2_test.go b/runsc/cgroup/cgroup_v2_test.go index f2a8bcc4c..4f7dbfc6d 100644 --- a/runsc/cgroup/cgroup_v2_test.go +++ b/runsc/cgroup/cgroup_v2_test.go @@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// https://www.apache.org/licenses/LICENSE-2.0 +// https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, diff --git a/runsc/cmd/util/util.go b/runsc/cmd/util/util.go index f7bc438ee..7170e35b8 100644 --- a/runsc/cmd/util/util.go +++ b/runsc/cmd/util/util.go @@ -40,8 +40,8 @@ type jsonError struct { // Errorf logs error to containerd log (--log), to stderr, and debug logs. It // returns subcommands.ExitFailure for convenience with subcommand.Execute() // methods: -// return Errorf("Danger! Danger!") // +// return Errorf("Danger! Danger!") func Errorf(format string, args ...interface{}) subcommands.ExitStatus { // If runsc is being invoked by docker or cri-o, then we might not have // access to stderr, so we log a serious-looking warning in addition to diff --git a/runsc/config/config.go b/runsc/config/config.go index 770d09170..0f3b2b9f4 100644 --- a/runsc/config/config.go +++ b/runsc/config/config.go @@ -29,14 +29,13 @@ import ( // Config holds configuration that is not part of the runtime spec. // // Follow these steps to add a new flag: -// 1. Create a new field in Config. -// 2. Add a field tag with the flag name -// 3. Register a new flag in flags.go, with same name and add a description -// 4. Add any necessary validation into validate() -// 5. If adding an enum, follow the same pattern as FileAccessType -// 6. Evaluate if the flag can be changed with OCI annotations. See -// overrideAllowlist for more details -// +// 1. Create a new field in Config. +// 2. Add a field tag with the flag name +// 3. Register a new flag in flags.go, with same name and add a description +// 4. Add any necessary validation into validate() +// 5. If adding an enum, follow the same pattern as FileAccessType +// 6. Evaluate if the flag can be changed with OCI annotations. See +// overrideAllowlist for more details type Config struct { // RootDir is the runtime root directory. RootDir string `flag:"root"` diff --git a/runsc/container/container.go b/runsc/container/container.go index 973c806ac..8600385b0 100644 --- a/runsc/container/container.go +++ b/runsc/container/container.go @@ -740,9 +740,9 @@ func (c *Container) Destroy() error { sb := c.Sandbox // We must perform the following cleanup steps: - // * stop the container and gofer processes, - // * remove the container filesystem on the host, and - // * delete the container metadata directory. + // * stop the container and gofer processes, + // * remove the container filesystem on the host, and + // * delete the container metadata directory. // // It's possible for one or more of these steps to fail, but we should // do our best to perform all of the cleanups. Hence, we keep a slice diff --git a/runsc/container/container_test.go b/runsc/container/container_test.go index 8ca2fd68a..c0f045414 100644 --- a/runsc/container/container_test.go +++ b/runsc/container/container_test.go @@ -1458,10 +1458,10 @@ func TestPauseResumeStatus(t *testing.T) { } // TestCapabilities verifies that: -// - Running exec as non-root UID and GID will result in an error (because the -// executable file can't be read). -// - Running exec as non-root with CAP_DAC_OVERRIDE succeeds because it skips -// this check. +// - Running exec as non-root UID and GID will result in an error (because the +// executable file can't be read). +// - Running exec as non-root with CAP_DAC_OVERRIDE succeeds because it skips +// this check. func TestCapabilities(t *testing.T) { // Pick uid/gid different than ours. uid := auth.KUID(os.Getuid() + 1) diff --git a/runsc/fsgofer/fsgofer.go b/runsc/fsgofer/fsgofer.go index 672e5951c..e38dba15a 100644 --- a/runsc/fsgofer/fsgofer.go +++ b/runsc/fsgofer/fsgofer.go @@ -16,8 +16,8 @@ // a simple mapping from a path prefix that is added to the path requested // by the sandbox. Ex: // -// prefix: "/docker/imgs/alpine" -// app path: /bin/ls => /docker/imgs/alpine/bin/ls +// prefix: "/docker/imgs/alpine" +// app path: /bin/ls => /docker/imgs/alpine/bin/ls package fsgofer import ( @@ -202,10 +202,10 @@ func (a *attachPoint) makeQID(stat *unix.Stat_t) p9.QID { // multiple files are only being opened for read (esp. startup). // // File operations must use "at" functions whenever possible: -// * Local operations must use AT_EMPTY_PATH: -// fchownat(fd, "", AT_EMPTY_PATH, ...), instead of chown(fullpath, ...) -// * Creation operations must use (fd + name): -// mkdirat(fd, name, ...), instead of mkdir(fullpath, ...) +// - Local operations must use AT_EMPTY_PATH: +// fchownat(fd, "", AT_EMPTY_PATH, ...), instead of chown(fullpath, ...) +// - Creation operations must use (fd + name): +// mkdirat(fd, name, ...), instead of mkdir(fullpath, ...) // // Apart from being faster, it also adds another layer of defense against // symlink attacks (note that O_NOFOLLOW applies only to the last element in diff --git a/runsc/sandbox/network.go b/runsc/sandbox/network.go index 03c5de2c6..4d8dc6be8 100644 --- a/runsc/sandbox/network.go +++ b/runsc/sandbox/network.go @@ -48,7 +48,8 @@ import ( // loopback interface only. // // Run the following container to test it: -// docker run -di --runtime=runsc -p 8080:80 -v $PWD:/usr/local/apache2/htdocs/ httpd:2.4 +// +// docker run -di --runtime=runsc -p 8080:80 -v $PWD:/usr/local/apache2/htdocs/ httpd:2.4 func setupNetwork(conn *urpc.Client, pid int, conf *config.Config) error { log.Infof("Setting up network") @@ -433,7 +434,8 @@ func routesForIface(iface net.Interface) ([]boot.Route, *boot.Route, *boot.Route } // removeAddress removes IP address from network device. It's equivalent to: -// ip addr del dev +// +// ip addr del dev func removeAddress(source netlink.Link, ipAndMask string) error { addr, err := netlink.ParseAddr(ipAndMask) if err != nil { diff --git a/runsc/specutils/safemount_test/safemount_runner.go b/runsc/specutils/safemount_test/safemount_runner.go index b23193033..91d81b309 100644 --- a/runsc/specutils/safemount_test/safemount_runner.go +++ b/runsc/specutils/safemount_test/safemount_runner.go @@ -86,10 +86,11 @@ func main() { } // runTest runs testfunc with the following directory structure: -// tempdir/ -// subdir/ -// subdir2/ -// symlink --> ./subdir2 +// +// tempdir/ +// subdir/ +// subdir2/ +// symlink --> ./subdir2 func runTest(tempdir string, testfunc func() error) error { // Create tempdir/subdir/. dirPath := filepath.Join(tempdir, "subdir") diff --git a/test/benchmarks/fs/bazel_test.go b/test/benchmarks/fs/bazel_test.go index 797b1952d..f02c40cf8 100644 --- a/test/benchmarks/fs/bazel_test.go +++ b/test/benchmarks/fs/bazel_test.go @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, diff --git a/test/benchmarks/fs/fio_test.go b/test/benchmarks/fs/fio_test.go index 1482466f4..44546e6bc 100644 --- a/test/benchmarks/fs/fio_test.go +++ b/test/benchmarks/fs/fio_test.go @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, diff --git a/test/benchmarks/media/ffmpeg_test.go b/test/benchmarks/media/ffmpeg_test.go index 1b99a319a..fd972b67e 100644 --- a/test/benchmarks/media/ffmpeg_test.go +++ b/test/benchmarks/media/ffmpeg_test.go @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, diff --git a/test/benchmarks/ml/tensorflow_test.go b/test/benchmarks/ml/tensorflow_test.go index 7068cb0fa..6c328090f 100644 --- a/test/benchmarks/ml/tensorflow_test.go +++ b/test/benchmarks/ml/tensorflow_test.go @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, diff --git a/test/benchmarks/network/httpd_test.go b/test/benchmarks/network/httpd_test.go index 629127250..54a72542a 100644 --- a/test/benchmarks/network/httpd_test.go +++ b/test/benchmarks/network/httpd_test.go @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, diff --git a/test/benchmarks/network/iperf_test.go b/test/benchmarks/network/iperf_test.go index 6ac7717b1..41808dc47 100644 --- a/test/benchmarks/network/iperf_test.go +++ b/test/benchmarks/network/iperf_test.go @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, diff --git a/test/benchmarks/network/nginx_test.go b/test/benchmarks/network/nginx_test.go index 74f3578fc..801946a79 100644 --- a/test/benchmarks/network/nginx_test.go +++ b/test/benchmarks/network/nginx_test.go @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, diff --git a/test/benchmarks/network/node_test.go b/test/benchmarks/network/node_test.go index a1fc82f95..bb59da048 100644 --- a/test/benchmarks/network/node_test.go +++ b/test/benchmarks/network/node_test.go @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, diff --git a/test/benchmarks/network/ruby_test.go b/test/benchmarks/network/ruby_test.go index b7ec16e0a..5632ae291 100644 --- a/test/benchmarks/network/ruby_test.go +++ b/test/benchmarks/network/ruby_test.go @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, diff --git a/test/benchmarks/tools/iperf_test.go b/test/benchmarks/tools/iperf_test.go index 03bb30d05..385f56953 100644 --- a/test/benchmarks/tools/iperf_test.go +++ b/test/benchmarks/tools/iperf_test.go @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, diff --git a/test/iptables/iptables_test.go b/test/iptables/iptables_test.go index 04d112134..cae26fe82 100644 --- a/test/iptables/iptables_test.go +++ b/test/iptables/iptables_test.go @@ -28,11 +28,11 @@ import ( ) // singleTest runs a TestCase. Each test follows a pattern: -// - Create a container. -// - Get the container's IP. -// - Send the container our IP. -// - Start a new goroutine running the local action of the test. -// - Wait for both the container and local actions to finish. +// - Create a container. +// - Get the container's IP. +// - Send the container our IP. +// - Start a new goroutine running the local action of the test. +// - Wait for both the container and local actions to finish. // // Container output is logged to $TEST_UNDECLARED_OUTPUTS_DIR if it exists, or // to stderr. diff --git a/test/packetimpact/tests/generic_dgram_socket_send_recv_test.go b/test/packetimpact/tests/generic_dgram_socket_send_recv_test.go index 1bcac3c79..1eac41848 100644 --- a/test/packetimpact/tests/generic_dgram_socket_send_recv_test.go +++ b/test/packetimpact/tests/generic_dgram_socket_send_recv_test.go @@ -361,10 +361,10 @@ type icmpV6TestEnv struct { // icmpV6Test and icmpV4Test look substantially similar at first look, but have // enough subtle differences in setup and test expectations to discourage // refactoring: -// - Different IP layers -// - Different testbench.Connections -// - Different UNIX domain and proto arguments -// - Different expectPacket and wantErrno for send and receive +// - Different IP layers +// - Different testbench.Connections +// - Different UNIX domain and proto arguments +// - Different expectPacket and wantErrno for send and receive type icmpV6Test struct{} func (test *icmpV6Test) setup(t *testing.T, dut testbench.DUT, bindTo, sendTo net.IP, bindToDevice bool) icmpV6TestEnv { diff --git a/test/packetimpact/tests/tcp_acceptable_ack_syn_rcvd_test.go b/test/packetimpact/tests/tcp_acceptable_ack_syn_rcvd_test.go index d603d47fe..e1d350d4d 100644 --- a/test/packetimpact/tests/tcp_acceptable_ack_syn_rcvd_test.go +++ b/test/packetimpact/tests/tcp_acceptable_ack_syn_rcvd_test.go @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, diff --git a/test/root/crictl_test.go b/test/root/crictl_test.go index 0378d851e..dbe5e9e80 100644 --- a/test/root/crictl_test.go +++ b/test/root/crictl_test.go @@ -306,9 +306,9 @@ disabled_plugins = ["io.containerd.internal.v1.restart"] ` // setup sets up before a test. Specifically it: -// * Creates directories and a socket for containerd to utilize. -// * Runs containerd and waits for it to reach a "ready" state for testing. -// * Returns a cleanup function that should be called at the end of the test. +// - Creates directories and a socket for containerd to utilize. +// - Runs containerd and waits for it to reach a "ready" state for testing. +// - Returns a cleanup function that should be called at the end of the test. func setup(t *testing.T) (*criutil.Crictl, func(), error) { // Create temporary containerd root and state directories, and a socket // via which crictl and containerd communicate. diff --git a/test/root/root.go b/test/root/root.go index 441fa5e2e..d2c3ada85 100644 --- a/test/root/root.go +++ b/test/root/root.go @@ -17,5 +17,5 @@ // docker, containerd, and crictl installed. To run these tests from the // project root directory: // -// make root-tests +// make root-tests package root diff --git a/test/uds/uds.go b/test/uds/uds.go index 028e366b8..41b742533 100644 --- a/test/uds/uds.go +++ b/test/uds/uds.go @@ -189,16 +189,16 @@ type socketCreator func(path string, proto int) (cleanup func(), err error) // CreateSocketTree creates a local tree of unix domain sockets for use in // testing: -// * /stream/echo -// * /stream/nonlistening -// * /seqpacket/echo -// * /seqpacket/nonlistening -// * /dgram/null +// - /stream/echo +// - /stream/nonlistening +// - /seqpacket/echo +// - /seqpacket/nonlistening +// - /dgram/null // // Additionally, it will attempt to connect to sockets at the following // locations, and turn into an echo server once connected: -// * /stream/created-in-sandbox -// * /seqpacket/created-in-sandbox +// - /stream/created-in-sandbox +// - /seqpacket/created-in-sandbox func CreateSocketTree(baseDir string) (dir string, cleanup func(), err error) { dir, err = ioutil.TempDir(baseDir, "sockets") if err != nil { diff --git a/tools/checkescape/checkescape.go b/tools/checkescape/checkescape.go index 397136739..daaf7b835 100644 --- a/tools/checkescape/checkescape.go +++ b/tools/checkescape/checkescape.go @@ -24,11 +24,11 @@ // The different types of escapes are as follows, with the category in // parentheses: // -// heap: A direct allocation is made on the heap (hard). -// builtin: A call is made to a built-in allocation function (hard). -// stack: A stack split as part of a function preamble (soft). -// interface: A call is made via an interface which *may* escape (soft). -// dynamic: A dynamic function is dispatched which *may* escape (soft). +// heap: A direct allocation is made on the heap (hard). +// builtin: A call is made to a built-in allocation function (hard). +// stack: A stack split as part of a function preamble (soft). +// interface: A call is made via an interface which *may* escape (soft). +// dynamic: A dynamic function is dispatched which *may* escape (soft). // // To the use the package, annotate a function-level comment with either the // line "// +checkescape" or "// +checkescape:OPTION[,OPTION]". In the second diff --git a/tools/checkescape/test1/test1.go b/tools/checkescape/test1/test1.go index f46eba39b..a2559c300 100644 --- a/tools/checkescape/test1/test1.go +++ b/tools/checkescape/test1/test1.go @@ -31,6 +31,7 @@ type Type struct { } // Foo implements Interface.Foo. +// //go:nosplit func (t Type) Foo() { fmt.Printf("%v", t) // Never executed. @@ -38,6 +39,7 @@ func (t Type) Foo() { // InterfaceFunction is passed an interface argument. // +checkescape:all,hard +// //go:nosplit func InterfaceFunction(i Interface) { // Do nothing; exported for tests. @@ -45,12 +47,14 @@ func InterfaceFunction(i Interface) { // TypeFunction is passed a concrete pointer argument. // +checkesacape:all,hard +// //go:nosplit func TypeFunction(t *Type) { } // BuiltinMap creates a new map. // +mustescape:local,builtin +// //go:noinline //go:nosplit func BuiltinMap(x int) map[string]bool { @@ -58,6 +62,7 @@ func BuiltinMap(x int) map[string]bool { } // +mustescape:builtin +// //go:noinline //go:nosplit func builtinMapRec(x int) map[string]bool { @@ -66,6 +71,7 @@ func builtinMapRec(x int) map[string]bool { // BuiltinClosure returns a closure around x. // +mustescape:local,builtin +// //go:noinline //go:nosplit func BuiltinClosure(x int) func() { @@ -75,6 +81,7 @@ func BuiltinClosure(x int) func() { } // +mustescape:builtin +// //go:noinline //go:nosplit func builtinClosureRec(x int) func() { @@ -83,6 +90,7 @@ func builtinClosureRec(x int) func() { // BuiltinMakeSlice makes a new slice. // +mustescape:local,builtin +// //go:noinline //go:nosplit func BuiltinMakeSlice(x int) []byte { @@ -90,6 +98,7 @@ func BuiltinMakeSlice(x int) []byte { } // +mustescape:builtin +// //go:noinline //go:nosplit func builtinMakeSliceRec(x int) []byte { @@ -98,6 +107,7 @@ func builtinMakeSliceRec(x int) []byte { // BuiltinAppend calls append on a slice. // +mustescape:local,builtin +// //go:noinline //go:nosplit func BuiltinAppend(x []byte) []byte { @@ -105,6 +115,7 @@ func BuiltinAppend(x []byte) []byte { } // +mustescape:builtin +// //go:noinline //go:nosplit func builtinAppendRec() []byte { @@ -113,6 +124,7 @@ func builtinAppendRec() []byte { // BuiltinChan makes a channel. // +mustescape:local,builtin +// //go:noinline //go:nosplit func BuiltinChan() chan int { @@ -120,6 +132,7 @@ func BuiltinChan() chan int { } // +mustescape:builtin +// //go:noinline //go:nosplit func builtinChanRec() chan int { @@ -128,6 +141,7 @@ func builtinChanRec() chan int { // Heap performs an explicit heap allocation. // +mustescape:local,heap +// //go:noinline //go:nosplit func Heap() *Type { @@ -136,6 +150,7 @@ func Heap() *Type { } // +mustescape:heap +// //go:noinline //go:nosplit func heapRec() *Type { @@ -144,6 +159,7 @@ func heapRec() *Type { // Dispatch dispatches via an interface. // +mustescape:local,interface +// //go:noinline //go:nosplit func Dispatch(i Interface) { @@ -151,6 +167,7 @@ func Dispatch(i Interface) { } // +mustescape:interface +// //go:noinline //go:nosplit func dispatchRec(i Interface) { @@ -159,6 +176,7 @@ func dispatchRec(i Interface) { // Dynamic invokes a dynamic function. // +mustescape:local,dynamic +// //go:noinline //go:nosplit func Dynamic(f func()) { @@ -166,6 +184,7 @@ func Dynamic(f func()) { } // +mustescape:dynamic +// //go:noinline //go:nosplit func dynamicRec(f func()) { @@ -179,12 +198,14 @@ func internalFunc() { // Split includes a guaranteed stack split. // +mustescape:local,stack +// //go:noinline func Split() { internalFunc() } // +mustescape:stack +// //go:noinline //go:nosplit func splitRec() { diff --git a/tools/checkescape/test2/test2.go b/tools/checkescape/test2/test2.go index 067d5a1f4..e2627b5f6 100644 --- a/tools/checkescape/test2/test2.go +++ b/tools/checkescape/test2/test2.go @@ -20,6 +20,7 @@ import ( ) // +checkescape:all +// //go:nosplit func interfaceFunctionCrossPkg() { var i test1.Interface @@ -27,6 +28,7 @@ func interfaceFunctionCrossPkg() { } // +checkesacape:all +// //go:nosplit func typeFunctionCrossPkg() { var t test1.Type @@ -34,54 +36,63 @@ func typeFunctionCrossPkg() { } // +mustescape:builtin +// //go:noinline func builtinMapCrossPkg(x int) map[string]bool { return test1.BuiltinMap(x) } // +mustescape:builtin +// //go:noinline func builtinClosureCrossPkg(x int) func() { return test1.BuiltinClosure(x) } // +mustescape:builtin +// //go:noinline func builtinMakeSliceCrossPkg(x int) []byte { return test1.BuiltinMakeSlice(x) } // +mustescape:builtin +// //go:noinline func builtinAppendCrossPkg() []byte { return test1.BuiltinAppend(nil) } // +mustescape:builtin +// //go:noinline func builtinChanCrossPkg() chan int { return test1.BuiltinChan() } // +mustescape:heap +// //go:noinline func heapCrossPkg() *test1.Type { return test1.Heap() } // +mustescape:interface +// //go:noinline func dispatchCrossPkg(i test1.Interface) { test1.Dispatch(i) } // +mustescape:dynamic +// //go:noinline func dynamicCrossPkg(f func()) { test1.Dynamic(f) } // +mustescape:stack +// //go:noinline //go:nosplit func splitCrosssPkt() { diff --git a/tools/go_generics/main.go b/tools/go_generics/main.go index 32c9accc3..60494067c 100644 --- a/tools/go_generics/main.go +++ b/tools/go_generics/main.go @@ -15,44 +15,44 @@ // go_generics reads a Go source file and writes a new version of that file with // a few transformations applied to each. Namely: // -// 1. Global types can be explicitly renamed with the -t option. For example, -// if -t=A=B is passed in, all references to A will be replaced with -// references to B; a function declaration like: +// 1. Global types can be explicitly renamed with the -t option. For example, +// if -t=A=B is passed in, all references to A will be replaced with +// references to B; a function declaration like: // -// func f(arg *A) +// func f(arg *A) // -// would be renamed to: +// would be renamed to: // -// func f(arg *B) +// func f(arg *B) // -// 2. Global type definitions and their method sets will be removed when they're -// being renamed with -t. For example, if -t=A=B is passed in, the following -// definition and methods that existed in the input file wouldn't exist at -// all in the output file: +// 2. Global type definitions and their method sets will be removed when they're +// being renamed with -t. For example, if -t=A=B is passed in, the following +// definition and methods that existed in the input file wouldn't exist at +// all in the output file: // -// type A struct{} +// type A struct{} // -// func (*A) f() {} +// func (*A) f() {} // -// 3. All global types, variables, constants and functions (not methods) are -// prefixed and suffixed based on the option -prefix and -suffix arguments. -// For example, if -suffix=A is passed in, the following globals: +// 3. All global types, variables, constants and functions (not methods) are +// prefixed and suffixed based on the option -prefix and -suffix arguments. +// For example, if -suffix=A is passed in, the following globals: // -// func f() -// type t struct{} +// func f() +// type t struct{} // -// would be renamed to: +// would be renamed to: // -// func fA() -// type tA struct{} +// func fA() +// type tA struct{} // -// Some special tags are also modified. For example: +// Some special tags are also modified. For example: // -// "state:.(t)" +// "state:.(t)" // -// would become: +// would become: // -// "state:.(tA)" +// "state:.(tA)" // // 4. The package is renamed to the value via the -p argument. // 5. Value of constants can be modified with -c argument. @@ -63,21 +63,21 @@ // // var b = 100 // -// func f() { -// g(b) -// b := 0 -// g(b) -// } +// func f() { +// g(b) +// b := 0 +// g(b) +// } // // Would be replaced with: // // var bA = 100 // -// func f() { -// g(bA) -// b := 0 -// g(b) -// } +// func f() { +// g(bA) +// b := 0 +// g(b) +// } // // Note that the second call to g() kept "b" as an argument because it refers to // the local variable "b". diff --git a/tools/go_marshal/gomarshal/util.go b/tools/go_marshal/gomarshal/util.go index 6a42691cd..69dbae320 100644 --- a/tools/go_marshal/gomarshal/util.go +++ b/tools/go_marshal/gomarshal/util.go @@ -167,11 +167,14 @@ func debugfAt(p token.Position, f string, a ...interface{}) { // buffer. emit can be invoked in one of two ways: // // (1) emit("some string") -// When emit is called with a single string argument, it is simply copied to -// the output buffer without any further formatting. +// +// When emit is called with a single string argument, it is simply copied to +// the output buffer without any further formatting. +// // (2) emit(fmtString, args...) -// emit can also be invoked in a similar fashion to *Printf() functions, -// where the first argument is a format string. +// +// emit can also be invoked in a similar fashion to *Printf() functions, +// where the first argument is a format string. // // Calling emit with a single argument that is not a string will result in a // panic, as the caller's intent is ambiguous. @@ -357,24 +360,24 @@ func (i *importStmt) equivalent(other *importStmt) bool { // // An importTable representing them would look like this: // -// importTable { -// is: map[string][]*importStmt { -// "sync": []*importStmt{ -// importStmt{name:"sync", path:"sync", aliased:false} -// importStmt{name:"sync", path:"pkg/sync", aliased:false} -// }, -// "kernel": []*importStmt{importStmt{ -// name: "kernel", -// path: "pkg/sentry/kernel", -// aliased: false -// }}, -// "ktime": []*importStmt{importStmt{ -// name: "ktime", -// path: "pkg/sentry/kernel/time", -// aliased: true, -// }}, -// } -// } +// importTable { +// is: map[string][]*importStmt { +// "sync": []*importStmt{ +// importStmt{name:"sync", path:"sync", aliased:false} +// importStmt{name:"sync", path:"pkg/sync", aliased:false} +// }, +// "kernel": []*importStmt{importStmt{ +// name: "kernel", +// path: "pkg/sentry/kernel", +// aliased: false +// }}, +// "ktime": []*importStmt{importStmt{ +// name: "ktime", +// path: "pkg/sentry/kernel/time", +// aliased: true, +// }}, +// } +// } // // Note that the local name "sync" is assigned to two different import // statements. This is possible if the import statements are from different diff --git a/tools/go_marshal/test/escape/escape.go b/tools/go_marshal/test/escape/escape.go index 23ec6e654..bfbbda028 100644 --- a/tools/go_marshal/test/escape/escape.go +++ b/tools/go_marshal/test/escape/escape.go @@ -50,6 +50,7 @@ func (t *dummyCopyContext) MarshalUnsafe(addr hostarch.Addr, marshallable marsha } // +checkescape:hard +// //go:nosplit func doCopyIn(t *dummyCopyContext) { var stat test.Stat @@ -57,6 +58,7 @@ func doCopyIn(t *dummyCopyContext) { } // +checkescape:hard +// //go:nosplit func doCopyOut(t *dummyCopyContext) { var stat test.Stat @@ -65,6 +67,7 @@ func doCopyOut(t *dummyCopyContext) { // +mustescape:builtin // +mustescape:stack +// //go:nosplit func doMarshalBytesDirect(t *dummyCopyContext) { var stat test.Stat @@ -75,6 +78,7 @@ func doMarshalBytesDirect(t *dummyCopyContext) { // +mustescape:builtin // +mustescape:stack +// //go:nosplit func doMarshalUnsafeDirect(t *dummyCopyContext) { var stat test.Stat @@ -85,6 +89,7 @@ func doMarshalUnsafeDirect(t *dummyCopyContext) { // +mustescape:local,heap // +mustescape:stack +// //go:nosplit func doMarshalBytesViaMarshallable(t *dummyCopyContext) { var stat test.Stat @@ -93,6 +98,7 @@ func doMarshalBytesViaMarshallable(t *dummyCopyContext) { // +mustescape:local,heap // +mustescape:stack +// //go:nosplit func doMarshalUnsafeViaMarshallable(t *dummyCopyContext) { var stat test.Stat diff --git a/tools/parsers/go_parser.go b/tools/parsers/go_parser.go index 57e538149..cef869416 100644 --- a/tools/parsers/go_parser.go +++ b/tools/parsers/go_parser.go @@ -49,17 +49,18 @@ func ParseOutput(output string, name string, official bool) (*bigquery.Suite, er // Example: "BenchmarkRuby/server_threads.1-6 1 1397875880 ns/op 140 requests_per_second.QPS" // // This function will return the following benchmark: -// *bigquery.Benchmark{ -// Name: BenchmarkRuby -// []*bigquery.Condition{ -// {Name: GOMAXPROCS, 6} -// {Name: server_threads, 1} -// } -// []*bigquery.Metric{ -// {Name: ns/op, Unit: ns/op, Sample: 1397875880} -// {Name: requests_per_second, Unit: QPS, Sample: 140 } -// } -//} +// +// *bigquery.Benchmark{ +// Name: BenchmarkRuby +// []*bigquery.Condition{ +// {Name: GOMAXPROCS, 6} +// {Name: server_threads, 1} +// } +// []*bigquery.Metric{ +// {Name: ns/op, Unit: ns/op, Sample: 1397875880} +// {Name: requests_per_second, Unit: QPS, Sample: 140 } +// } +// } func parseLine(line string) (*bigquery.Benchmark, error) { fields := strings.Fields(line) diff --git a/tools/verity/measure_tool_unsafe.go b/tools/verity/measure_tool_unsafe.go index d4079be9e..d1864ed54 100644 --- a/tools/verity/measure_tool_unsafe.go +++ b/tools/verity/measure_tool_unsafe.go @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS,