Loopback serves d on a private socket, passing the other end to the kernel to connect to an NBD device. It returns the device-number that the kernel chose. wait should be called to check for errors from serving the device. It blocks until ctx is cancelled or an error occurs (so it behaves like Serve
(ctx context.Context, d Device, size uint64)
| 52 | // |
| 53 | // This is a Linux-only API. |
| 54 | func Loopback(ctx context.Context, d Device, size uint64) (idx uint32, wait func() error, err error) { |
| 55 | sp, err := unix.Socketpair(unix.AF_UNIX, unix.SOCK_STREAM, 0) |
| 56 | if err != nil { |
| 57 | return 0, nil, err |
| 58 | } |
| 59 | exp := Export{ |
| 60 | Size: size, |
| 61 | Device: d, |
| 62 | BlockSizes: &defaultBlockSizes, |
| 63 | Flags: uint16(nbdnl.FlagHasFlags | nbdnl.FlagSendFlush), |
| 64 | } |
| 65 | |
| 66 | client, server := os.NewFile(uintptr(sp[0]), "client"), os.NewFile(uintptr(sp[1]), "server") |
| 67 | serverc, err := net.FileConn(server) |
| 68 | server.Close() |
| 69 | if err != nil { |
| 70 | client.Close() |
| 71 | return 0, nil, err |
| 72 | } |
| 73 | |
| 74 | idx, err = Configure(exp, client) |
| 75 | if err != nil { |
| 76 | client.Close() |
| 77 | return 0, nil, err |
| 78 | } |
| 79 | |
| 80 | var eg errgroup.Group |
| 81 | eg.Go(func() error { |
| 82 | return serve(ctx, serverc, connParameters{exp, defaultBlockSizes}) |
| 83 | }) |
| 84 | wait = func() error { |
| 85 | err := eg.Wait() |
| 86 | // canceling the context is the only way for Loopback to return, so do |
| 87 | // not consider them errors. |
| 88 | if err == context.Canceled || err == context.DeadlineExceeded { |
| 89 | err = nil |
| 90 | } |
| 91 | if e := nbdnl.Disconnect(idx); e != nil && err == nil { |
| 92 | err = fmt.Errorf("failed to disconnect device: %w", e) |
| 93 | } |
| 94 | if e := client.Close(); e != nil && err == nil { |
| 95 | err = fmt.Errorf("failed to close client socket: %w", e) |
| 96 | } |
| 97 | if e := serverc.Close(); e != nil && err == nil { |
| 98 | err = fmt.Errorf("failed to close server connection: %w", e) |
| 99 | } |
| 100 | return err |
| 101 | } |
| 102 | return idx, wait, nil |
| 103 | } |