Skip to content

Commit

Permalink
feat: Add optional poll-based ready check
Browse files Browse the repository at this point in the history
  • Loading branch information
pojntfx committed May 18, 2023
1 parent f0a9264 commit 6c1db61
Showing 1 changed file with 86 additions and 33 deletions.
119 changes: 86 additions & 33 deletions pkg/client/nbd.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ import (
"io"
"net"
"os"
"path"
"path/filepath"
"strconv"
"strings"
"syscall"
"time"

"github.com/pilebones/go-udev/netlink"
"github.com/pojntfx/go-nbd/pkg/ioctl"
Expand All @@ -24,10 +29,12 @@ var (
)

type Options struct {
ExportName string
BlockSize uint32
OnConnected func()
Timeout int
ExportName string
BlockSize uint32
OnConnected func()
ReadyCheckUdev bool
ReadyCheckPollInterval time.Duration
Timeout int
}

func negotiateNewstyle(conn net.Conn) error {
Expand Down Expand Up @@ -60,6 +67,10 @@ func Connect(conn net.Conn, device *os.File, options *Options) error {
options.ExportName = "default"
}

if !options.ReadyCheckUdev && options.ReadyCheckPollInterval <= 0 {
options.ReadyCheckPollInterval = time.Millisecond
}

var cfd uintptr
switch c := conn.(type) {
case *net.TCPConn:
Expand All @@ -82,41 +93,83 @@ func Connect(conn net.Conn, device *os.File, options *Options) error {

fatal := make(chan error)
if options.OnConnected != nil {
udevConn := new(netlink.UEventConn)
if err := udevConn.Connect(netlink.UdevEvent); err != nil {
return err
}
defer udevConn.Close()

var (
udevReadyCh = make(chan netlink.UEvent)
udevErrCh = make(chan error)
udevQuit = udevConn.Monitor(udevReadyCh, udevErrCh, &netlink.RuleDefinitions{
Rules: []netlink.RuleDefinition{
{
Env: map[string]string{
"DEVNAME": device.Name(),
if options.ReadyCheckUdev {
udevConn := new(netlink.UEventConn)
if err := udevConn.Connect(netlink.UdevEvent); err != nil {
return err
}
defer udevConn.Close()

var (
udevReadyCh = make(chan netlink.UEvent)
udevErrCh = make(chan error)
udevQuit = udevConn.Monitor(udevReadyCh, udevErrCh, &netlink.RuleDefinitions{
Rules: []netlink.RuleDefinition{
{
Env: map[string]string{
"DEVNAME": device.Name(),
},
},
},
},
})
)
defer close(udevQuit)
})
)
defer close(udevQuit)

go func() {
select {
case <-udevReadyCh:
close(udevQuit)
go func() {
select {
case <-udevReadyCh:
close(udevQuit)

options.OnConnected()
options.OnConnected()

return
case err := <-udevErrCh:
fatal <- err
return
case err := <-udevErrCh:
fatal <- err

return
}
}()
return
}
}()
} else {
go func() {
sizeFile, err := os.Open(path.Join("/sys", "block", filepath.Base(device.Name()), "size"))
if err != nil {
fatal <- err

return
}
defer sizeFile.Close()

for {
if _, err := sizeFile.Seek(0, io.SeekStart); err != nil {
fatal <- err

return
}

rsize, err := io.ReadAll(sizeFile)
if err != nil {
fatal <- err

return
}

size, err := strconv.ParseInt(strings.TrimSpace(string(rsize)), 10, 64)
if err != nil {
fatal <- err

return
}

if size > 0 {
options.OnConnected()

return
}

time.Sleep(options.ReadyCheckPollInterval)
}
}()
}
}

if _, _, err := syscall.Syscall(
Expand Down

0 comments on commit 6c1db61

Please sign in to comment.