mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Merge pull request #3875 from btw616:fix/issue-3874
PiperOrigin-RevId: 334428344
This commit is contained in:
@@ -69,8 +69,8 @@ go_template_instance(
|
||||
prefix = "socket",
|
||||
template = "//pkg/ilist:generic_list",
|
||||
types = {
|
||||
"Element": "*SocketEntry",
|
||||
"Linker": "*SocketEntry",
|
||||
"Element": "*SocketRecordVFS1",
|
||||
"Linker": "*SocketRecordVFS1",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
+59
-24
@@ -220,13 +220,18 @@ type Kernel struct {
|
||||
// danglingEndpoints is used to save / restore tcpip.DanglingEndpoints.
|
||||
danglingEndpoints struct{} `state:".([]tcpip.Endpoint)"`
|
||||
|
||||
// sockets is the list of all network sockets the system. Protected by
|
||||
// extMu.
|
||||
// sockets is the list of all network sockets in the system.
|
||||
// Protected by extMu.
|
||||
// TODO(gvisor.dev/issue/1624): Only used by VFS1.
|
||||
sockets socketList
|
||||
|
||||
// nextSocketEntry is the next entry number to use in sockets. Protected
|
||||
// socketsVFS2 records all network sockets in the system. Protected by
|
||||
// extMu.
|
||||
socketsVFS2 map[*vfs.FileDescription]*SocketRecord
|
||||
|
||||
// nextSocketRecord is the next entry number to use in sockets. Protected
|
||||
// by extMu.
|
||||
nextSocketEntry uint64
|
||||
nextSocketRecord uint64
|
||||
|
||||
// deviceRegistry is used to save/restore device.SimpleDevices.
|
||||
deviceRegistry struct{} `state:".(*device.Registry)"`
|
||||
@@ -414,6 +419,8 @@ func (k *Kernel) Init(args InitKernelArgs) error {
|
||||
return fmt.Errorf("failed to create sockfs mount: %v", err)
|
||||
}
|
||||
k.socketMount = socketMount
|
||||
|
||||
k.socketsVFS2 = make(map[*vfs.FileDescription]*SocketRecord)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -1512,20 +1519,27 @@ func (k *Kernel) SupervisorContext() context.Context {
|
||||
}
|
||||
}
|
||||
|
||||
// SocketEntry represents a socket recorded in Kernel.sockets. It implements
|
||||
// SocketRecord represents a socket recorded in Kernel.socketsVFS2.
|
||||
//
|
||||
// +stateify savable
|
||||
type SocketRecord struct {
|
||||
k *Kernel
|
||||
Sock *refs.WeakRef // TODO(gvisor.dev/issue/1624): Only used by VFS1.
|
||||
SockVFS2 *vfs.FileDescription // Only used by VFS2.
|
||||
ID uint64 // Socket table entry number.
|
||||
}
|
||||
|
||||
// SocketRecordVFS1 represents a socket recorded in Kernel.sockets. It implements
|
||||
// refs.WeakRefUser for sockets stored in the socket table.
|
||||
//
|
||||
// +stateify savable
|
||||
type SocketEntry struct {
|
||||
type SocketRecordVFS1 struct {
|
||||
socketEntry
|
||||
k *Kernel
|
||||
Sock *refs.WeakRef
|
||||
SockVFS2 *vfs.FileDescription
|
||||
ID uint64 // Socket table entry number.
|
||||
SocketRecord
|
||||
}
|
||||
|
||||
// WeakRefGone implements refs.WeakRefUser.WeakRefGone.
|
||||
func (s *SocketEntry) WeakRefGone(context.Context) {
|
||||
func (s *SocketRecordVFS1) WeakRefGone(context.Context) {
|
||||
s.k.extMu.Lock()
|
||||
s.k.sockets.Remove(s)
|
||||
s.k.extMu.Unlock()
|
||||
@@ -1536,9 +1550,14 @@ func (s *SocketEntry) WeakRefGone(context.Context) {
|
||||
// Precondition: Caller must hold a reference to sock.
|
||||
func (k *Kernel) RecordSocket(sock *fs.File) {
|
||||
k.extMu.Lock()
|
||||
id := k.nextSocketEntry
|
||||
k.nextSocketEntry++
|
||||
s := &SocketEntry{k: k, ID: id}
|
||||
id := k.nextSocketRecord
|
||||
k.nextSocketRecord++
|
||||
s := &SocketRecordVFS1{
|
||||
SocketRecord: SocketRecord{
|
||||
k: k,
|
||||
ID: id,
|
||||
},
|
||||
}
|
||||
s.Sock = refs.NewWeakRef(sock, s)
|
||||
k.sockets.PushBack(s)
|
||||
k.extMu.Unlock()
|
||||
@@ -1550,29 +1569,45 @@ func (k *Kernel) RecordSocket(sock *fs.File) {
|
||||
// Precondition: Caller must hold a reference to sock.
|
||||
//
|
||||
// Note that the socket table will not hold a reference on the
|
||||
// vfs.FileDescription, because we do not support weak refs on VFS2 files.
|
||||
// vfs.FileDescription.
|
||||
func (k *Kernel) RecordSocketVFS2(sock *vfs.FileDescription) {
|
||||
k.extMu.Lock()
|
||||
id := k.nextSocketEntry
|
||||
k.nextSocketEntry++
|
||||
s := &SocketEntry{
|
||||
if _, ok := k.socketsVFS2[sock]; ok {
|
||||
panic(fmt.Sprintf("Socket %p added twice", sock))
|
||||
}
|
||||
id := k.nextSocketRecord
|
||||
k.nextSocketRecord++
|
||||
s := &SocketRecord{
|
||||
k: k,
|
||||
ID: id,
|
||||
SockVFS2: sock,
|
||||
}
|
||||
k.sockets.PushBack(s)
|
||||
k.socketsVFS2[sock] = s
|
||||
k.extMu.Unlock()
|
||||
}
|
||||
|
||||
// DeleteSocketVFS2 removes a VFS2 socket from the system-wide socket table.
|
||||
func (k *Kernel) DeleteSocketVFS2(sock *vfs.FileDescription) {
|
||||
k.extMu.Lock()
|
||||
delete(k.socketsVFS2, sock)
|
||||
k.extMu.Unlock()
|
||||
}
|
||||
|
||||
// ListSockets returns a snapshot of all sockets.
|
||||
//
|
||||
// Callers of ListSockets() in VFS2 should use SocketEntry.SockVFS2.TryIncRef()
|
||||
// Callers of ListSockets() in VFS2 should use SocketRecord.SockVFS2.TryIncRef()
|
||||
// to get a reference on a socket in the table.
|
||||
func (k *Kernel) ListSockets() []*SocketEntry {
|
||||
func (k *Kernel) ListSockets() []*SocketRecord {
|
||||
k.extMu.Lock()
|
||||
var socks []*SocketEntry
|
||||
for s := k.sockets.Front(); s != nil; s = s.Next() {
|
||||
socks = append(socks, s)
|
||||
var socks []*SocketRecord
|
||||
if VFS2Enabled {
|
||||
for _, s := range k.socketsVFS2 {
|
||||
socks = append(socks, s)
|
||||
}
|
||||
} else {
|
||||
for s := k.sockets.Front(); s != nil; s = s.Next() {
|
||||
socks = append(socks, &s.SocketRecord)
|
||||
}
|
||||
}
|
||||
k.extMu.Unlock()
|
||||
return socks
|
||||
|
||||
@@ -78,6 +78,13 @@ func newVFS2Socket(t *kernel.Task, family int, stype linux.SockType, protocol in
|
||||
return vfsfd, nil
|
||||
}
|
||||
|
||||
// Release implements vfs.FileDescriptionImpl.Release.
|
||||
func (s *socketVFS2) Release(ctx context.Context) {
|
||||
t := kernel.TaskFromContext(ctx)
|
||||
t.Kernel().DeleteSocketVFS2(&s.vfsfd)
|
||||
s.socketOpsCommon.Release(ctx)
|
||||
}
|
||||
|
||||
// Readiness implements waiter.Waitable.Readiness.
|
||||
func (s *socketVFS2) Readiness(mask waiter.EventMask) waiter.EventMask {
|
||||
return s.socketOpsCommon.Readiness(mask)
|
||||
|
||||
@@ -82,6 +82,13 @@ func NewVFS2(t *kernel.Task, skType linux.SockType, protocol Protocol) (*SocketV
|
||||
return fd, nil
|
||||
}
|
||||
|
||||
// Release implements vfs.FileDescriptionImpl.Release.
|
||||
func (s *SocketVFS2) Release(ctx context.Context) {
|
||||
t := kernel.TaskFromContext(ctx)
|
||||
t.Kernel().DeleteSocketVFS2(&s.vfsfd)
|
||||
s.socketOpsCommon.Release(ctx)
|
||||
}
|
||||
|
||||
// Readiness implements waiter.Waitable.Readiness.
|
||||
func (s *SocketVFS2) Readiness(mask waiter.EventMask) waiter.EventMask {
|
||||
return s.socketOpsCommon.Readiness(mask)
|
||||
|
||||
@@ -79,6 +79,13 @@ func NewVFS2(t *kernel.Task, family int, skType linux.SockType, protocol int, qu
|
||||
return vfsfd, nil
|
||||
}
|
||||
|
||||
// Release implements vfs.FileDescriptionImpl.Release.
|
||||
func (s *SocketVFS2) Release(ctx context.Context) {
|
||||
t := kernel.TaskFromContext(ctx)
|
||||
t.Kernel().DeleteSocketVFS2(&s.vfsfd)
|
||||
s.socketOpsCommon.Release(ctx)
|
||||
}
|
||||
|
||||
// Readiness implements waiter.Waitable.Readiness.
|
||||
func (s *SocketVFS2) Readiness(mask waiter.EventMask) waiter.EventMask {
|
||||
return s.socketOpsCommon.Readiness(mask)
|
||||
|
||||
@@ -7,10 +7,21 @@ go_template_instance(
|
||||
name = "socket_refs",
|
||||
out = "socket_refs.go",
|
||||
package = "unix",
|
||||
prefix = "socketOpsCommon",
|
||||
prefix = "socketOperations",
|
||||
template = "//pkg/refs_vfs2:refs_template",
|
||||
types = {
|
||||
"T": "socketOpsCommon",
|
||||
"T": "SocketOperations",
|
||||
},
|
||||
)
|
||||
|
||||
go_template_instance(
|
||||
name = "socket_vfs2_refs",
|
||||
out = "socket_vfs2_refs.go",
|
||||
package = "unix",
|
||||
prefix = "socketVFS2",
|
||||
template = "//pkg/refs_vfs2:refs_template",
|
||||
types = {
|
||||
"T": "SocketVFS2",
|
||||
},
|
||||
)
|
||||
|
||||
@@ -20,6 +31,7 @@ go_library(
|
||||
"device.go",
|
||||
"io.go",
|
||||
"socket_refs.go",
|
||||
"socket_vfs2_refs.go",
|
||||
"unix.go",
|
||||
"unix_vfs2.go",
|
||||
],
|
||||
|
||||
@@ -55,6 +55,7 @@ type SocketOperations struct {
|
||||
fsutil.FileNoopFlush `state:"nosave"`
|
||||
fsutil.FileUseInodeUnstableAttr `state:"nosave"`
|
||||
|
||||
socketOperationsRefs
|
||||
socketOpsCommon
|
||||
}
|
||||
|
||||
@@ -84,11 +85,27 @@ func NewWithDirent(ctx context.Context, d *fs.Dirent, ep transport.Endpoint, sty
|
||||
return fs.NewFile(ctx, d, flags, &s)
|
||||
}
|
||||
|
||||
// DecRef implements RefCounter.DecRef.
|
||||
func (s *SocketOperations) DecRef(ctx context.Context) {
|
||||
s.socketOperationsRefs.DecRef(func() {
|
||||
s.ep.Close(ctx)
|
||||
if s.abstractNamespace != nil {
|
||||
s.abstractNamespace.Remove(s.abstractName, s)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Release implemements fs.FileOperations.Release.
|
||||
func (s *SocketOperations) Release(ctx context.Context) {
|
||||
// Release only decrements a reference on s because s may be referenced in
|
||||
// the abstract socket namespace.
|
||||
s.DecRef(ctx)
|
||||
}
|
||||
|
||||
// socketOpsCommon contains the socket operations common to VFS1 and VFS2.
|
||||
//
|
||||
// +stateify savable
|
||||
type socketOpsCommon struct {
|
||||
socketOpsCommonRefs
|
||||
socket.SendReceiveTimeout
|
||||
|
||||
ep transport.Endpoint
|
||||
@@ -101,23 +118,6 @@ type socketOpsCommon struct {
|
||||
abstractNamespace *kernel.AbstractSocketNamespace
|
||||
}
|
||||
|
||||
// DecRef implements RefCounter.DecRef.
|
||||
func (s *socketOpsCommon) DecRef(ctx context.Context) {
|
||||
s.socketOpsCommonRefs.DecRef(func() {
|
||||
s.ep.Close(ctx)
|
||||
if s.abstractNamespace != nil {
|
||||
s.abstractNamespace.Remove(s.abstractName, s)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Release implemements fs.FileOperations.Release.
|
||||
func (s *socketOpsCommon) Release(ctx context.Context) {
|
||||
// Release only decrements a reference on s because s may be referenced in
|
||||
// the abstract socket namespace.
|
||||
s.DecRef(ctx)
|
||||
}
|
||||
|
||||
func (s *socketOpsCommon) isPacket() bool {
|
||||
switch s.stype {
|
||||
case linux.SOCK_DGRAM, linux.SOCK_SEQPACKET:
|
||||
|
||||
@@ -45,6 +45,7 @@ type SocketVFS2 struct {
|
||||
vfs.DentryMetadataFileDescriptionImpl
|
||||
vfs.LockFD
|
||||
|
||||
socketVFS2Refs
|
||||
socketOpsCommon
|
||||
}
|
||||
|
||||
@@ -91,6 +92,25 @@ func NewFileDescription(ep transport.Endpoint, stype linux.SockType, flags uint3
|
||||
return vfsfd, nil
|
||||
}
|
||||
|
||||
// DecRef implements RefCounter.DecRef.
|
||||
func (s *SocketVFS2) DecRef(ctx context.Context) {
|
||||
s.socketVFS2Refs.DecRef(func() {
|
||||
t := kernel.TaskFromContext(ctx)
|
||||
t.Kernel().DeleteSocketVFS2(&s.vfsfd)
|
||||
s.ep.Close(ctx)
|
||||
if s.abstractNamespace != nil {
|
||||
s.abstractNamespace.Remove(s.abstractName, s)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Release implements vfs.FileDescriptionImpl.Release.
|
||||
func (s *SocketVFS2) Release(ctx context.Context) {
|
||||
// Release only decrements a reference on s because s may be referenced in
|
||||
// the abstract socket namespace.
|
||||
s.DecRef(ctx)
|
||||
}
|
||||
|
||||
// GetSockOpt implements the linux syscall getsockopt(2) for sockets backed by
|
||||
// a transport.Endpoint.
|
||||
func (s *SocketVFS2) GetSockOpt(t *kernel.Task, level, name int, outPtr usermem.Addr, outLen int) (marshal.Marshallable, *syserr.Error) {
|
||||
|
||||
Reference in New Issue
Block a user