diff --git a/pkg/lisafs/client.go b/pkg/lisafs/client.go index bb741bdee..51d7e2d09 100644 --- a/pkg/lisafs/client.go +++ b/pkg/lisafs/client.go @@ -101,7 +101,7 @@ func NewClient(sock *unet.Socket) (*Client, Inode, error) { mountReq MountReq mountResp MountResp ) - if err := c.SndRcvMessage(Mount, uint32(mountReq.SizeBytes()), mountReq.MarshalBytes, mountResp.CheckedUnmarshal, nil, mountResp.String, mountResp.String); err != nil { + if err := c.SndRcvMessage(Mount, uint32(mountReq.SizeBytes()), mountReq.MarshalBytes, mountResp.CheckedUnmarshal, nil, mountReq.String, mountResp.String); err != nil { return nil, Inode{}, err } diff --git a/pkg/lisafs/fd.go b/pkg/lisafs/fd.go index ce5551ff8..1d63af00d 100644 --- a/pkg/lisafs/fd.go +++ b/pkg/lisafs/fd.go @@ -458,13 +458,18 @@ type ControlFDImpl interface { Renamed() // GetXattr returns extended attributes of this file. It returns the number - // of bytes written into dataBuf. + // of bytes written into the buffer returned by getValueBuf which can be used + // to request buffer for some size. // - // If the value is larger than len(dataBuf), implementations may return - // ERANGE to indicate that the buffer is too small. + // If the value is larger than size, implementations may return ERANGE to + // indicate that the buffer is too small. + // + // N.B. size may be 0, in which can the implementation must first find out + // the attribute value size using getxattr(2) by passing size=0. Then request + // a buffer large enough using getValueBuf and write the value there. // // On the server, GetXattr has a read concurrency guarantee. - GetXattr(name string, dataBuf []byte) (uint16, error) + GetXattr(name string, size uint32, getValueBuf func(uint32) []byte) (uint16, error) // SetXattr sets extended attributes on this file. // diff --git a/pkg/lisafs/handlers.go b/pkg/lisafs/handlers.go index 02a1701d3..1747bc823 100644 --- a/pkg/lisafs/handlers.go +++ b/pkg/lisafs/handlers.go @@ -1295,17 +1295,19 @@ func FGetXattrHandler(c *Connection, comm Communicator, payloadLen uint32) (uint // FGetXattrResp simply is a wrapper around SizedString. var valueLen primitive.Uint16 respMetaSize := uint32(valueLen.SizeBytes()) - payloadBuf := comm.PayloadBuf(respMetaSize + uint32(req.BufSize)) var n uint16 if err := fd.safelyRead(func() error { if fd.node.isDeleted() { return unix.EINVAL } - n, err = fd.impl.GetXattr(string(req.Name), payloadBuf[respMetaSize:]) + n, err = fd.impl.GetXattr(string(req.Name), uint32(req.BufSize), func(dataLen uint32) []byte { + return comm.PayloadBuf(dataLen + respMetaSize)[respMetaSize:] + }) return err }); err != nil { return 0, err } + payloadBuf := comm.PayloadBuf(respMetaSize) valueLen = primitive.Uint16(n) valueLen.MarshalBytes(payloadBuf) return respMetaSize + uint32(n), nil diff --git a/runsc/fsgofer/lisafs.go b/runsc/fsgofer/lisafs.go index b2408787b..b0a7fa3de 100644 --- a/runsc/fsgofer/lisafs.go +++ b/runsc/fsgofer/lisafs.go @@ -668,14 +668,21 @@ func (fd *controlFDLisa) Renamed() { } // GetXattr implements lisafs.ControlFDImpl.GetXattr. -func (fd *controlFDLisa) GetXattr(name string, dataBuf []byte) (uint16, error) { +func (fd *controlFDLisa) GetXattr(name string, size uint32, getValueBuf func(uint32) []byte) (uint16, error) { if !fd.Conn().ServerImpl().(*LisafsServer).config.EnableVerityXattr { return 0, unix.EOPNOTSUPP } if _, ok := verityXattrs[name]; !ok { return 0, unix.EOPNOTSUPP } - n, err := unix.Fgetxattr(fd.hostFD, name, dataBuf) + if size == 0 { + n, err := unix.Fgetxattr(fd.hostFD, name, nil) + if err != nil { + return 0, err + } + size = uint32(n) + } + n, err := unix.Fgetxattr(fd.hostFD, name, getValueBuf(size)) return uint16(n), err }