From ce4f4283badb6b07baf9f8e6d99e7a5fd15c92db Mon Sep 17 00:00:00 2001 From: Ayush Ranjan Date: Fri, 5 Nov 2021 10:40:53 -0700 Subject: Make {Un}Marshal{Bytes/Unsafe} return remaining buffer. Change marshal.Marshallable method signatures to return the remaining buffer. This makes it easier to implement these method manually. Without this, we would have to manually do buffer shifting which is error prone. tools/go_marshal/test:benchmark test does not show change in performance. Additionally fixed some marshalling bugs in fsimpl/fuse. Updated multiple callpoints to get rid of redundant slice indexing work and simplified code using this new signature. Updates #6450 PiperOrigin-RevId: 407857019 --- pkg/abi/linux/fuse.go | 111 ++++++++++++++++++++++------------------ pkg/abi/linux/msgqueue.go | 12 ++--- pkg/abi/linux/netfilter.go | 30 +++++------ pkg/abi/linux/netfilter_ipv6.go | 32 ++++++------ pkg/abi/linux/socket.go | 3 -- 5 files changed, 96 insertions(+), 92 deletions(-) (limited to 'pkg/abi') diff --git a/pkg/abi/linux/fuse.go b/pkg/abi/linux/fuse.go index 1070b457c..1112dadd6 100644 --- a/pkg/abi/linux/fuse.go +++ b/pkg/abi/linux/fuse.go @@ -352,6 +352,22 @@ type FUSEEntryOut struct { Attr FUSEAttr } +// CString represents a null terminated string which can be marshalled. +type CString string + +// MarshalBytes implements marshal.Marshallable.MarshalBytes. +func (s *CString) MarshalBytes(buf []byte) []byte { + copy(buf, *s) + buf[len(*s)] = 0 // null char + return buf[s.SizeBytes():] +} + +// SizeBytes implements marshal.Marshallable.SizeBytes. +func (s *CString) SizeBytes() int { + // 1 extra byte for null-terminated string. + return len(*s) + 1 +} + // FUSELookupIn is the request sent by the kernel to the daemon // to look up a file name. // @@ -360,18 +376,17 @@ type FUSELookupIn struct { marshal.StubMarshallable // Name is a file name to be looked up. - Name string + Name CString } // MarshalBytes serializes r.name to the dst buffer. -func (r *FUSELookupIn) MarshalBytes(buf []byte) { - copy(buf, r.Name) +func (r *FUSELookupIn) MarshalBytes(buf []byte) []byte { + return r.Name.MarshalBytes(buf) } // SizeBytes is the size of the memory representation of FUSELookupIn. -// 1 extra byte for null-terminated string. func (r *FUSELookupIn) SizeBytes() int { - return len(r.Name) + 1 + return r.Name.SizeBytes() } // MAX_NON_LFS indicates the maximum offset without large file support. @@ -530,19 +545,18 @@ type FUSECreateIn struct { CreateMeta FUSECreateMeta // Name is the name of the node to create. - Name string + Name CString } // MarshalBytes serializes r.CreateMeta and r.Name to the dst buffer. -func (r *FUSECreateIn) MarshalBytes(buf []byte) { - r.CreateMeta.MarshalBytes(buf[:r.CreateMeta.SizeBytes()]) - copy(buf[r.CreateMeta.SizeBytes():], r.Name) +func (r *FUSECreateIn) MarshalBytes(buf []byte) []byte { + buf = r.CreateMeta.MarshalBytes(buf) + return r.Name.MarshalBytes(buf) } // SizeBytes is the size of the memory representation of FUSECreateIn. -// 1 extra byte for null-terminated string. func (r *FUSECreateIn) SizeBytes() int { - return r.CreateMeta.SizeBytes() + len(r.Name) + 1 + return r.CreateMeta.SizeBytes() + r.Name.SizeBytes() } // FUSEMknodMeta contains all the static fields of FUSEMknodIn, @@ -573,19 +587,18 @@ type FUSEMknodIn struct { MknodMeta FUSEMknodMeta // Name is the name of the node to create. - Name string + Name CString } // MarshalBytes serializes r.MknodMeta and r.Name to the dst buffer. -func (r *FUSEMknodIn) MarshalBytes(buf []byte) { - r.MknodMeta.MarshalBytes(buf[:r.MknodMeta.SizeBytes()]) - copy(buf[r.MknodMeta.SizeBytes():], r.Name) +func (r *FUSEMknodIn) MarshalBytes(buf []byte) []byte { + buf = r.MknodMeta.MarshalBytes(buf) + return r.Name.MarshalBytes(buf) } // SizeBytes is the size of the memory representation of FUSEMknodIn. -// 1 extra byte for null-terminated string. func (r *FUSEMknodIn) SizeBytes() int { - return r.MknodMeta.SizeBytes() + len(r.Name) + 1 + return r.MknodMeta.SizeBytes() + r.Name.SizeBytes() } // FUSESymLinkIn is the request sent by the kernel to the daemon, @@ -596,30 +609,30 @@ type FUSESymLinkIn struct { marshal.StubMarshallable // Name of symlink to create. - Name string + Name CString // Target of the symlink. - Target string + Target CString } // MarshalBytes serializes r.Name and r.Target to the dst buffer. -// Left null-termination at end of r.Name and r.Target. -func (r *FUSESymLinkIn) MarshalBytes(buf []byte) { - copy(buf, r.Name) - copy(buf[len(r.Name)+1:], r.Target) +func (r *FUSESymLinkIn) MarshalBytes(buf []byte) []byte { + buf = r.Name.MarshalBytes(buf) + return r.Target.MarshalBytes(buf) } // SizeBytes is the size of the memory representation of FUSESymLinkIn. -// 2 extra bytes for null-terminated string. func (r *FUSESymLinkIn) SizeBytes() int { - return len(r.Name) + len(r.Target) + 2 + return r.Name.SizeBytes() + r.Target.SizeBytes() } // FUSEEmptyIn is used by operations without request body. type FUSEEmptyIn struct{ marshal.StubMarshallable } // MarshalBytes do nothing for marshal. -func (r *FUSEEmptyIn) MarshalBytes(buf []byte) {} +func (r *FUSEEmptyIn) MarshalBytes(buf []byte) []byte { + return buf +} // SizeBytes is 0 for empty request. func (r *FUSEEmptyIn) SizeBytes() int { @@ -649,19 +662,18 @@ type FUSEMkdirIn struct { MkdirMeta FUSEMkdirMeta // Name of the directory to create. - Name string + Name CString } // MarshalBytes serializes r.MkdirMeta and r.Name to the dst buffer. -func (r *FUSEMkdirIn) MarshalBytes(buf []byte) { - r.MkdirMeta.MarshalBytes(buf[:r.MkdirMeta.SizeBytes()]) - copy(buf[r.MkdirMeta.SizeBytes():], r.Name) +func (r *FUSEMkdirIn) MarshalBytes(buf []byte) []byte { + buf = r.MkdirMeta.MarshalBytes(buf) + return r.Name.MarshalBytes(buf) } // SizeBytes is the size of the memory representation of FUSEMkdirIn. -// 1 extra byte for null-terminated Name string. func (r *FUSEMkdirIn) SizeBytes() int { - return r.MkdirMeta.SizeBytes() + len(r.Name) + 1 + return r.MkdirMeta.SizeBytes() + r.Name.SizeBytes() } // FUSERmDirIn is the request sent by the kernel to the daemon @@ -672,17 +684,17 @@ type FUSERmDirIn struct { marshal.StubMarshallable // Name is a directory name to be removed. - Name string + Name CString } // MarshalBytes serializes r.name to the dst buffer. -func (r *FUSERmDirIn) MarshalBytes(buf []byte) { - copy(buf, r.Name) +func (r *FUSERmDirIn) MarshalBytes(buf []byte) []byte { + return r.Name.MarshalBytes(buf) } // SizeBytes is the size of the memory representation of FUSERmDirIn. func (r *FUSERmDirIn) SizeBytes() int { - return len(r.Name) + 1 + return r.Name.SizeBytes() } // FUSEDirents is a list of Dirents received from the FUSE daemon server. @@ -738,7 +750,7 @@ func (r *FUSEDirents) SizeBytes() int { } // UnmarshalBytes deserializes FUSEDirents from the src buffer. -func (r *FUSEDirents) UnmarshalBytes(src []byte) { +func (r *FUSEDirents) UnmarshalBytes(src []byte) []byte { for { if len(src) <= (*FUSEDirentMeta)(nil).SizeBytes() { break @@ -754,11 +766,10 @@ func (r *FUSEDirents) UnmarshalBytes(src []byte) { // to do this. Linux allocates 1 page to store all the dirents and then // simply reads them from the page. var dirent FUSEDirent - dirent.UnmarshalBytes(src) + src = dirent.UnmarshalBytes(src) r.Dirents = append(r.Dirents, &dirent) - - src = src[dirent.SizeBytes():] } + return src } // SizeBytes is the size of the memory representation of FUSEDirent. @@ -772,20 +783,20 @@ func (r *FUSEDirent) SizeBytes() int { } // UnmarshalBytes deserializes FUSEDirent from the src buffer. -func (r *FUSEDirent) UnmarshalBytes(src []byte) { - r.Meta.UnmarshalBytes(src) - src = src[r.Meta.SizeBytes():] +func (r *FUSEDirent) UnmarshalBytes(src []byte) []byte { + src = r.Meta.UnmarshalBytes(src) if r.Meta.NameLen > FUSE_NAME_MAX { // The name is too long and therefore invalid. We don't // need to unmarshal the name since it'll be thrown away. - return + return src } buf := make([]byte, r.Meta.NameLen) name := primitive.ByteSlice(buf) name.UnmarshalBytes(src[:r.Meta.NameLen]) r.Name = string(name) + return src[r.Meta.NameLen:] } // FATTR_* consts are the attribute flags defined in include/uapi/linux/fuse.h. @@ -863,17 +874,15 @@ type FUSEUnlinkIn struct { marshal.StubMarshallable // Name of the node to unlink. - Name string + Name CString } -// MarshalBytes serializes r.name to the dst buffer, which should -// have size len(r.Name) + 1 and last byte set to 0. -func (r *FUSEUnlinkIn) MarshalBytes(buf []byte) { - copy(buf, r.Name) +// MarshalBytes serializes r.name to the dst buffer. +func (r *FUSEUnlinkIn) MarshalBytes(buf []byte) []byte { + return r.Name.MarshalBytes(buf) } // SizeBytes is the size of the memory representation of FUSEUnlinkIn. -// 1 extra byte for null-terminated Name string. func (r *FUSEUnlinkIn) SizeBytes() int { - return len(r.Name) + 1 + return r.Name.SizeBytes() } diff --git a/pkg/abi/linux/msgqueue.go b/pkg/abi/linux/msgqueue.go index 0612a8214..6f8eb4dd9 100644 --- a/pkg/abi/linux/msgqueue.go +++ b/pkg/abi/linux/msgqueue.go @@ -82,15 +82,15 @@ func (b *MsgBuf) SizeBytes() int { } // MarshalBytes implements marshal.Marshallable.MarshalBytes. -func (b *MsgBuf) MarshalBytes(dst []byte) { - b.Type.MarshalUnsafe(dst) - b.Text.MarshalBytes(dst[b.Type.SizeBytes():]) +func (b *MsgBuf) MarshalBytes(dst []byte) []byte { + dst = b.Type.MarshalUnsafe(dst) + return b.Text.MarshalBytes(dst) } // UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes. -func (b *MsgBuf) UnmarshalBytes(src []byte) { - b.Type.UnmarshalUnsafe(src) - b.Text.UnmarshalBytes(src[b.Type.SizeBytes():]) +func (b *MsgBuf) UnmarshalBytes(src []byte) []byte { + src = b.Type.UnmarshalUnsafe(src) + return b.Text.UnmarshalBytes(src) } // MsgInfo is equivelant to struct msginfo. Source: include/uapi/linux/msg.h diff --git a/pkg/abi/linux/netfilter.go b/pkg/abi/linux/netfilter.go index 3fd05483a..1470a5578 100644 --- a/pkg/abi/linux/netfilter.go +++ b/pkg/abi/linux/netfilter.go @@ -144,15 +144,15 @@ func (ke *KernelIPTEntry) SizeBytes() int { } // MarshalBytes implements marshal.Marshallable.MarshalBytes. -func (ke *KernelIPTEntry) MarshalBytes(dst []byte) { - ke.Entry.MarshalUnsafe(dst) - ke.Elems.MarshalBytes(dst[ke.Entry.SizeBytes():]) +func (ke *KernelIPTEntry) MarshalBytes(dst []byte) []byte { + dst = ke.Entry.MarshalUnsafe(dst) + return ke.Elems.MarshalBytes(dst) } // UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes. -func (ke *KernelIPTEntry) UnmarshalBytes(src []byte) { - ke.Entry.UnmarshalUnsafe(src) - ke.Elems.UnmarshalBytes(src[ke.Entry.SizeBytes():]) +func (ke *KernelIPTEntry) UnmarshalBytes(src []byte) []byte { + src = ke.Entry.UnmarshalUnsafe(src) + return ke.Elems.UnmarshalBytes(src) } var _ marshal.Marshallable = (*KernelIPTEntry)(nil) @@ -455,23 +455,21 @@ func (ke *KernelIPTGetEntries) SizeBytes() int { } // MarshalBytes implements marshal.Marshallable.MarshalBytes. -func (ke *KernelIPTGetEntries) MarshalBytes(dst []byte) { - ke.IPTGetEntries.MarshalUnsafe(dst) - marshalledUntil := ke.IPTGetEntries.SizeBytes() +func (ke *KernelIPTGetEntries) MarshalBytes(dst []byte) []byte { + dst = ke.IPTGetEntries.MarshalUnsafe(dst) for i := range ke.Entrytable { - ke.Entrytable[i].MarshalBytes(dst[marshalledUntil:]) - marshalledUntil += ke.Entrytable[i].SizeBytes() + dst = ke.Entrytable[i].MarshalBytes(dst) } + return dst } // UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes. -func (ke *KernelIPTGetEntries) UnmarshalBytes(src []byte) { - ke.IPTGetEntries.UnmarshalUnsafe(src) - unmarshalledUntil := ke.IPTGetEntries.SizeBytes() +func (ke *KernelIPTGetEntries) UnmarshalBytes(src []byte) []byte { + src = ke.IPTGetEntries.UnmarshalUnsafe(src) for i := range ke.Entrytable { - ke.Entrytable[i].UnmarshalBytes(src[unmarshalledUntil:]) - unmarshalledUntil += ke.Entrytable[i].SizeBytes() + src = ke.Entrytable[i].UnmarshalBytes(src) } + return src } var _ marshal.Marshallable = (*KernelIPTGetEntries)(nil) diff --git a/pkg/abi/linux/netfilter_ipv6.go b/pkg/abi/linux/netfilter_ipv6.go index f8c0e891e..aba0202ef 100644 --- a/pkg/abi/linux/netfilter_ipv6.go +++ b/pkg/abi/linux/netfilter_ipv6.go @@ -84,23 +84,21 @@ func (ke *KernelIP6TGetEntries) SizeBytes() int { } // MarshalBytes implements marshal.Marshallable.MarshalBytes. -func (ke *KernelIP6TGetEntries) MarshalBytes(dst []byte) { - ke.IPTGetEntries.MarshalUnsafe(dst) - marshalledUntil := ke.IPTGetEntries.SizeBytes() +func (ke *KernelIP6TGetEntries) MarshalBytes(dst []byte) []byte { + dst = ke.IPTGetEntries.MarshalUnsafe(dst) for i := range ke.Entrytable { - ke.Entrytable[i].MarshalBytes(dst[marshalledUntil:]) - marshalledUntil += ke.Entrytable[i].SizeBytes() + dst = ke.Entrytable[i].MarshalBytes(dst) } + return dst } // UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes. -func (ke *KernelIP6TGetEntries) UnmarshalBytes(src []byte) { - ke.IPTGetEntries.UnmarshalUnsafe(src) - unmarshalledUntil := ke.IPTGetEntries.SizeBytes() +func (ke *KernelIP6TGetEntries) UnmarshalBytes(src []byte) []byte { + src = ke.IPTGetEntries.UnmarshalUnsafe(src) for i := range ke.Entrytable { - ke.Entrytable[i].UnmarshalBytes(src[unmarshalledUntil:]) - unmarshalledUntil += ke.Entrytable[i].SizeBytes() + src = ke.Entrytable[i].UnmarshalBytes(src) } + return src } var _ marshal.Marshallable = (*KernelIP6TGetEntries)(nil) @@ -166,17 +164,19 @@ func (ke *KernelIP6TEntry) SizeBytes() int { } // MarshalBytes implements marshal.Marshallable.MarshalBytes. -func (ke *KernelIP6TEntry) MarshalBytes(dst []byte) { - ke.Entry.MarshalUnsafe(dst) - ke.Elems.MarshalBytes(dst[ke.Entry.SizeBytes():]) +func (ke *KernelIP6TEntry) MarshalBytes(dst []byte) []byte { + dst = ke.Entry.MarshalUnsafe(dst) + return ke.Elems.MarshalBytes(dst) } // UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes. -func (ke *KernelIP6TEntry) UnmarshalBytes(src []byte) { - ke.Entry.UnmarshalUnsafe(src) - ke.Elems.UnmarshalBytes(src[ke.Entry.SizeBytes():]) +func (ke *KernelIP6TEntry) UnmarshalBytes(src []byte) []byte { + src = ke.Entry.UnmarshalUnsafe(src) + return ke.Elems.UnmarshalBytes(src) } +var _ marshal.Marshallable = (*KernelIP6TEntry)(nil) + // IP6TIP contains information for matching a packet's IP header. // It corresponds to struct ip6t_ip6 in // include/uapi/linux/netfilter_ipv6/ip6_tables.h. diff --git a/pkg/abi/linux/socket.go b/pkg/abi/linux/socket.go index f60e42997..a31690a04 100644 --- a/pkg/abi/linux/socket.go +++ b/pkg/abi/linux/socket.go @@ -555,9 +555,6 @@ type ControlMessageIPv6PacketInfo struct { // ControlMessageCredentials struct. var SizeOfControlMessageCredentials = (*ControlMessageCredentials)(nil).SizeBytes() -// A ControlMessageRights is an SCM_RIGHTS socket control message. -type ControlMessageRights []int32 - // SizeOfControlMessageRight is the size of a single element in // ControlMessageRights. const SizeOfControlMessageRight = 4 -- cgit v1.2.3