@@ -7,7 +7,12 @@ import (
77 "io"
88 "net"
99 "os"
10+ "path"
11+ "path/filepath"
12+ "strconv"
13+ "strings"
1014 "syscall"
15+ "time"
1116
1217 "github.com/pilebones/go-udev/netlink"
1318 "github.com/pojntfx/go-nbd/pkg/ioctl"
@@ -24,10 +29,12 @@ var (
2429)
2530
2631type Options struct {
27- ExportName string
28- BlockSize uint32
29- OnConnected func ()
30- Timeout int
32+ ExportName string
33+ BlockSize uint32
34+ OnConnected func ()
35+ ReadyCheckUdev bool
36+ ReadyCheckPollInterval time.Duration
37+ Timeout int
3138}
3239
3340func negotiateNewstyle (conn net.Conn ) error {
@@ -60,6 +67,10 @@ func Connect(conn net.Conn, device *os.File, options *Options) error {
6067 options .ExportName = "default"
6168 }
6269
70+ if ! options .ReadyCheckUdev && options .ReadyCheckPollInterval <= 0 {
71+ options .ReadyCheckPollInterval = time .Millisecond
72+ }
73+
6374 var cfd uintptr
6475 switch c := conn .(type ) {
6576 case * net.TCPConn :
@@ -82,41 +93,83 @@ func Connect(conn net.Conn, device *os.File, options *Options) error {
8293
8394 fatal := make (chan error )
8495 if options .OnConnected != nil {
85- udevConn := new (netlink.UEventConn )
86- if err := udevConn .Connect (netlink .UdevEvent ); err != nil {
87- return err
88- }
89- defer udevConn .Close ()
90-
91- var (
92- udevReadyCh = make (chan netlink.UEvent )
93- udevErrCh = make (chan error )
94- udevQuit = udevConn .Monitor (udevReadyCh , udevErrCh , & netlink.RuleDefinitions {
95- Rules : []netlink.RuleDefinition {
96- {
97- Env : map [string ]string {
98- "DEVNAME" : device .Name (),
96+ if options .ReadyCheckUdev {
97+ udevConn := new (netlink.UEventConn )
98+ if err := udevConn .Connect (netlink .UdevEvent ); err != nil {
99+ return err
100+ }
101+ defer udevConn .Close ()
102+
103+ var (
104+ udevReadyCh = make (chan netlink.UEvent )
105+ udevErrCh = make (chan error )
106+ udevQuit = udevConn .Monitor (udevReadyCh , udevErrCh , & netlink.RuleDefinitions {
107+ Rules : []netlink.RuleDefinition {
108+ {
109+ Env : map [string ]string {
110+ "DEVNAME" : device .Name (),
111+ },
99112 },
100113 },
101- },
102- })
103- )
104- defer close (udevQuit )
114+ })
115+ )
116+ defer close (udevQuit )
105117
106- go func () {
107- select {
108- case <- udevReadyCh :
109- close (udevQuit )
118+ go func () {
119+ select {
120+ case <- udevReadyCh :
121+ close (udevQuit )
110122
111- options .OnConnected ()
123+ options .OnConnected ()
112124
113- return
114- case err := <- udevErrCh :
115- fatal <- err
125+ return
126+ case err := <- udevErrCh :
127+ fatal <- err
116128
117- return
118- }
119- }()
129+ return
130+ }
131+ }()
132+ } else {
133+ go func () {
134+ sizeFile , err := os .Open (path .Join ("/sys" , "block" , filepath .Base (device .Name ()), "size" ))
135+ if err != nil {
136+ fatal <- err
137+
138+ return
139+ }
140+ defer sizeFile .Close ()
141+
142+ for {
143+ if _ , err := sizeFile .Seek (0 , io .SeekStart ); err != nil {
144+ fatal <- err
145+
146+ return
147+ }
148+
149+ rsize , err := io .ReadAll (sizeFile )
150+ if err != nil {
151+ fatal <- err
152+
153+ return
154+ }
155+
156+ size , err := strconv .ParseInt (strings .TrimSpace (string (rsize )), 10 , 64 )
157+ if err != nil {
158+ fatal <- err
159+
160+ return
161+ }
162+
163+ if size > 0 {
164+ options .OnConnected ()
165+
166+ return
167+ }
168+
169+ time .Sleep (options .ReadyCheckPollInterval )
170+ }
171+ }()
172+ }
120173 }
121174
122175 if _ , _ , err := syscall .Syscall (
0 commit comments