Files
visor/pkg/lisafs/communicator.go
T
Ayush RanjanandgVisor bot 4021b261d2 Optionally donate a host FD to the mount point in lisafs.
This is not used as of now. This is required for directfs later. The impacted
RPCs are Mount and Open. Mount has been modified to now donate an optional FD
to the mount point.

As the mount point can be a socket or a symlink, which needs to be opened with
O_PATH, we can no longer expect unix.SetNonblock() to work always while donating
FD in lisafs. So allow it to fail. Just log a warning in such cases.

Also split out the logic to start channels from lisafs.NewClient(). Not all
clients require channels.

PiperOrigin-RevId: 504631423
2023-01-25 12:30:20 -08:00

88 lines
3.1 KiB
Go

// Copyright 2021 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// 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
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package lisafs
import (
"fmt"
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/log"
)
// Communicator is a server side utility which represents exactly how the
// server is communicating with the client.
type Communicator interface {
fmt.Stringer
// PayloadBuf returns a slice to the payload section of its internal buffer
// where the message can be marshalled. The handlers should use this to
// populate the payload buffer with the message.
//
// The payload buffer contents *should* be preserved across calls with
// different sizes. Note that this is not a guarantee, because a compromised
// owner of a "shared" payload buffer can tamper with its contents anytime,
// even when it's not its turn to do so.
PayloadBuf(size uint32) []byte
// SndRcvMessage sends message m. The caller must have populated PayloadBuf()
// with payloadLen bytes. The caller expects to receive wantFDs FDs.
// Any received FDs must be accessible via ReleaseFDs(). It returns the
// response message along with the response payload length.
SndRcvMessage(m MID, payloadLen uint32, wantFDs uint8) (MID, uint32, error)
// DonateFD attempts to make fd non-blocking and starts tracking it. The next
// call to ReleaseFDs will include fd in the order it was added. Communicator
// takes ownership of fd. Server side should call this.
DonateFD(fd int)
// Track starts tracking fd. The next call to ReleaseFDs will include fd in
// the order it was added. Communicator takes ownership of fd. Client side
// should use this for accumulating received FDs.
TrackFD(fd int)
// ReleaseFDs returns the accumulated FDs and stops tracking them. The
// ownership of the FDs is transferred to the caller.
ReleaseFDs() []int
}
// fdTracker is a partial implementation of Communicator. It can be embedded in
// Communicator implementations to keep track of FD donations.
type fdTracker struct {
fds []int
}
// DonateFD implements Communicator.DonateFD.
func (d *fdTracker) DonateFD(fd int) {
// Try to make the FD non-blocking.
if err := unix.SetNonblock(fd, true); err != nil {
// This may fail if fd was opened with O_PATH, because fcntl(F_SETFL) fails
// with EBADF on O_PATH FDs.
log.Warningf("DonateFD: unix.SetNonblock() failed on FD %d: %v", fd, err)
}
d.TrackFD(fd)
}
// TrackFD implements Communicator.TrackFD.
func (d *fdTracker) TrackFD(fd int) {
d.fds = append(d.fds, fd)
}
// ReleaseFDs implements Communicator.ReleaseFDs.
func (d *fdTracker) ReleaseFDs() []int {
ret := d.fds
d.fds = d.fds[:0]
return ret
}