usbip: inline thin wrappers and drop pass-through darwin session
Apply the <10-LoC / <3-non-test-caller heuristic across the package: inline writeControlFrame, removeLeaseWaiter, vhciAttach, vhciHubForSpeed, applyControlSnapshot, applyRemoteEntries, shouldRetryBusID, entrySerial, and the trivial darwin/linux import-host constructors at their call sites. Delete the darwinClientSession wrapper -- darwinVirtualController already satisfies DataSession, so attach the Description() method to it directly and return the controller from darwinImportHost.Attach. Fold the 11-line data_session.go into host.go beside AttachedSession, which embeds DataSession.
This commit is contained in:
+10
-1
@@ -139,7 +139,16 @@ func (c *ClientService) runBusIDLoop(ctx context.Context, busid, description str
|
||||
if ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
if !c.shouldRetryBusID(ctx, busid) {
|
||||
retry := true
|
||||
if !c.assignment.Matched() {
|
||||
err = c.syncRemoteStateContext(ctx)
|
||||
if err != nil {
|
||||
c.logger.Warn("refresh remote exports after releasing ", busid, ": ", err)
|
||||
} else {
|
||||
retry = c.assignment.IsRetryDesired(busid)
|
||||
}
|
||||
}
|
||||
if !retry {
|
||||
c.logger.Info("remote export ", busid, " disappeared; stopping import worker")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -72,7 +72,9 @@ func (s *clientControlSession) requestLease(ctx context.Context, busid string) (
|
||||
Version: controlProtocolVersion,
|
||||
}, request)
|
||||
if err != nil {
|
||||
s.removeLeaseWaiter(nonce)
|
||||
s.access.Lock()
|
||||
delete(s.pending, nonce)
|
||||
s.access.Unlock()
|
||||
return controlLeaseResponse{}, err
|
||||
}
|
||||
|
||||
@@ -80,7 +82,9 @@ func (s *clientControlSession) requestLease(ctx context.Context, busid string) (
|
||||
case result := <-waiter:
|
||||
return result.response, result.err
|
||||
case <-ctx.Done():
|
||||
s.removeLeaseWaiter(nonce)
|
||||
s.access.Lock()
|
||||
delete(s.pending, nonce)
|
||||
s.access.Unlock()
|
||||
return controlLeaseResponse{}, ctx.Err()
|
||||
}
|
||||
}
|
||||
@@ -100,12 +104,6 @@ func (s *clientControlSession) deliverLeaseResponse(response controlLeaseRespons
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *clientControlSession) removeLeaseWaiter(nonce uint64) {
|
||||
s.access.Lock()
|
||||
delete(s.pending, nonce)
|
||||
s.access.Unlock()
|
||||
}
|
||||
|
||||
func (s *clientControlSession) closeWithError(err error) {
|
||||
s.access.Lock()
|
||||
if s.closed {
|
||||
@@ -144,15 +142,6 @@ func (c *ClientService) requestImportLease(ctx context.Context, busid string) (c
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *ClientService) applyControlSnapshot(snapshot controlDeviceSnapshot) {
|
||||
devices := deviceInfoV2Map(snapshot.Devices)
|
||||
values := sortedDeviceInfoV2Values(devices)
|
||||
c.remoteAccess.Lock()
|
||||
c.remoteDevicesV2 = devices
|
||||
c.remoteAccess.Unlock()
|
||||
c.applyRemoteDeviceState(values)
|
||||
}
|
||||
|
||||
func (c *ClientService) applyControlDelta(delta controlDeviceDelta) {
|
||||
c.remoteAccess.Lock()
|
||||
if c.remoteDevicesV2 == nil {
|
||||
@@ -194,6 +183,10 @@ func (c *ClientService) syncRemoteStateAndResetControlState(ctx context.Context)
|
||||
c.remoteAccess.Lock()
|
||||
c.remoteDevicesV2 = devices
|
||||
c.remoteAccess.Unlock()
|
||||
c.applyRemoteEntries(entries)
|
||||
if !c.assignment.Matched() {
|
||||
c.applyRemoteExports(entries)
|
||||
return nil
|
||||
}
|
||||
c.applyMatchedExportsWithRetained(entries, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ type darwinPendingSubmit struct {
|
||||
reply chan SubmitResponse
|
||||
}
|
||||
|
||||
var _ DataSession = (*darwinVirtualController)(nil)
|
||||
var _ AttachedSession = (*darwinVirtualController)(nil)
|
||||
|
||||
type darwinVirtualController struct {
|
||||
ctx context.Context
|
||||
@@ -124,6 +124,10 @@ func (c *darwinVirtualController) Err() error {
|
||||
return c.runErr
|
||||
}
|
||||
|
||||
func (c *darwinVirtualController) Description() string {
|
||||
return "IOUSBHostControllerInterface"
|
||||
}
|
||||
|
||||
func (c *darwinVirtualController) enqueueEvent(event darwinControllerEvent) {
|
||||
select {
|
||||
case c.events <- event:
|
||||
|
||||
@@ -99,11 +99,11 @@ func (c *ClientService) runControlSession() error {
|
||||
if err != nil {
|
||||
return E.Cause(errControlUnsupported, "write control preface: ", err)
|
||||
}
|
||||
err = writeControlFrame(conn, controlFrame{
|
||||
err = writeControlMessage(conn, controlFrame{
|
||||
Type: controlFrameHello,
|
||||
Version: controlProtocolVersion,
|
||||
Capabilities: controlCapabilities,
|
||||
})
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return E.Cause(errControlUnsupported, "write control hello: ", err)
|
||||
}
|
||||
@@ -190,7 +190,12 @@ func (c *ClientService) runControlSession() error {
|
||||
return E.Cause(errImmediateReconnect, "read device snapshot: ", err)
|
||||
}
|
||||
lastSeq = frame.Sequence
|
||||
c.applyControlSnapshot(snapshot)
|
||||
devices := deviceInfoV2Map(snapshot.Devices)
|
||||
values := sortedDeviceInfoV2Values(devices)
|
||||
c.remoteAccess.Lock()
|
||||
c.remoteDevicesV2 = devices
|
||||
c.remoteAccess.Unlock()
|
||||
c.applyRemoteDeviceState(values)
|
||||
case controlFrameDeviceDelta:
|
||||
if !extended {
|
||||
return E.Cause(errImmediateReconnect, "unexpected control frame ", frame.Type)
|
||||
@@ -254,16 +259,12 @@ func (c *ClientService) syncRemoteStateContext(ctx context.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.applyRemoteEntries(entries)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ClientService) applyRemoteEntries(entries []DeviceEntry) {
|
||||
if !c.assignment.Matched() {
|
||||
c.applyRemoteExports(entries)
|
||||
return
|
||||
return nil
|
||||
}
|
||||
c.applyMatchedExportsWithRetained(entries, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ClientService) applyRemoteDeviceState(devices []DeviceInfoV2) {
|
||||
@@ -448,15 +449,3 @@ func (c *ClientService) fetchDevList(ctx context.Context) ([]DeviceEntry, error)
|
||||
}
|
||||
return ReadOpRepDevListBody(conn)
|
||||
}
|
||||
|
||||
func (c *ClientService) shouldRetryBusID(ctx context.Context, busid string) bool {
|
||||
if c.assignment.Matched() {
|
||||
return true
|
||||
}
|
||||
err := c.syncRemoteStateContext(ctx)
|
||||
if err != nil {
|
||||
c.logger.Warn("refresh remote exports after releasing ", busid, ": ", err)
|
||||
return true
|
||||
}
|
||||
return c.assignment.IsRetryDesired(busid)
|
||||
}
|
||||
|
||||
@@ -161,10 +161,6 @@ func (cr *controlReader) read(r io.Reader) (controlMessage, error) {
|
||||
return controlMessage{Frame: frame, Payload: payload}, nil
|
||||
}
|
||||
|
||||
func writeControlFrame(w io.Writer, frame controlFrame) error {
|
||||
return writeControlMessage(w, frame, nil)
|
||||
}
|
||||
|
||||
func writeControlMessage(w io.Writer, frame controlFrame, payload any) error {
|
||||
rawPayload, err := marshalControlPayload(payload)
|
||||
if err != nil {
|
||||
@@ -224,12 +220,16 @@ func deviceInfoV2FromEntry(entry DeviceEntry, backend string, stableID string, s
|
||||
if state == "" {
|
||||
state = deviceStateAvailable
|
||||
}
|
||||
serial := entry.Serial
|
||||
if serial == "" {
|
||||
serial = entry.Info.SerialString()
|
||||
}
|
||||
return DeviceInfoV2{
|
||||
BusID: entry.Info.BusIDString(),
|
||||
StableID: stableID,
|
||||
Backend: backend,
|
||||
Path: cstring(entry.Info.Path[:]),
|
||||
Serial: entrySerial(entry),
|
||||
Serial: serial,
|
||||
VendorID: entry.Info.IDVendor,
|
||||
ProductID: entry.Info.IDProduct,
|
||||
BCDDevice: entry.Info.BCDDevice,
|
||||
|
||||
@@ -144,7 +144,7 @@ func TestDarwinClientSessionClosesOnContextCancel(t *testing.T) {
|
||||
defer serverConn.Close()
|
||||
controller := newDarwinVirtualController(context.Background(), newTestLogger(t), clientConn, DeviceInfoTruncated{})
|
||||
go controller.readLoop()
|
||||
session := &darwinClientSession{controller: controller}
|
||||
session := controller
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
@@ -304,11 +304,11 @@ func (s *darwinFakeUSBIPServer) handleControlConn(conn net.Conn) {
|
||||
return
|
||||
}
|
||||
capabilities := hello.Capabilities & controlCapabilities
|
||||
err = writeControlFrame(conn, controlFrame{
|
||||
err = writeControlMessage(conn, controlFrame{
|
||||
Type: controlFrameAck,
|
||||
Version: controlProtocolVersion,
|
||||
Capabilities: capabilities,
|
||||
})
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -345,7 +345,7 @@ func (s *darwinFakeUSBIPServer) handleControlConn(conn net.Conn) {
|
||||
}
|
||||
return
|
||||
}
|
||||
err = writeControlFrame(conn, controlFrame{Type: controlFramePong, Version: controlProtocolVersion})
|
||||
err = writeControlMessage(conn, controlFrame{Type: controlFramePong, Version: controlProtocolVersion}, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
package usbip
|
||||
|
||||
// DataSession implementations MUST close the channel returned by Done
|
||||
// when the session terminates for any reason. Err is only valid after
|
||||
// Done is closed; it returns nil for a clean detach. Close is idempotent
|
||||
// and safe to call from any goroutine.
|
||||
type DataSession interface {
|
||||
Done() <-chan struct{}
|
||||
Err() error
|
||||
Close() error
|
||||
}
|
||||
@@ -48,6 +48,16 @@ type ExportSnapshot struct {
|
||||
RawStatus int
|
||||
}
|
||||
|
||||
// DataSession implementations MUST close the channel returned by Done
|
||||
// when the session terminates for any reason. Err is only valid after
|
||||
// Done is closed; it returns nil for a clean detach. Close is idempotent
|
||||
// and safe to call from any goroutine.
|
||||
type DataSession interface {
|
||||
Done() <-chan struct{}
|
||||
Err() error
|
||||
Close() error
|
||||
}
|
||||
|
||||
type AttachedSession interface {
|
||||
DataSession
|
||||
Description() string
|
||||
|
||||
@@ -24,7 +24,7 @@ func newPlatformExportHost(logger log.ContextLogger, matches []option.USBIPDevic
|
||||
}
|
||||
|
||||
func newPlatformImportHost(logger log.ContextLogger) (ImportHost, error) {
|
||||
return newDarwinImportHost(logger), nil
|
||||
return &darwinImportHost{logger: logger}, nil
|
||||
}
|
||||
|
||||
// darwinExportHost retains stale captures: devices that reconcile
|
||||
@@ -285,10 +285,6 @@ type darwinImportHost struct {
|
||||
logger log.ContextLogger
|
||||
}
|
||||
|
||||
func newDarwinImportHost(logger log.ContextLogger) *darwinImportHost {
|
||||
return &darwinImportHost{logger: logger}
|
||||
}
|
||||
|
||||
func (h *darwinImportHost) Start(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
@@ -304,27 +300,7 @@ func (h *darwinImportHost) Attach(ctx context.Context, info DeviceInfoTruncated,
|
||||
_ = controller.Close()
|
||||
return nil, err
|
||||
}
|
||||
return &darwinClientSession{controller: controller}, nil
|
||||
}
|
||||
|
||||
type darwinClientSession struct {
|
||||
controller *darwinVirtualController
|
||||
}
|
||||
|
||||
func (s *darwinClientSession) Done() <-chan struct{} {
|
||||
return s.controller.Done()
|
||||
}
|
||||
|
||||
func (s *darwinClientSession) Err() error {
|
||||
return s.controller.Err()
|
||||
}
|
||||
|
||||
func (s *darwinClientSession) Close() error {
|
||||
return s.controller.Close()
|
||||
}
|
||||
|
||||
func (s *darwinClientSession) Description() string {
|
||||
return "IOUSBHostControllerInterface"
|
||||
return controller, nil
|
||||
}
|
||||
|
||||
var _ DataSession = (*darwinServerDataSession)(nil)
|
||||
|
||||
@@ -26,7 +26,10 @@ func newPlatformExportHost(logger log.ContextLogger, matches []option.USBIPDevic
|
||||
}
|
||||
|
||||
func newPlatformImportHost(logger log.ContextLogger) (ImportHost, error) {
|
||||
return newLinuxImportHost(logger), nil
|
||||
return &linuxImportHost{
|
||||
logger: logger,
|
||||
ports: make(map[int]struct{}),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func isMissingUSBDeviceError(err error) bool {
|
||||
@@ -463,13 +466,6 @@ type linuxImportHost struct {
|
||||
ports map[int]struct{}
|
||||
}
|
||||
|
||||
func newLinuxImportHost(logger log.ContextLogger) *linuxImportHost {
|
||||
return &linuxImportHost{
|
||||
logger: logger,
|
||||
ports: make(map[int]struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (h *linuxImportHost) Start(ctx context.Context) error {
|
||||
return ensureKernelPath(sysVHCIControllerV0, "vhci-hcd", "vhci_hcd.0")
|
||||
}
|
||||
@@ -512,7 +508,8 @@ func (h *linuxImportHost) attachOnce(ctx context.Context, info DeviceInfoTruncat
|
||||
triedPorts[port] = struct{}{}
|
||||
continue
|
||||
}
|
||||
err = vhciAttach(port, handoff.file.Fd(), info.DevID(), info.Speed)
|
||||
attachLine := fmt.Sprintf("%d %d %d %d", port, int(handoff.file.Fd()), info.DevID(), info.Speed)
|
||||
err = writeSysfs(filepath.Join(sysVHCIControllerV0, "attach"), attachLine)
|
||||
if err != nil {
|
||||
h.releasePort(port)
|
||||
if errors.Is(err, unix.EBUSY) {
|
||||
|
||||
@@ -287,18 +287,15 @@ func trailingCString(b []byte) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func entrySerial(entry DeviceEntry) string {
|
||||
if entry.Serial != "" {
|
||||
return entry.Serial
|
||||
}
|
||||
return entry.Info.SerialString()
|
||||
}
|
||||
|
||||
func entryDeviceKey(entry DeviceEntry) DeviceKey {
|
||||
serial := entry.Serial
|
||||
if serial == "" {
|
||||
serial = entry.Info.SerialString()
|
||||
}
|
||||
return DeviceKey{
|
||||
BusID: entry.Info.BusIDString(),
|
||||
VendorID: entry.Info.IDVendor,
|
||||
ProductID: entry.Info.IDProduct,
|
||||
Serial: entrySerial(entry),
|
||||
Serial: serial,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,12 +198,12 @@ func (s *ServerService) handleControlConn(conn net.Conn) {
|
||||
capabilities := hello.Capabilities & controlCapabilities
|
||||
sub, seq := s.ledger.Subscribe(s.ctx, conn, capabilities)
|
||||
defer s.ledger.Unsubscribe(sub)
|
||||
err = writeControlFrame(conn, controlFrame{
|
||||
err = writeControlMessage(conn, controlFrame{
|
||||
Type: controlFrameAck,
|
||||
Version: controlProtocolVersion,
|
||||
Capabilities: capabilities,
|
||||
Sequence: seq,
|
||||
})
|
||||
}, nil)
|
||||
if err != nil {
|
||||
s.logger.Debug("write control ack: ", err)
|
||||
return
|
||||
|
||||
@@ -177,7 +177,11 @@ func vhciPickFreePort(speed uint32, skip map[int]struct{}) (int, error) {
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
targetHub := vhciHubForSpeed(speed)
|
||||
targetHub := "hs"
|
||||
switch speed {
|
||||
case SpeedSuper, SpeedSuperPlus:
|
||||
targetHub = "ss"
|
||||
}
|
||||
for _, record := range records {
|
||||
if record.hub != targetHub || record.state != 4 {
|
||||
continue
|
||||
@@ -190,11 +194,6 @@ func vhciPickFreePort(speed uint32, skip map[int]struct{}) (int, error) {
|
||||
return -1, E.New("no free ", targetHub, " vhci port")
|
||||
}
|
||||
|
||||
func vhciAttach(port int, fd uintptr, devid uint32, speed uint32) error {
|
||||
line := fmt.Sprintf("%d %d %d %d", port, int(fd), devid, speed)
|
||||
return writeSysfs(filepath.Join(sysVHCIControllerV0, "attach"), line)
|
||||
}
|
||||
|
||||
func readVHCIStatus() ([]vhciStatusRecord, error) {
|
||||
raw, err := os.ReadFile(filepath.Join(sysVHCIControllerV0, "status"))
|
||||
if err != nil {
|
||||
@@ -237,15 +236,6 @@ func parseVHCIStatus(raw string) []vhciStatusRecord {
|
||||
return records
|
||||
}
|
||||
|
||||
func vhciHubForSpeed(speed uint32) string {
|
||||
switch speed {
|
||||
case SpeedSuper, SpeedSuperPlus:
|
||||
return "ss"
|
||||
default:
|
||||
return "hs"
|
||||
}
|
||||
}
|
||||
|
||||
func ensureKernelPath(path string, module string, description string) error {
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
|
||||
Reference in New Issue
Block a user