mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Support multiple FUSE kernel versions of FUSE_INIT response struct
The fuse_init_out struct changes in different FUSE kernel versions. A FUSE server may implement older versions of fuse_init_out, but they share common attributes from the beginning. Implement variable-length marshallable interface to support older versions of ABI. Fixes #3707
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
"gvisor.dev/gvisor/tools/go_marshal/marshal"
|
||||
"gvisor.dev/gvisor/tools/go_marshal/primitive"
|
||||
)
|
||||
@@ -262,6 +263,63 @@ type FUSEInitOut struct {
|
||||
_ [8]uint32
|
||||
}
|
||||
|
||||
// FUSEInitRes is a variable-length wrapper of FUSEInitOut. The FUSE server may
|
||||
// implement older version of FUSE protocol, which contains a FUSEInitOut with
|
||||
// less attributes.
|
||||
//
|
||||
// Dynamically-sized objects cannot be marshalled.
|
||||
type FUSEInitRes struct {
|
||||
marshal.StubMarshallable
|
||||
|
||||
// InitOut contains the response from the FUSE server.
|
||||
InitOut FUSEInitOut
|
||||
|
||||
// Len is the total length of bytes of the response.
|
||||
Len uint32
|
||||
}
|
||||
|
||||
// UnMarshalBytes deserializes src to the InitOut attribute in a FUSEInitRes.
|
||||
func (r *FUSEInitRes) UnmarshalBytes(src []byte) {
|
||||
out := &r.InitOut
|
||||
|
||||
// Introduced before FUSE kernel version 7.13.
|
||||
out.Major = uint32(usermem.ByteOrder.Uint32(src[:4]))
|
||||
src = src[4:]
|
||||
out.Minor = uint32(usermem.ByteOrder.Uint32(src[:4]))
|
||||
src = src[4:]
|
||||
out.MaxReadahead = uint32(usermem.ByteOrder.Uint32(src[:4]))
|
||||
src = src[4:]
|
||||
out.Flags = uint32(usermem.ByteOrder.Uint32(src[:4]))
|
||||
src = src[4:]
|
||||
out.MaxBackground = uint16(usermem.ByteOrder.Uint16(src[:2]))
|
||||
src = src[2:]
|
||||
out.CongestionThreshold = uint16(usermem.ByteOrder.Uint16(src[:2]))
|
||||
src = src[2:]
|
||||
out.MaxWrite = uint32(usermem.ByteOrder.Uint32(src[:4]))
|
||||
src = src[4:]
|
||||
|
||||
// Introduced in FUSE kernel version 7.23.
|
||||
if len(src) >= 4 {
|
||||
out.TimeGran = uint32(usermem.ByteOrder.Uint32(src[:4]))
|
||||
src = src[4:]
|
||||
}
|
||||
// Introduced in FUSE kernel version 7.28.
|
||||
if len(src) >= 2 {
|
||||
out.MaxPages = uint16(usermem.ByteOrder.Uint16(src[:2]))
|
||||
src = src[2:]
|
||||
}
|
||||
// Introduced in FUSE kernel version 7.31.
|
||||
if len(src) >= 2 {
|
||||
out.MapAlignment = uint16(usermem.ByteOrder.Uint16(src[:2]))
|
||||
src = src[2:]
|
||||
}
|
||||
}
|
||||
|
||||
// SizeBytes is the size of the payload of the FUSE_INIT response.
|
||||
func (r *FUSEInitRes) SizeBytes() int {
|
||||
return int(r.Len)
|
||||
}
|
||||
|
||||
// FUSEGetAttrIn is the request sent by the kernel to the daemon,
|
||||
// to get the attribute of a inode.
|
||||
//
|
||||
|
||||
@@ -346,6 +346,11 @@ func (r *Response) Error() error {
|
||||
return error(sysErrNo)
|
||||
}
|
||||
|
||||
// DataLen returns the size of the response without the header.
|
||||
func (r *Response) DataLen() uint32 {
|
||||
return r.hdr.Len - uint32(r.hdr.SizeBytes())
|
||||
}
|
||||
|
||||
// UnmarshalPayload unmarshals the response data into m.
|
||||
func (r *Response) UnmarshalPayload(m marshal.Marshallable) error {
|
||||
hdrLen := r.hdr.SizeBytes()
|
||||
|
||||
@@ -76,12 +76,12 @@ func (conn *connection) InitRecv(res *Response, hasSysAdminCap bool) error {
|
||||
return err
|
||||
}
|
||||
|
||||
var out linux.FUSEInitOut
|
||||
if err := res.UnmarshalPayload(&out); err != nil {
|
||||
initRes := linux.FUSEInitRes{Len: res.DataLen()}
|
||||
if err := res.UnmarshalPayload(&initRes); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return conn.initProcessReply(&out, hasSysAdminCap)
|
||||
return conn.initProcessReply(&initRes.InitOut, hasSysAdminCap)
|
||||
}
|
||||
|
||||
// Process the FUSE_INIT reply from the FUSE server.
|
||||
|
||||
Reference in New Issue
Block a user