usbip: drop vhci secondary-controller plumbing

The secondary index threaded from sysfs status* files into
linuxClientSession only decorated one debug log string. Port numbers
are already globally unique across vhci controllers, so the port
alone identifies the attachment. Drop the field, the per-attach
sysfs glob+read for lookup, and the now-redundant filename parser;
the inline status* filter in readPrimaryVHCIStatus is enough to
guard the multi-file enumeration that vhciPickFreePort still needs.
This commit is contained in:
世界
2026-05-20 15:06:23 +08:00
parent e7518225ac
commit 3c034f99a0
2 changed files with 25 additions and 57 deletions
+12 -30
View File
@@ -741,26 +741,25 @@ func (h *linuxImportHost) Attach(ctx context.Context, info DeviceInfoTruncated,
mode = "relay"
}
h.logger.Debug("usbip client handoff ", info.BusIDString(), ": ", mode)
port, secondary, attachErr := h.attachOnce(ctx, info, handoff)
port, attachErr := h.attachOnce(ctx, info, handoff)
if attachErr != nil {
_ = handoff.Close()
return nil, attachErr
}
_ = handoff.Start()
return &linuxClientSession{
handoff: handoff,
host: h,
port: port,
secondary: secondary,
handoff: handoff,
host: h,
port: port,
}, nil
}
func (h *linuxImportHost) attachOnce(ctx context.Context, info DeviceInfoTruncated, handoff *kernelHandoffSession) (int, int, error) {
func (h *linuxImportHost) attachOnce(ctx context.Context, info DeviceInfoTruncated, handoff *kernelHandoffSession) (int, error) {
triedPorts := make(map[int]struct{})
for {
port, err := vhciPickFreePort(info.Speed, triedPorts)
if err != nil {
return -1, 0, err
return -1, err
}
if !h.reservePort(port) {
triedPorts[port] = struct{}{}
@@ -774,29 +773,16 @@ func (h *linuxImportHost) attachOnce(ctx context.Context, info DeviceInfoTruncat
triedPorts[port] = struct{}{}
continue
}
return -1, 0, E.Cause(err, "vhci attach")
return -1, E.Cause(err, "vhci attach")
}
err = handoff.closeKernelFD()
if err != nil {
h.logger.Debug("close kernel fd ", info.BusIDString(), ": ", err)
}
return port, lookupSecondaryForPort(port), nil
return port, nil
}
}
func lookupSecondaryForPort(port int) int {
records, err := readPrimaryVHCIStatus()
if err != nil {
return 0
}
for _, record := range records {
if record.port == port {
return record.secondary
}
}
return 0
}
func (h *linuxImportHost) reservePort(port int) bool {
h.portsAccess.Lock()
defer h.portsAccess.Unlock()
@@ -818,10 +804,9 @@ func (h *linuxImportHost) releasePort(port int) {
}
type linuxClientSession struct {
handoff *kernelHandoffSession
host *linuxImportHost
port int
secondary int
handoff *kernelHandoffSession
host *linuxImportHost
port int
closeOnce sync.Once
closeErr error
@@ -850,8 +835,5 @@ func (s *linuxClientSession) Close() error {
}
func (s *linuxClientSession) Description() string {
if s.secondary == 0 {
return fmt.Sprintf("vhci_hcd.0 port %d", s.port)
}
return fmt.Sprintf("vhci_hcd.0 (controller %d) port %d", s.secondary, s.port)
return fmt.Sprintf("vhci_hcd.0 port %d", s.port)
}
+13 -27
View File
@@ -68,13 +68,11 @@ func (d *sysfsDevice) toProtocol() DeviceInfoTruncated {
// vhciStatusRecord is one row of /sys/devices/platform/vhci_hcd.0/status
// or status.N. The kernel emits globally unique port numbers across every
// status* file; secondary identifies which file the row came from
// (0 for status, N for status.N) and exists only for diagnostic logging.
// status* file.
type vhciStatusRecord struct {
secondary int
hub string
port int
state int
hub string
port int
state int
}
func listUSBDevices() ([]sysfsDevice, error) {
@@ -213,8 +211,8 @@ func waitForUsbipStatusCleared(ctx context.Context, busid string) {
// readPrimaryVHCIStatus reads every status* file under
// /sys/devices/platform/vhci_hcd.0 and concatenates the rows in lexical
// order. status reports controller 0; status.N reports controller N.
// Port numbers are already globally unique — no remapping is needed.
// order. Port numbers are already globally unique across controllers — no
// remapping is needed.
func readPrimaryVHCIStatus() ([]vhciStatusRecord, error) {
matches, err := filepath.Glob(filepath.Join(sysVHCIControllerV0, "status*"))
if err != nil {
@@ -223,15 +221,15 @@ func readPrimaryVHCIStatus() ([]vhciStatusRecord, error) {
sort.Strings(matches)
records := make([]vhciStatusRecord, 0)
for _, path := range matches {
secondary, parseErr := vhciSecondaryFromStatusFile(filepath.Base(path))
if parseErr != nil {
base := filepath.Base(path)
if base != "status" && !strings.HasPrefix(base, "status.") {
continue
}
raw, readErr := os.ReadFile(path)
if readErr != nil {
return nil, readErr
}
records = append(records, parseVHCIStatus(secondary, string(raw))...)
records = append(records, parseVHCIStatus(string(raw))...)
}
return records, nil
}
@@ -267,18 +265,7 @@ func vhciPickFreePort(speed uint32, skip map[int]struct{}) (int, error) {
return -1, E.New("no free ", targetHub, " vhci port")
}
func vhciSecondaryFromStatusFile(name string) (int, error) {
if name == "status" {
return 0, nil
}
suffix := strings.TrimPrefix(name, "status.")
if suffix == name {
return 0, E.New("not a status file: ", name)
}
return strconv.Atoi(suffix)
}
func parseVHCIStatus(secondary int, raw string) []vhciStatusRecord {
func parseVHCIStatus(raw string) []vhciStatusRecord {
scanner := bufio.NewScanner(strings.NewReader(raw))
records := make([]vhciStatusRecord, 0)
first := true
@@ -304,10 +291,9 @@ func parseVHCIStatus(secondary int, raw string) []vhciStatusRecord {
continue
}
records = append(records, vhciStatusRecord{
secondary: secondary,
hub: fields[0],
port: port,
state: state,
hub: fields[0],
port: port,
state: state,
})
}
return records