From c7338a57e21f55b60572411e124b052f4203641e Mon Sep 17 00:00:00 2001 From: Antony Chazapis Date: Wed, 22 Nov 2023 12:09:09 +0200 Subject: [PATCH 01/10] Network block device frontend --- go.mod | 5 + go.sum | 6 + pkg/controller/init_frontend.go | 3 + pkg/frontend/nbd/frontend.go | 270 ++++++++++ pkg/types/types.go | 1 + vendor/github.com/pmorjan/kmod/LICENSE | 22 + vendor/github.com/pmorjan/kmod/README.md | 78 +++ vendor/github.com/pmorjan/kmod/go.work | 6 + vendor/github.com/pmorjan/kmod/kmod_linux.go | 507 ++++++++++++++++++ .../github.com/pmorjan/kmod/status_string.go | 28 + vendor/github.com/pojntfx/go-nbd/LICENSE | 73 +++ .../pojntfx/go-nbd/pkg/backend/backend.go | 11 + .../pojntfx/go-nbd/pkg/backend/file.go | 48 ++ .../pojntfx/go-nbd/pkg/backend/memory.go | 55 ++ .../go-nbd/pkg/protocol/negotiation.go | 65 +++ .../go-nbd/pkg/protocol/transmission.go | 29 + .../pojntfx/go-nbd/pkg/server/nbd.go | 484 +++++++++++++++++ vendor/golang.org/x/sync/LICENSE | 27 + vendor/golang.org/x/sync/PATENTS | 22 + vendor/golang.org/x/sync/errgroup/errgroup.go | 132 +++++ vendor/golang.org/x/sync/errgroup/go120.go | 14 + .../golang.org/x/sync/errgroup/pre_go120.go | 15 + vendor/modules.txt | 12 + 23 files changed, 1913 insertions(+) create mode 100644 pkg/frontend/nbd/frontend.go create mode 100644 vendor/github.com/pmorjan/kmod/LICENSE create mode 100644 vendor/github.com/pmorjan/kmod/README.md create mode 100644 vendor/github.com/pmorjan/kmod/go.work create mode 100644 vendor/github.com/pmorjan/kmod/kmod_linux.go create mode 100644 vendor/github.com/pmorjan/kmod/status_string.go create mode 100644 vendor/github.com/pojntfx/go-nbd/LICENSE create mode 100644 vendor/github.com/pojntfx/go-nbd/pkg/backend/backend.go create mode 100644 vendor/github.com/pojntfx/go-nbd/pkg/backend/file.go create mode 100644 vendor/github.com/pojntfx/go-nbd/pkg/backend/memory.go create mode 100644 vendor/github.com/pojntfx/go-nbd/pkg/protocol/negotiation.go create mode 100644 vendor/github.com/pojntfx/go-nbd/pkg/protocol/transmission.go create mode 100644 vendor/github.com/pojntfx/go-nbd/pkg/server/nbd.go create mode 100644 vendor/golang.org/x/sync/LICENSE create mode 100644 vendor/golang.org/x/sync/PATENTS create mode 100644 vendor/golang.org/x/sync/errgroup/errgroup.go create mode 100644 vendor/golang.org/x/sync/errgroup/go120.go create mode 100644 vendor/golang.org/x/sync/errgroup/pre_go120.go diff --git a/go.mod b/go.mod index a3f1c3cac..ae5e8a7d1 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,8 @@ require ( github.com/longhorn/sparse-tools v0.0.0-20230408015858-c849def39d3c github.com/moby/moby v23.0.2+incompatible github.com/pkg/errors v0.9.1 + github.com/pmorjan/kmod v1.1.0 + github.com/pojntfx/go-nbd v0.3.2 github.com/rancher/go-fibmap v0.0.0-20160418233256-5fc9f8c1ed47 github.com/rancher/go-rancher v0.1.1-0.20190307222549-9756097e5e4c github.com/sirupsen/logrus v1.9.0 @@ -59,6 +61,7 @@ require ( github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect github.com/slok/goresilience v0.2.0 // indirect go.uber.org/multierr v1.11.0 // indirect + golang.org/x/sync v0.4.0 // indirect golang.org/x/text v0.13.0 // indirect google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect google.golang.org/protobuf v1.30.0 // indirect @@ -69,3 +72,5 @@ require ( k8s.io/mount-utils v0.27.1 // indirect k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect ) + +replace github.com/pojntfx/go-nbd => github.com/chazapis/go-nbd v0.0.0-20231031233644-40daa63e22c3 diff --git a/go.sum b/go.sum index 5bd1edf53..079c39079 100644 --- a/go.sum +++ b/go.sum @@ -15,6 +15,8 @@ github.com/c9s/goprocinfo v0.0.0-20190309065803-0b2ad9ac246b h1:4yfM1Zm+7U+m0inJ github.com/c9s/goprocinfo v0.0.0-20190309065803-0b2ad9ac246b/go.mod h1:uEyr4WpAH4hio6LFriaPkL938XnrvLpNPmQHBdrmbIE= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chazapis/go-nbd v0.0.0-20231031233644-40daa63e22c3 h1:5DIm8VSCX68W/CehdyRTPnGMY+W807gpHDSlukpBSO4= +github.com/chazapis/go-nbd v0.0.0-20231031233644-40daa63e22c3/go.mod h1:6rBj1gu9NwR0nOEYJgdafavnKlVBitsdRmAi1GG34Es= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -96,6 +98,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmorjan/kmod v1.1.0 h1:ZLb0WalLhz4ENECpySrXMgRqFfBkoqWju680MWL5X94= +github.com/pmorjan/kmod v1.1.0/go.mod h1:iGxkdcq8DCjMw61SXKPMxG7taOrEqjNTIQPPgfvgX88= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v1.15.0 h1:5fCgGYogn0hFdhyhLbw7hEsWxufKtY9klyvdNfFlFhM= github.com/prometheus/client_golang v1.15.0/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= @@ -156,6 +160,8 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/pkg/controller/init_frontend.go b/pkg/controller/init_frontend.go index f17ad25e5..c3bf7b964 100644 --- a/pkg/controller/init_frontend.go +++ b/pkg/controller/init_frontend.go @@ -8,6 +8,7 @@ import ( "github.com/longhorn/longhorn-engine/pkg/frontend/rest" "github.com/longhorn/longhorn-engine/pkg/frontend/socket" "github.com/longhorn/longhorn-engine/pkg/frontend/tgt" + "github.com/longhorn/longhorn-engine/pkg/frontend/nbd" "github.com/longhorn/longhorn-engine/pkg/types" "github.com/sirupsen/logrus" ) @@ -31,6 +32,8 @@ func NewFrontend(frontendType string, iscsiTargetRequestTimeout time.Duration) ( return tgt.New(devtypes.FrontendTGTBlockDev, defaultScsiTimeout, defaultIscsiAbortTimeout, iscsiTargetRequestTimeout), nil case devtypes.FrontendTGTISCSI: return tgt.New(devtypes.FrontendTGTISCSI, defaultScsiTimeout, defaultIscsiAbortTimeout, iscsiTargetRequestTimeout), nil + case "nbd": + return nbd.New(), nil default: return nil, fmt.Errorf("unsupported frontend type: %v", frontendType) } diff --git a/pkg/frontend/nbd/frontend.go b/pkg/frontend/nbd/frontend.go new file mode 100644 index 000000000..0a13934dc --- /dev/null +++ b/pkg/frontend/nbd/frontend.go @@ -0,0 +1,270 @@ +package nbd + +import ( + "fmt" + "net" + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + nbd "github.com/pojntfx/go-nbd/pkg/server" + "github.com/pmorjan/kmod" + + "github.com/longhorn/longhorn-engine/pkg/types" +) + +const ( + frontendName = "nbd" + + SocketDirectory = "/var/run" + DeviceDirectory = "/dev/longhorn/" +) + +type Nbd struct { + Volume string + Size int64 + SectorSize int + + isUp bool + socketPath string + nbdDevicePath string + clients int +} + +func New() types.Frontend { + return &Nbd{} +} + +func (n *Nbd) FrontendName() string { + return frontendName +} + +func (n *Nbd) Init(name string, size, sectorSize int64) error { + n.Volume = name + n.Size = size + n.SectorSize = int(sectorSize) + + return n.Shutdown() +} + +func (n *Nbd) Startup(rwu types.ReaderWriterUnmapperAt) error { + if err := n.startNbdServer(rwu); err != nil { + return err + } + n.isUp = true + + // Load nbd module + k, err := kmod.New() + if err != nil { + return err + } + if err := k.Load("nbd", "", 0); err != nil { + return err + } + + // Connect device + n.nbdDevicePath, err = n.getNextFreeNbdDevice() + if err != nil { + return err + } + args := strings.Fields(fmt.Sprintf("/usr/sbin/nbd-client -u %s -b 4096 %s -C 2", n.GetSocketPath(), n.nbdDevicePath)) + cmd := exec.Command(args[0], args[1:]...) + if err := cmd.Run(); err != nil { + return err + } + + // Create symlink + devicePath := n.GetDevicePath() + logrus.Infof("linking %v to %v", devicePath, n.nbdDevicePath) + if err := os.MkdirAll(DeviceDirectory, os.ModePerm); err != nil { + return err + } + if _, err := os.Lstat(devicePath); err == nil { + os.Remove(devicePath) + } + if err := os.Symlink(n.nbdDevicePath, devicePath); err != nil { + return err + } + + return nil +} + +func (n *Nbd) getNextFreeNbdDevice() (string, error) { + var nbdDevicePath string + for i := 0; i < 16; i++ { + nbdDevicePath = fmt.Sprintf("/dev/nbd%d", i) + args := strings.Fields(fmt.Sprintf("/usr/sbin/nbd-client -c %s", nbdDevicePath)) + cmd := exec.Command(args[0], args[1:]...) + if err := cmd.Run(); err != nil { + return nbdDevicePath, nil + } + } + return "", fmt.Errorf("no more nbd devices") +} + + +func (n *Nbd) Shutdown() error { + if n.Volume == "" || !n.isUp { + return nil + } + + // Disconnect device + args := strings.Fields(fmt.Sprintf("/usr/sbin/nbd-client -d %s", n.nbdDevicePath)) + cmd := exec.Command(args[0], args[1:]...) + if err := cmd.Run(); err != nil { + return err + } + + // Delete symlink + devicePath := n.GetDevicePath() + if _, err := os.Lstat(devicePath); err == nil { + os.Remove(devicePath) + } + + if n.Volume != "" { + logrus.Warnf("Shutting down nbd server for %v", n.Volume) + } + n.isUp = false + + return nil +} + +func (n *Nbd) State() types.State { + if n.isUp { + return types.StateUp + } + return types.StateDown +} + +func (n *Nbd) Endpoint() string { + if n.isUp { + return n.GetSocketPath() + } + return "" +} + +func (n *Nbd) GetSocketPath() string { + if n.Volume == "" { + panic("Invalid volume name") + } + return filepath.Join(SocketDirectory, "longhorn-nbd-"+n.Volume+".sock") +} + +func (n *Nbd) GetDevicePath() string { + if n.Volume == "" { + panic("Invalid volume name") + } + return filepath.Join(DeviceDirectory, n.Volume) +} + +func (n *Nbd) startNbdServer(rwu types.ReaderWriterUnmapperAt) error { + socketPath := n.GetSocketPath() + if err := os.MkdirAll(filepath.Dir(socketPath), 0700); err != nil { + return errors.Wrapf(err, "cannot create directory %v", filepath.Dir(socketPath)) + } + // Check and remove existing socket + if st, err := os.Stat(socketPath); err == nil && !st.IsDir() { + if err := os.Remove(socketPath); err != nil { + return err + } + } + + n.socketPath = socketPath + go n.startNbdServerListen(rwu) + return nil +} + +func (n *Nbd) startNbdServerListen(rwu types.ReaderWriterUnmapperAt) error { + ln, err := net.Listen("unix", n.socketPath) + if err != nil { + return err + } + defer ln.Close() + + for { + conn, err := ln.Accept() + if err != nil { + logrus.WithError(err).Error("Failed to accept nbd connection") + continue + } + + n.clients++ + + logrus.Infof("%v clients connected", n.clients) + + go n.handleServerConnection(conn, rwu) + } +} + +func (n *Nbd) handleServerConnection(conn net.Conn, rwu types.ReaderWriterUnmapperAt) { + defer func() { + conn.Close() + + n.clients-- + + if err := recover(); err != nil { + logrus.Infof("Client disconnected with error: %v", err) + } + + logrus.Infof("%v clients connected", n.clients) + }() + + b := NewNbdBackend(rwu, n.Size) + + if err := nbd.Handle( + conn, + []*nbd.Export{ + { + Name: "", + Description: "Longhorn volume", + Backend: b, + }, + }, + &nbd.Options{ + ReadOnly: false, + MinimumBlockSize: 4096, + PreferredBlockSize: 4096, + MaximumBlockSize: 4096, + }); err != nil { + logrus.WithError(err).Errorf("Failed to handle nbd connection") + } +} + +type NbdBackend struct { + rwu types.ReaderWriterUnmapperAt + size int64 +} + +func NewNbdBackend(rwu types.ReaderWriterUnmapperAt, size int64) *NbdBackend { + return &NbdBackend{ + rwu: rwu, + size: size, + } +} + +func (b *NbdBackend) ReadAt(p []byte, off int64) (n int, err error) { + return b.rwu.ReadAt(p, off) +} + +func (b *NbdBackend) WriteAt(p []byte, off int64) (n int, err error) { + return b.rwu.WriteAt(p, off) +} + +func (b *NbdBackend) Size() (int64, error) { + return b.size, nil +} + +func (b *NbdBackend) Sync() error { + return nil +} + +func (n *Nbd) Upgrade(name string, size, sectorSize int64, rwu types.ReaderWriterUnmapperAt) error { + return fmt.Errorf("upgrade is not supported") +} + +func (n *Nbd) Expand(size int64) error { + return fmt.Errorf("expand is not supported") +} diff --git a/pkg/types/types.go b/pkg/types/types.go index 9f1dae264..c0d560ebc 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -42,6 +42,7 @@ const ( EngineFrontendBlockDev = "tgt-blockdev" EngineFrontendISCSI = "tgt-iscsi" + EngineFrontendNbd = "nbd" VolumeHeadName = "volume-head" ) diff --git a/vendor/github.com/pmorjan/kmod/LICENSE b/vendor/github.com/pmorjan/kmod/LICENSE new file mode 100644 index 000000000..dcab740f4 --- /dev/null +++ b/vendor/github.com/pmorjan/kmod/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2020 Peter Morjan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/vendor/github.com/pmorjan/kmod/README.md b/vendor/github.com/pmorjan/kmod/README.md new file mode 100644 index 000000000..edf00a895 --- /dev/null +++ b/vendor/github.com/pmorjan/kmod/README.md @@ -0,0 +1,78 @@ +[![GoDoc](https://godoc.org/github.com/pmorjan/kmod?status.svg)](https://godoc.org/github.com/pmorjan/kmod) + +# kmod + +A Go implementation of functions to load and unload Linux kernel modules. + +Module dependencies are loaded / unloaded automatically as defined in +`/modules.dep`. +Kmod uses the syscall finit_module(2) to load a kernel file into the kernel +and if that fails init_module(2). Compressed files are not supported +directly but users can provide a custom function to uncompress and load a module +file into the kernel. (**SetInitFunc**). This is to keep the number of external +dependencies low and also allows maximum flexibility. + +See the simple examples below and [modprobe.go](cmd/modprobe/modprobe.go) +for an complete example. + +```go +// Load uncompressed kernel module +package main + +import ( + "log" + + "github.com/pmorjan/kmod" +) + +func main() { + k, err := kmod.New() + if err != nil { + log.Fatal(err) + } + if err := k.Load("brd", "rd_size=32768 rd_nr=16", 0); err != nil { + log.Fatal(err) + } +} +``` + +```go +// Load XZ compressed module +package main + +import ( + "io/ioutil" + "log" + "os" + + "github.com/pmorjan/kmod" + "github.com/ulikunitz/xz" + "golang.org/x/sys/unix" +) + +func main() { + k, err := kmod.New(kmod.SetInitFunc(modInit)) + if err != nil { + log.Fatal(err) + } + if err := k.Load("brd", "rd_size=32768 rd_nr=16", 0); err != nil { + log.Fatal(err) + } +} + +func modInit(path, params string, flags int) error { + f, err := os.Open(path) + if err != nil { + return err + } + rd, err := xz.NewReader(f) + if err != nil { + return err + } + buf, err := ioutil.ReadAll(rd) + if err != nil { + return err + } + return unix.InitModule(buf, params) +} +``` diff --git a/vendor/github.com/pmorjan/kmod/go.work b/vendor/github.com/pmorjan/kmod/go.work new file mode 100644 index 000000000..3a3836275 --- /dev/null +++ b/vendor/github.com/pmorjan/kmod/go.work @@ -0,0 +1,6 @@ +go 1.18 + +use ( + . + ./cmd/modprobe +) diff --git a/vendor/github.com/pmorjan/kmod/kmod_linux.go b/vendor/github.com/pmorjan/kmod/kmod_linux.go new file mode 100644 index 000000000..1d4cf1b12 --- /dev/null +++ b/vendor/github.com/pmorjan/kmod/kmod_linux.go @@ -0,0 +1,507 @@ +//go:generate stringer -type status + +// Package kmod provides functions to load and unload Linux kernel modules. +// +// Module dependencies are loaded / unloaded automatically according to /modules.dep. +// Compressed module files can be loaded via a custom InitFunc provided by the caller. +// See SetInitFunc and cmd/modprobe for details. +// +package kmod + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "io" + "log" + "os" + "path/filepath" + "strings" + + "golang.org/x/sys/unix" +) + +// ErrModuleNotFound is the error resulting if a module can't be found. +var ErrModuleNotFound = errors.New("module not found") + +// ErrModuleInUse is the error resulting if a module can't be unloaded because +// it is in use. +var ErrModuleInUse = errors.New("module is in use") + +// InitFunc provides a hook to load a kernel module into the kernel. +type InitFunc func(filename string, params string, flags int) error + +// Kmod represents internal configuration +type Kmod struct { + dryrun bool + ignoreAlias bool + ignoreBuiltin bool + ignoreStatus bool + modConfig string + modDir string + modInitFunc InitFunc + modRootdir string + verbose bool +} + +// Option configures Kmod. +type Option func(*Kmod) + +// SetDryrun returns an Option that specifies to do everything but actually load or unload. +func SetDryrun() Option { return func(k *Kmod) { k.dryrun = true } } + +// SetIgnoreAlias returns an Option that specifies not to consult modules.alias +// to resolve aliases. +func SetIgnoreAlias() Option { return func(k *Kmod) { k.ignoreAlias = true } } + +// SetIgnoreBuiltin returns an Option that specifies not to consult modules.builtin +// to find built-in modules. +func SetIgnoreBuiltin() Option { return func(k *Kmod) { k.ignoreBuiltin = true } } + +// SetIgnoreStatus returns an Option that specifies not to consult /proc/modules +// to get the current status of a module. +func SetIgnoreStatus() Option { return func(k *Kmod) { k.ignoreStatus = true } } + +// SetInitFunc returns an Option that sets fn to be used for loading module files +// into the kernel. The default function tries to use finit_module(2) first and if that +// failes init_module(2). To support compressed module files see the example cmd/modprobe. +func SetInitFunc(fn InitFunc) Option { + return func(k *Kmod) { k.modInitFunc = fn } +} + +// SetConfigFile returns an Option that specifies the (optional) configuration file +// for modules, default: /etc/modprobe.conf. The config file is used only for module +// parameters. +// options parameter [parameter]... +func SetConfigFile(path string) Option { + return func(k *Kmod) { k.modConfig = path } +} + +// SetRootDir returns an Option that sets dir as root directory for modules, +// default: /lib/modules +func SetRootDir(dir string) Option { return func(k *Kmod) { k.modRootdir = dir } } + +// SetVerbose returns an Option that specifies to log info messages about what's going on. +func SetVerbose() Option { return func(k *Kmod) { k.verbose = true } } + +// New returns a new Kmod. +func New(opts ...Option) (*Kmod, error) { + k := &Kmod{ + modConfig: "/etc/modprobe.conf", + modRootdir: "/lib/modules", + } + for _, opt := range opts { + opt(k) + } + + var u unix.Utsname + if err := unix.Uname(&u); err != nil { + return nil, err + } + rel := string(u.Release[:bytes.IndexByte(u.Release[:], 0)]) + k.modDir = filepath.Join(k.modRootdir, rel) + + if _, err := os.Stat(filepath.Join(k.modDir, "modules.dep")); err != nil { + return nil, err + } + return k, nil +} + +// Load loads a kernel module. If the module depends on other modules +// Load will try to load all dependencies first. +func (k *Kmod) Load(name, params string, flags int) error { + name = cleanName(name) + + realname, err := k.checkAlias(name) + if err != nil { + return fmt.Errorf("get alias %s failed: %w", name, err) + } + if realname != "" { + k.infof("%s is alias for %s", name, realname) + name = realname + } + + builtin, err := k.isBuiltin(name) + if err != nil { + return fmt.Errorf("check builtin %s failed: %w", name, err) + } + if builtin { + k.infof("%s is builtin", name) + return nil + } + + modules, err := k.modDeps(name) + if err != nil { + return err + } + + if err := k.applyConfig(modules); err != nil { + return err + } + modules[0].params += " " + params + modules[0].flags = flags + + // load dependencies first, ignore errors + for i := len(modules) - 1; i > 0; i-- { + _ = k.load(modules[i]) + } + + // load target module, check error + err = k.load(modules[0]) + if errors.Is(err, unix.EEXIST) { + return nil + } + if err != nil { + return fmt.Errorf("load %s failed: %w", modules[0].name, err) + } + return nil +} + +// Unload unloads a module from the kernel. Unload also tries to unload all +// module dependencies that are no longer in use. +func (k *Kmod) Unload(name string) error { + name = cleanName(name) + + alias, err := k.checkAlias(name) + if err != nil { + return fmt.Errorf("check alias %s failed: %w", name, err) + } + if alias != "" { + k.infof("%s is alias for %s", name, alias) + name = alias + } + + builtin, err := k.isBuiltin(name) + if err != nil { + return fmt.Errorf("check builtin %s failed: %w", name, err) + } + if builtin { + k.infof("%s is builtin", name) + return nil + } + + modules, err := k.modDeps(name) + if err != nil { + return err + } + + // unload target module, check error + if err := k.unload(modules[0]); err != nil { + if err == unix.EBUSY || err == unix.EAGAIN { + return ErrModuleInUse + } + if err != unix.ENOENT { + return err + } + } + + // unload dependencies, ignore errors + for i := 1; i < len(modules); i++ { + _ = k.unload(modules[i]) + } + + return nil +} + +// Dependencies returns a list of module dependencies. +func (k *Kmod) Dependencies(name string) ([]string, error) { + name = cleanName(name) + + realname, err := k.checkAlias(name) + if err != nil { + return nil, fmt.Errorf("get alias %s failed: %w", name, err) + } + if realname != "" { + k.infof("%s is alias for %s", name, realname) + name = realname + } + + builtin, err := k.isBuiltin(name) + if err != nil { + return nil, fmt.Errorf("check builtin %s failed: %w", name, err) + } + if builtin { + return nil, fmt.Errorf("%s is builtin", name) + } + + modules, err := k.modDeps(name) + if err != nil { + return nil, err + } + + var list []string + for i := len(modules) - 1; i >= 0; i-- { + list = append(list, modules[i].path) + } + + return list, nil +} + +func (k *Kmod) isBuiltin(name string) (bool, error) { + if k.ignoreBuiltin { + return false, nil + } + f, err := os.Open(filepath.Join(k.modDir, "modules.builtin")) + if err != nil { + return false, err + } + defer f.Close() + + var found bool + scanner := bufio.NewScanner(f) + for scanner.Scan() { + line := scanner.Text() + if pathToName(line) == name { + found = true + break + } + } + if err := scanner.Err(); err != nil { + return false, err + } + return found, nil +} + +type module struct { + name string + path string + params string + flags int +} + +type status int + +const ( + unknown status = iota + unloaded + unloading + loading + live + inuse +) + +// /proc/modules +// name | memory size | reference count | references | state: +// macvlan 28672 1 macvtap, Live 0x0000000000000000 +func (k *Kmod) modStatus(name string) (status, error) { + var state status = unknown + if k.ignoreStatus { + return state, nil + } + f, err := os.Open("/proc/modules") + if err != nil { + return state, err + } + defer f.Close() + + state = unloaded + + scanner := bufio.NewScanner(f) + for scanner.Scan() { + fields := strings.Fields(scanner.Text()) + if fields[0] == name { + if fields[2] != "0" { + state = inuse + break + } + switch fields[4] { + case "Live": + state = live + case "Loading": + state = loading + case "Unloading": + state = unloading + } + break + } + } + if err := scanner.Err(); err != nil { + return state, err + } + + return state, nil +} + +// modules.alias +// alias fs-xfs xfs +func (k *Kmod) checkAlias(name string) (string, error) { + if k.ignoreAlias { + return "", nil + } + f, err := os.Open(filepath.Join(k.modDir, "modules.alias")) + if err != nil { + return "", err + } + defer f.Close() + + var realname string + scanner := bufio.NewScanner(f) + for scanner.Scan() { + line := scanner.Text() + if strings.HasPrefix(line, "#") { + continue + } + fields := strings.Fields(line) + if len(fields) >= 3 { + if cleanName(fields[1]) == name { + realname = fields[2] + break + } + } + } + if err := scanner.Err(); err != nil { + return "", err + } + + return realname, nil +} + +// modDeps returns a module and all its depenencies +func (k *Kmod) modDeps(name string) ([]module, error) { + f, err := os.Open(filepath.Join(k.modDir, "modules.dep")) + if err != nil { + return nil, err + } + defer f.Close() + + var deps []string + scanner := bufio.NewScanner(f) + for scanner.Scan() { + line := scanner.Text() + fields := strings.Fields(line) + if pathToName(strings.TrimSuffix(fields[0], ":")) == name { + deps = fields + break + } + } + if err := scanner.Err(); err != nil { + return nil, err + } + + if len(deps) == 0 { + return nil, ErrModuleNotFound + } + deps[0] = strings.TrimSuffix(deps[0], ":") + + var modules []module + for _, v := range deps { + modules = append(modules, module{ + name: pathToName(v), + path: filepath.Join(k.modDir, v), + }) + } + + return modules, nil +} + +// modprobe.conf +// options option [option]... +func (k *Kmod) applyConfig(modules []module) error { + if k.modConfig == "" { + return nil + } + f, err := os.Open(k.modConfig) + if os.IsNotExist(err) { + return nil + } + if err != nil { + return err + } + defer f.Close() + + scanner := bufio.NewScanner(f) + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + if strings.HasPrefix(line, "#") { + continue + } + fields := strings.Fields(line) + if len(fields) < 3 || fields[0] != "options" { + continue + } + name := cleanName(fields[1]) + for i, m := range modules { + if m.name == name { + m.params = strings.Join(fields[2:], " ") + modules[i] = m + break + } + } + } + return scanner.Err() +} + +func (k *Kmod) load(m module) error { + state, err := k.modStatus(m.name) + if err != nil { + return err + } + if state >= loading { + return nil + } + if k.dryrun { + return nil + } + k.infof("loading %s %s %s", m.name, m.path, m.params) + + if k.modInitFunc != nil { + return k.modInitFunc(m.path, m.params, m.flags) + } + + f, err := os.Open(m.path) + if err != nil { + return err + } + defer f.Close() + + // first try finit_module(2), then init_module(2) + err = unix.FinitModule(int(f.Fd()), m.params, m.flags) + if errors.Is(err, unix.ENOSYS) { + if m.flags != 0 { + return err + } + buf, err := io.ReadAll(f) + if err != nil { + return err + } + return unix.InitModule(buf, m.params) + } + return err +} + +func (k *Kmod) unload(m module) error { + state, err := k.modStatus(m.name) + if err != nil { + return err + } + if state == unloading || state == unloaded { + return nil + } + if state == inuse { + return ErrModuleInUse + } + if k.dryrun { + return nil + } + k.infof("unloading %s", m.name) + return unix.DeleteModule(m.name, 0) +} + +func (k *Kmod) infof(format string, a ...interface{}) { + if k.verbose { + log.Printf(format, a...) + } +} + +func cleanName(s string) string { + return strings.ReplaceAll(strings.TrimSpace(s), "-", "_") +} + +func pathToName(s string) string { + s = filepath.Base(s) + for ext := filepath.Ext(s); ext != ""; ext = filepath.Ext(s) { + s = strings.TrimSuffix(s, ext) + } + return cleanName(s) +} diff --git a/vendor/github.com/pmorjan/kmod/status_string.go b/vendor/github.com/pmorjan/kmod/status_string.go new file mode 100644 index 000000000..38535c4f4 --- /dev/null +++ b/vendor/github.com/pmorjan/kmod/status_string.go @@ -0,0 +1,28 @@ +// Code generated by "stringer -type status"; DO NOT EDIT. + +package kmod + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[unknown-0] + _ = x[unloaded-1] + _ = x[unloading-2] + _ = x[loading-3] + _ = x[live-4] + _ = x[inuse-5] +} + +const _status_name = "unknownunloadedunloadingloadingliveinuse" + +var _status_index = [...]uint8{0, 7, 15, 24, 31, 35, 40} + +func (i status) String() string { + if i < 0 || i >= status(len(_status_index)-1) { + return "status(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _status_name[_status_index[i]:_status_index[i+1]] +} diff --git a/vendor/github.com/pojntfx/go-nbd/LICENSE b/vendor/github.com/pojntfx/go-nbd/LICENSE new file mode 100644 index 000000000..137069b82 --- /dev/null +++ b/vendor/github.com/pojntfx/go-nbd/LICENSE @@ -0,0 +1,73 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/github.com/pojntfx/go-nbd/pkg/backend/backend.go b/vendor/github.com/pojntfx/go-nbd/pkg/backend/backend.go new file mode 100644 index 000000000..53141c174 --- /dev/null +++ b/vendor/github.com/pojntfx/go-nbd/pkg/backend/backend.go @@ -0,0 +1,11 @@ +package backend + +import "io" + +type Backend interface { + io.ReaderAt + io.WriterAt + + Size() (int64, error) + Sync() error +} diff --git a/vendor/github.com/pojntfx/go-nbd/pkg/backend/file.go b/vendor/github.com/pojntfx/go-nbd/pkg/backend/file.go new file mode 100644 index 000000000..eee21911f --- /dev/null +++ b/vendor/github.com/pojntfx/go-nbd/pkg/backend/file.go @@ -0,0 +1,48 @@ +package backend + +import ( + "os" + "sync" +) + +type FileBackend struct { + file *os.File + lock sync.RWMutex +} + +func NewFileBackend(file *os.File) *FileBackend { + return &FileBackend{file, sync.RWMutex{}} +} + +func (b *FileBackend) ReadAt(p []byte, off int64) (n int, err error) { + b.lock.RLock() + + n, err = b.file.ReadAt(p, off) + + b.lock.RUnlock() + + return +} + +func (b *FileBackend) WriteAt(p []byte, off int64) (n int, err error) { + b.lock.Lock() + + n, err = b.file.WriteAt(p, off) + + b.lock.Unlock() + + return +} + +func (b *FileBackend) Size() (int64, error) { + stat, err := b.file.Stat() + if err != nil { + return -1, err + } + + return stat.Size(), nil +} + +func (b *FileBackend) Sync() error { + return b.file.Sync() +} diff --git a/vendor/github.com/pojntfx/go-nbd/pkg/backend/memory.go b/vendor/github.com/pojntfx/go-nbd/pkg/backend/memory.go new file mode 100644 index 000000000..164ed7217 --- /dev/null +++ b/vendor/github.com/pojntfx/go-nbd/pkg/backend/memory.go @@ -0,0 +1,55 @@ +package backend + +import ( + "io" + "sync" +) + +type MemoryBackend struct { + memory []byte + lock sync.Mutex +} + +func NewMemoryBackend(memory []byte) *MemoryBackend { + return &MemoryBackend{memory, sync.Mutex{}} +} + +func (b *MemoryBackend) ReadAt(p []byte, off int64) (n int, err error) { + b.lock.Lock() + + if off >= int64(len(b.memory)) { + return 0, io.EOF + } + + n = copy(p, b.memory[off:off+int64(len(p))]) + + b.lock.Unlock() + + return +} + +func (b *MemoryBackend) WriteAt(p []byte, off int64) (n int, err error) { + b.lock.Lock() + + if off >= int64(len(b.memory)) { + return 0, io.EOF + } + + n = copy(b.memory[off:off+int64(len(p))], p) + + if n < len(p) { + return n, io.ErrShortWrite + } + + b.lock.Unlock() + + return +} + +func (b *MemoryBackend) Size() (int64, error) { + return int64(len(b.memory)), nil +} + +func (b *MemoryBackend) Sync() error { + return nil +} diff --git a/vendor/github.com/pojntfx/go-nbd/pkg/protocol/negotiation.go b/vendor/github.com/pojntfx/go-nbd/pkg/protocol/negotiation.go new file mode 100644 index 000000000..e256cd86c --- /dev/null +++ b/vendor/github.com/pojntfx/go-nbd/pkg/protocol/negotiation.go @@ -0,0 +1,65 @@ +package protocol + +// See https://github.com/NetworkBlockDevice/nbd/blob/master/doc/proto.md and https://github.com/abligh/gonbdserver/ + +const ( + NEGOTIATION_MAGIC_OLDSTYLE = uint64(0x4e42444d41474943) + NEGOTIATION_MAGIC_OPTION = uint64(0x49484156454F5054) + NEGOTIATION_MAGIC_REPLY = uint64(0x3e889045565a9) + + NEGOTIATION_HANDSHAKE_FLAG_FIXED_NEWSTYLE = uint16(1 << 0) + + NEGOTIATION_ID_OPTION_ABORT = uint32(2) + NEGOTIATION_ID_OPTION_LIST = uint32(3) + NEGOTIATION_ID_OPTION_INFO = uint32(6) + NEGOTIATION_ID_OPTION_GO = uint32(7) + + NEGOTIATION_TYPE_REPLY_ACK = uint32(1) + NEGOTIATION_TYPE_REPLY_SERVER = uint32(2) + NEGOTIATION_TYPE_REPLY_INFO = uint32(3) + NEGOTIATION_TYPE_REPLY_ERR_UNSUPPORTED = uint32(1 | uint32(1<<31)) + NEGOTIATION_TYPE_REPLY_ERR_UNKNOWN = uint32(6 | uint32(1<<31)) + + NEGOTIATION_TYPE_INFO_EXPORT = uint16(0) + NEGOTIATION_TYPE_INFO_NAME = uint16(1) + NEGOTIATION_TYPE_INFO_DESCRIPTION = uint16(2) + NEGOTIATION_TYPE_INFO_BLOCKSIZE = uint16(3) +) + +type NegotiationNewstyleHeader struct { + OldstyleMagic uint64 + OptionMagic uint64 + HandshakeFlags uint16 +} + +type NegotiationOptionHeader struct { + OptionMagic uint64 + ID uint32 + Length uint32 +} + +type NegotiationReplyHeader struct { + ReplyMagic uint64 + ID uint32 + Type uint32 + Length uint32 +} + +type NegotiationReplyInfo struct { + Type uint16 + Size uint64 + TransmissionFlags uint16 +} + +type NegotiationReplyNameHeader struct { + Type uint16 +} + +type NegotiationReplyDescriptionHeader NegotiationReplyNameHeader + +type NegotiationReplyBlockSize struct { + Type uint16 + MinimumBlockSize uint32 + PreferredBlockSize uint32 + MaximumBlockSize uint32 +} diff --git a/vendor/github.com/pojntfx/go-nbd/pkg/protocol/transmission.go b/vendor/github.com/pojntfx/go-nbd/pkg/protocol/transmission.go new file mode 100644 index 000000000..2a2c8241a --- /dev/null +++ b/vendor/github.com/pojntfx/go-nbd/pkg/protocol/transmission.go @@ -0,0 +1,29 @@ +package protocol + +const ( + TRANSMISSION_MAGIC_REQUEST = uint32(0x25609513) + TRANSMISSION_MAGIC_REPLY = uint32(0x67446698) + + TRANSMISSION_TYPE_REQUEST_READ = uint16(0) + TRANSMISSION_TYPE_REQUEST_WRITE = uint16(1) + TRANSMISSION_TYPE_REQUEST_DISC = uint16(2) + + TRANSMISSION_ERROR_EPERM = uint32(1) + TRANSMISSION_ERROR_EIO = uint32(5) + TRANSMISSION_ERROR_EINVAL = uint32(22) +) + +type TransmissionRequestHeader struct { + RequestMagic uint32 + CommandFlags uint16 + Type uint16 + Handle uint64 + Offset uint64 + Length uint32 +} + +type TransmissionReplyHeader struct { + ReplyMagic uint32 + Error uint32 + Handle uint64 +} diff --git a/vendor/github.com/pojntfx/go-nbd/pkg/server/nbd.go b/vendor/github.com/pojntfx/go-nbd/pkg/server/nbd.go new file mode 100644 index 000000000..fa990a8fa --- /dev/null +++ b/vendor/github.com/pojntfx/go-nbd/pkg/server/nbd.go @@ -0,0 +1,484 @@ +package server + +import ( + "bytes" + "encoding/binary" + "context" + "errors" + "io" + "net" + "time" + + "golang.org/x/sync/errgroup" + + "github.com/pojntfx/go-nbd/pkg/backend" + "github.com/pojntfx/go-nbd/pkg/protocol" +) + +var ( + ErrInvalidMagic = errors.New("invalid magic") + ErrInvalidBlocksize = errors.New("invalid blocksize") +) + +const ( + maximumPacketSize = 32 * 1024 * 1024 // Support for a 32M maximum packet size is expected: https://sourceforge.net/p/nbd/mailman/message/35081223/ +) + +type Export struct { + Name string + Description string + + Backend backend.Backend +} + +type Options struct { + ReadOnly bool + MinimumBlockSize uint32 + PreferredBlockSize uint32 + MaximumBlockSize uint32 +} + +func Handle(conn net.Conn, exports []*Export, options *Options) error { + if options == nil { + options = &Options{ + ReadOnly: false, + } + } + + if options.MinimumBlockSize == 0 { + options.MinimumBlockSize = 1 + } + + if options.PreferredBlockSize == 0 { + options.PreferredBlockSize = 4096 + } + + if options.MaximumBlockSize == 0 { + options.MaximumBlockSize = maximumPacketSize + } + + // Negotiation + if err := binary.Write(conn, binary.BigEndian, protocol.NegotiationNewstyleHeader{ + OldstyleMagic: protocol.NEGOTIATION_MAGIC_OLDSTYLE, + OptionMagic: protocol.NEGOTIATION_MAGIC_OPTION, + HandshakeFlags: protocol.NEGOTIATION_HANDSHAKE_FLAG_FIXED_NEWSTYLE, + }); err != nil { + return err + } + + _, err := io.CopyN(io.Discard, conn, 4) // Discard client flags (uint32) + if err != nil { + return err + } + + var export *Export +n: + for { + var optionHeader protocol.NegotiationOptionHeader + if err := binary.Read(conn, binary.BigEndian, &optionHeader); err != nil { + return err + } + + if optionHeader.OptionMagic != protocol.NEGOTIATION_MAGIC_OPTION { + return ErrInvalidMagic + } + + switch optionHeader.ID { + case protocol.NEGOTIATION_ID_OPTION_INFO, protocol.NEGOTIATION_ID_OPTION_GO: + var exportNameLength uint32 + if err := binary.Read(conn, binary.BigEndian, &exportNameLength); err != nil { + return err + } + + exportName := make([]byte, exportNameLength) + if _, err := io.ReadFull(conn, exportName); err != nil { + return err + } + + for _, candidate := range exports { + if candidate.Name == string(exportName) { + export = candidate + + break + } + } + + if export == nil { + if length := int64(optionHeader.Length) - 4 - int64(exportNameLength); length > 0 { // Discard the option's data, minus the export name length and export name we've already read + _, err := io.CopyN(io.Discard, conn, length) + if err != nil { + return err + } + } + + if err := binary.Write(conn, binary.BigEndian, protocol.NegotiationReplyHeader{ + ReplyMagic: protocol.NEGOTIATION_MAGIC_REPLY, + ID: optionHeader.ID, + Type: protocol.NEGOTIATION_TYPE_REPLY_ERR_UNKNOWN, + Length: 0, + }); err != nil { + return err + } + + break + } + + size, err := export.Backend.Size() + if err != nil { + return err + } + + { + var informationRequestCount uint16 + if err := binary.Read(conn, binary.BigEndian, &informationRequestCount); err != nil { + return err + } + + _, err := io.CopyN(io.Discard, conn, 2*int64(informationRequestCount)) // Discard information requests (uint16s) + if err != nil { + return err + } + } + + { + info := &bytes.Buffer{} + if err := binary.Write(info, binary.BigEndian, protocol.NegotiationReplyInfo{ + Type: protocol.NEGOTIATION_TYPE_INFO_EXPORT, + Size: uint64(size), + TransmissionFlags: 0b1000_0001_0000_0000, + }); err != nil { + return err + } + + if err := binary.Write(conn, binary.BigEndian, protocol.NegotiationReplyHeader{ + ReplyMagic: protocol.NEGOTIATION_MAGIC_REPLY, + ID: optionHeader.ID, + Type: protocol.NEGOTIATION_TYPE_REPLY_INFO, + Length: uint32(info.Len()), + }); err != nil { + return err + } + + if _, err := io.Copy(conn, info); err != nil { + return err + } + } + + { + info := &bytes.Buffer{} + if err := binary.Write(info, binary.BigEndian, protocol.NegotiationReplyNameHeader{ + Type: protocol.NEGOTIATION_TYPE_INFO_NAME, + }); err != nil { + return err + } + + if _, err := info.Write([]byte(exportName)); err != nil { + return err + } + + if err := binary.Write(conn, binary.BigEndian, protocol.NegotiationReplyHeader{ + ReplyMagic: protocol.NEGOTIATION_MAGIC_REPLY, + ID: optionHeader.ID, + Type: protocol.NEGOTIATION_TYPE_REPLY_INFO, + Length: uint32(info.Len()), + }); err != nil { + return err + } + + if _, err := io.Copy(conn, info); err != nil { + return err + } + } + + { + info := &bytes.Buffer{} + if err := binary.Write(info, binary.BigEndian, protocol.NegotiationReplyDescriptionHeader{ + Type: protocol.NEGOTIATION_TYPE_INFO_DESCRIPTION, + }); err != nil { + return err + } + + if err := binary.Write(info, binary.BigEndian, []byte(export.Description)); err != nil { + return err + } + + if err := binary.Write(conn, binary.BigEndian, protocol.NegotiationReplyHeader{ + ReplyMagic: protocol.NEGOTIATION_MAGIC_REPLY, + ID: optionHeader.ID, + Type: protocol.NEGOTIATION_TYPE_REPLY_INFO, + Length: uint32(info.Len()), + }); err != nil { + return err + } + + if _, err := io.Copy(conn, info); err != nil { + return err + } + } + + { + info := &bytes.Buffer{} + if err := binary.Write(info, binary.BigEndian, protocol.NegotiationReplyBlockSize{ + Type: protocol.NEGOTIATION_TYPE_INFO_BLOCKSIZE, + MinimumBlockSize: options.MinimumBlockSize, + PreferredBlockSize: options.PreferredBlockSize, + MaximumBlockSize: options.MaximumBlockSize, + }); err != nil { + return err + } + + if err := binary.Write(conn, binary.BigEndian, protocol.NegotiationReplyHeader{ + ReplyMagic: protocol.NEGOTIATION_MAGIC_REPLY, + ID: optionHeader.ID, + Type: protocol.NEGOTIATION_TYPE_REPLY_INFO, + Length: uint32(info.Len()), + }); err != nil { + return err + } + + if _, err := io.Copy(conn, info); err != nil { + return err + } + } + + if err := binary.Write(conn, binary.BigEndian, protocol.NegotiationReplyHeader{ + ReplyMagic: protocol.NEGOTIATION_MAGIC_REPLY, + ID: optionHeader.ID, + Type: protocol.NEGOTIATION_TYPE_REPLY_ACK, + Length: 0, + }); err != nil { + return err + } + + if optionHeader.ID == protocol.NEGOTIATION_ID_OPTION_GO { + break n + } + case protocol.NEGOTIATION_ID_OPTION_ABORT: + if err := binary.Write(conn, binary.BigEndian, protocol.NegotiationReplyHeader{ + ReplyMagic: protocol.NEGOTIATION_MAGIC_REPLY, + ID: optionHeader.ID, + Type: protocol.NEGOTIATION_TYPE_REPLY_ACK, + Length: 0, + }); err != nil { + return err + } + + return nil + case protocol.NEGOTIATION_ID_OPTION_LIST: + { + info := &bytes.Buffer{} + + for _, export := range exports { + exportName := []byte(export.Name) + + if err := binary.Write(info, binary.BigEndian, uint32(len(exportName))); err != nil { + return err + } + + if err := binary.Write(info, binary.BigEndian, exportName); err != nil { + return err + } + } + + if err := binary.Write(conn, binary.BigEndian, protocol.NegotiationReplyHeader{ + ReplyMagic: protocol.NEGOTIATION_MAGIC_REPLY, + ID: optionHeader.ID, + Type: protocol.NEGOTIATION_TYPE_REPLY_SERVER, + Length: uint32(info.Len()), + }); err != nil { + return err + } + + if _, err := io.Copy(conn, info); err != nil { + return err + } + } + + if err := binary.Write(conn, binary.BigEndian, protocol.NegotiationReplyHeader{ + ReplyMagic: protocol.NEGOTIATION_MAGIC_REPLY, + ID: optionHeader.ID, + Type: protocol.NEGOTIATION_TYPE_REPLY_ACK, + Length: 0, + }); err != nil { + return err + } + default: + _, err := io.CopyN(io.Discard, conn, int64(optionHeader.Length)) // Discard the unknown option's data + if err != nil { + return err + } + + if err := binary.Write(conn, binary.BigEndian, protocol.NegotiationReplyHeader{ + ReplyMagic: protocol.NEGOTIATION_MAGIC_REPLY, + ID: optionHeader.ID, + Type: protocol.NEGOTIATION_TYPE_REPLY_ERR_UNSUPPORTED, + Length: 0, + }); err != nil { + return err + } + } + } + + // Transmission + ctx, _ := context.WithCancel(context.Background()) + group, _ := errgroup.WithContext(ctx) + responseCh := make(chan *Response, 1024) + group.Go(func() error { + return Writer(ctx, conn, responseCh) + }) + group.Go(func() error { + return Reader(ctx, conn, export, options, responseCh) + }) + + if err := group.Wait(); err != nil { + return err + } + return nil +} + +type Response struct { + Handle uint64 + Data []byte + Offset uint64 + Error uint32 +} + +func Reader(ctx context.Context, conn net.Conn, export *Export, options *Options, responseCh chan<- *Response) error { + defer conn.Close() + + var requestHeader protocol.TransmissionRequestHeader + + for { + if err := conn.SetReadDeadline(time.Now().Add(1 * time.Second)); err != nil { + return err + } + if err := binary.Read(conn, binary.BigEndian, &requestHeader); err != nil { + select { + case <-ctx.Done(): + return nil + default: + if netErr, ok := err.(net.Error); ok && netErr.Timeout() { + continue + } + return err + } + + } + + if requestHeader.RequestMagic != protocol.TRANSMISSION_MAGIC_REQUEST { + return ErrInvalidMagic + } + + if requestHeader.Length > maximumPacketSize { + return ErrInvalidBlocksize + } + + switch requestHeader.Type { + case protocol.TRANSMISSION_TYPE_REQUEST_READ: + resp := &Response{ + Handle: requestHeader.Handle, + Data: make([]byte, requestHeader.Length), + Offset: requestHeader.Offset, + } + go HandleRead(export, responseCh, resp) + case protocol.TRANSMISSION_TYPE_REQUEST_WRITE: + if options.ReadOnly { + _, err := io.CopyN(io.Discard, conn, int64(requestHeader.Length)) // Discard the write command's data + if err != nil { + return err + } + + responseCh <- &Response{ + Handle: requestHeader.Handle, + Error: protocol.TRANSMISSION_ERROR_EPERM, + } + break + } + + resp := &Response{ + Handle: requestHeader.Handle, + Data: make([]byte, requestHeader.Length), + Offset: requestHeader.Offset, + } + n, err := io.ReadAtLeast(conn, resp.Data, int(requestHeader.Length)) + if err != nil { + return err + } + if n != int(requestHeader.Length) { + resp.Data = resp.Data[:n] + } + go HandleWrite(export, responseCh, resp) + case protocol.TRANSMISSION_TYPE_REQUEST_DISC: + if !options.ReadOnly { + if err := export.Backend.Sync(); err != nil { + return err + } + } + + return nil + default: + _, err := io.CopyN(io.Discard, conn, int64(requestHeader.Length)) // Discard the unknown command's data + if err != nil { + return err + } + + responseCh <- &Response{ + Handle: requestHeader.Handle, + Error: protocol.TRANSMISSION_ERROR_EINVAL, + } + } + } + return nil +} + +func Writer(ctx context.Context, conn net.Conn, responseCh <-chan *Response) error { + defer conn.Close() + + header := protocol.TransmissionReplyHeader{ + ReplyMagic: protocol.TRANSMISSION_MAGIC_REPLY, + Error: 0, + Handle: 0, + } + for { + select { + case <-ctx.Done(): + return nil + case resp := <-responseCh: + header.Handle = resp.Handle + header.Error = resp.Error + if err := binary.Write(conn, binary.BigEndian, header); err != nil { + return err + } + if resp.Error == 0 && resp.Data != nil { + if _, err := conn.Write(resp.Data); err != nil { + return err + } + } + } + } + return nil +} + +func HandleRead(export *Export, responses chan<- *Response, resp *Response) { + n, err := export.Backend.ReadAt(resp.Data, int64(resp.Offset)) + if err != nil { + resp.Error = protocol.TRANSMISSION_ERROR_EIO + responses <- resp + return + } + if n != len(resp.Data) { + resp.Data = resp.Data[:n] + } + responses <- resp +} + +func HandleWrite(export *Export, responses chan<- *Response, resp *Response) { + if _, err := export.Backend.WriteAt(resp.Data, int64(resp.Offset)); err != nil { + resp.Error = protocol.TRANSMISSION_ERROR_EIO + responses <- resp + return + } + resp.Data = nil + responses <- resp +} + diff --git a/vendor/golang.org/x/sync/LICENSE b/vendor/golang.org/x/sync/LICENSE new file mode 100644 index 000000000..6a66aea5e --- /dev/null +++ b/vendor/golang.org/x/sync/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/golang.org/x/sync/PATENTS b/vendor/golang.org/x/sync/PATENTS new file mode 100644 index 000000000..733099041 --- /dev/null +++ b/vendor/golang.org/x/sync/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) +patent license to make, have made, use, offer to sell, sell, import, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. diff --git a/vendor/golang.org/x/sync/errgroup/errgroup.go b/vendor/golang.org/x/sync/errgroup/errgroup.go new file mode 100644 index 000000000..b18efb743 --- /dev/null +++ b/vendor/golang.org/x/sync/errgroup/errgroup.go @@ -0,0 +1,132 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package errgroup provides synchronization, error propagation, and Context +// cancelation for groups of goroutines working on subtasks of a common task. +package errgroup + +import ( + "context" + "fmt" + "sync" +) + +type token struct{} + +// A Group is a collection of goroutines working on subtasks that are part of +// the same overall task. +// +// A zero Group is valid, has no limit on the number of active goroutines, +// and does not cancel on error. +type Group struct { + cancel func(error) + + wg sync.WaitGroup + + sem chan token + + errOnce sync.Once + err error +} + +func (g *Group) done() { + if g.sem != nil { + <-g.sem + } + g.wg.Done() +} + +// WithContext returns a new Group and an associated Context derived from ctx. +// +// The derived Context is canceled the first time a function passed to Go +// returns a non-nil error or the first time Wait returns, whichever occurs +// first. +func WithContext(ctx context.Context) (*Group, context.Context) { + ctx, cancel := withCancelCause(ctx) + return &Group{cancel: cancel}, ctx +} + +// Wait blocks until all function calls from the Go method have returned, then +// returns the first non-nil error (if any) from them. +func (g *Group) Wait() error { + g.wg.Wait() + if g.cancel != nil { + g.cancel(g.err) + } + return g.err +} + +// Go calls the given function in a new goroutine. +// It blocks until the new goroutine can be added without the number of +// active goroutines in the group exceeding the configured limit. +// +// The first call to return a non-nil error cancels the group's context, if the +// group was created by calling WithContext. The error will be returned by Wait. +func (g *Group) Go(f func() error) { + if g.sem != nil { + g.sem <- token{} + } + + g.wg.Add(1) + go func() { + defer g.done() + + if err := f(); err != nil { + g.errOnce.Do(func() { + g.err = err + if g.cancel != nil { + g.cancel(g.err) + } + }) + } + }() +} + +// TryGo calls the given function in a new goroutine only if the number of +// active goroutines in the group is currently below the configured limit. +// +// The return value reports whether the goroutine was started. +func (g *Group) TryGo(f func() error) bool { + if g.sem != nil { + select { + case g.sem <- token{}: + // Note: this allows barging iff channels in general allow barging. + default: + return false + } + } + + g.wg.Add(1) + go func() { + defer g.done() + + if err := f(); err != nil { + g.errOnce.Do(func() { + g.err = err + if g.cancel != nil { + g.cancel(g.err) + } + }) + } + }() + return true +} + +// SetLimit limits the number of active goroutines in this group to at most n. +// A negative value indicates no limit. +// +// Any subsequent call to the Go method will block until it can add an active +// goroutine without exceeding the configured limit. +// +// The limit must not be modified while any goroutines in the group are active. +func (g *Group) SetLimit(n int) { + if n < 0 { + g.sem = nil + return + } + if len(g.sem) != 0 { + panic(fmt.Errorf("errgroup: modify limit while %v goroutines in the group are still active", len(g.sem))) + } + g.sem = make(chan token, n) +} diff --git a/vendor/golang.org/x/sync/errgroup/go120.go b/vendor/golang.org/x/sync/errgroup/go120.go new file mode 100644 index 000000000..7d419d376 --- /dev/null +++ b/vendor/golang.org/x/sync/errgroup/go120.go @@ -0,0 +1,14 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.20 +// +build go1.20 + +package errgroup + +import "context" + +func withCancelCause(parent context.Context) (context.Context, func(error)) { + return context.WithCancelCause(parent) +} diff --git a/vendor/golang.org/x/sync/errgroup/pre_go120.go b/vendor/golang.org/x/sync/errgroup/pre_go120.go new file mode 100644 index 000000000..1795c18ac --- /dev/null +++ b/vendor/golang.org/x/sync/errgroup/pre_go120.go @@ -0,0 +1,15 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !go1.20 +// +build !go1.20 + +package errgroup + +import "context" + +func withCancelCause(parent context.Context) (context.Context, func(error)) { + ctx, cancel := context.WithCancel(parent) + return ctx, func(error) { cancel() } +} diff --git a/vendor/modules.txt b/vendor/modules.txt index bf4150844..75a54f9b8 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -187,6 +187,14 @@ github.com/pierrec/lz4/v4/internal/xxh32 # github.com/pkg/errors v0.9.1 ## explicit github.com/pkg/errors +# github.com/pmorjan/kmod v1.1.0 +## explicit; go 1.18 +github.com/pmorjan/kmod +# github.com/pojntfx/go-nbd v0.3.2 => github.com/chazapis/go-nbd v0.0.0-20231031233644-40daa63e22c3 +## explicit; go 1.21 +github.com/pojntfx/go-nbd/pkg/backend +github.com/pojntfx/go-nbd/pkg/protocol +github.com/pojntfx/go-nbd/pkg/server # github.com/prometheus/client_golang v1.15.0 ## explicit; go 1.17 github.com/prometheus/client_golang/prometheus @@ -245,6 +253,9 @@ golang.org/x/net/http2/hpack golang.org/x/net/idna golang.org/x/net/internal/timeseries golang.org/x/net/trace +# golang.org/x/sync v0.4.0 +## explicit; go 1.17 +golang.org/x/sync/errgroup # golang.org/x/sys v0.13.0 ## explicit; go 1.17 golang.org/x/sys/unix @@ -377,3 +388,4 @@ k8s.io/utils/clock k8s.io/utils/exec k8s.io/utils/io k8s.io/utils/keymutex +# github.com/pojntfx/go-nbd => github.com/chazapis/go-nbd v0.0.0-20231031233644-40daa63e22c3 From 8e44b12490f0f0eb6003786bafa94014cf1eae0f Mon Sep 17 00:00:00 2001 From: Antony Chazapis Date: Wed, 22 Nov 2023 12:34:27 +0200 Subject: [PATCH 02/10] Make frontend streams a parameter --- app/cmd/controller.go | 15 +++++++++++++-- pkg/controller/control.go | 16 +++++++++------- pkg/controller/init_frontend.go | 4 ++-- pkg/frontend/nbd/frontend.go | 7 ++++--- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/app/cmd/controller.go b/app/cmd/controller.go index b96c13298..c669e8728 100644 --- a/app/cmd/controller.go +++ b/app/cmd/controller.go @@ -67,6 +67,12 @@ func ControllerCmd() cli.Command { Value: int64(controller.DefaultEngineReplicaTimeout.Seconds()), Usage: "In seconds. Timeout between engine and replica(s)", }, + cli.IntFlag{ + Name: "frontend-streams", + Required: false, + Value: 1, + Usage: "Number of concurrent streams to the frontend", + }, cli.StringFlag{ Name: "data-server-protocol", Value: "tcp", @@ -138,6 +144,11 @@ func startController(c *cli.Context) error { engineReplicaTimeout = controller.DetermineEngineReplicaTimeout(engineReplicaTimeout) iscsiTargetRequestTimeout := controller.DetermineIscsiTargetRequestTimeout(engineReplicaTimeout) + frontendStreams := c.Int("replica-streams") + if frontendStreams < 1 { + return errors.New("at least one stream to the frontend is required") + } + factories := map[string]types.BackendFactory{} for _, backend := range backends { switch backend { @@ -152,7 +163,7 @@ func startController(c *cli.Context) error { var frontend types.Frontend if frontendName != "" { - f, err := controller.NewFrontend(frontendName, iscsiTargetRequestTimeout) + f, err := controller.NewFrontend(frontendName, frontendStreams, iscsiTargetRequestTimeout) if err != nil { return errors.Wrapf(err, "failed to find frontend: %s", frontendName) } @@ -161,7 +172,7 @@ func startController(c *cli.Context) error { logrus.Infof("Creating volume %v controller with iSCSI target request timeout %v and engine to replica(s) timeout %v", volumeName, iscsiTargetRequestTimeout, engineReplicaTimeout) - control := controller.NewController(volumeName, dynamic.New(factories), frontend, isUpgrade, disableRevCounter, salvageRequested, + control := controller.NewController(volumeName, dynamic.New(factories), frontend, frontendStreams, isUpgrade, disableRevCounter, salvageRequested, unmapMarkSnapChainRemoved, iscsiTargetRequestTimeout, engineReplicaTimeout, types.DataServerProtocol(dataServerProtocol), fileSyncHTTPClientTimeout) diff --git a/pkg/controller/control.go b/pkg/controller/control.go index 8b005b2a8..4b24dfb5a 100644 --- a/pkg/controller/control.go +++ b/pkg/controller/control.go @@ -30,6 +30,7 @@ type Controller struct { factory types.BackendFactory backend *replicator frontend types.Frontend + frontendStreams int isUpgrade bool iscsiTargetRequestTimeout time.Duration engineReplicaTimeout time.Duration @@ -66,14 +67,15 @@ const ( lastModifyCheckPeriod = 5 * time.Second ) -func NewController(name string, factory types.BackendFactory, frontend types.Frontend, isUpgrade, disableRevCounter, salvageRequested, unmapMarkSnapChainRemoved bool, +func NewController(name string, factory types.BackendFactory, frontend types.Frontend, frontendStreams int, isUpgrade, disableRevCounter, salvageRequested, unmapMarkSnapChainRemoved bool, iscsiTargetRequestTimeout, engineReplicaTimeout time.Duration, dataServerProtocol types.DataServerProtocol, fileSyncHTTPClientTimeout int) *Controller { c := &Controller{ - factory: factory, - VolumeName: name, - frontend: frontend, - metrics: &types.Metrics{}, - latestMetrics: &types.Metrics{}, + factory: factory, + VolumeName: name, + frontend: frontend, + frontendStreams: frontendStreams, + metrics: &types.Metrics{}, + latestMetrics: &types.Metrics{}, isUpgrade: isUpgrade, revisionCounterDisabled: disableRevCounter, @@ -484,7 +486,7 @@ func (c *Controller) StartFrontend(frontend string) error { } } - f, err := NewFrontend(frontend, c.iscsiTargetRequestTimeout) + f, err := NewFrontend(frontend, c.frontendStreams, c.iscsiTargetRequestTimeout) if err != nil { return errors.Wrapf(err, "failed to find frontend: %s", frontend) } diff --git a/pkg/controller/init_frontend.go b/pkg/controller/init_frontend.go index c3bf7b964..33e9b2b7d 100644 --- a/pkg/controller/init_frontend.go +++ b/pkg/controller/init_frontend.go @@ -22,7 +22,7 @@ const ( maxEngineReplicaTimeout = 30 * time.Second ) -func NewFrontend(frontendType string, iscsiTargetRequestTimeout time.Duration) (types.Frontend, error) { +func NewFrontend(frontendType string, frontendStreams int, iscsiTargetRequestTimeout time.Duration) (types.Frontend, error) { switch frontendType { case "rest": return rest.New(), nil @@ -33,7 +33,7 @@ func NewFrontend(frontendType string, iscsiTargetRequestTimeout time.Duration) ( case devtypes.FrontendTGTISCSI: return tgt.New(devtypes.FrontendTGTISCSI, defaultScsiTimeout, defaultIscsiAbortTimeout, iscsiTargetRequestTimeout), nil case "nbd": - return nbd.New(), nil + return nbd.New(frontendStreams), nil default: return nil, fmt.Errorf("unsupported frontend type: %v", frontendType) } diff --git a/pkg/frontend/nbd/frontend.go b/pkg/frontend/nbd/frontend.go index 0a13934dc..276d5765e 100644 --- a/pkg/frontend/nbd/frontend.go +++ b/pkg/frontend/nbd/frontend.go @@ -31,11 +31,12 @@ type Nbd struct { isUp bool socketPath string nbdDevicePath string + connections int clients int } -func New() types.Frontend { - return &Nbd{} +func New(frontendStreams int) types.Frontend { + return &Nbd{connections: frontendStreams} } func (n *Nbd) FrontendName() string { @@ -70,7 +71,7 @@ func (n *Nbd) Startup(rwu types.ReaderWriterUnmapperAt) error { if err != nil { return err } - args := strings.Fields(fmt.Sprintf("/usr/sbin/nbd-client -u %s -b 4096 %s -C 2", n.GetSocketPath(), n.nbdDevicePath)) + args := strings.Fields(fmt.Sprintf("/usr/sbin/nbd-client -N %s -u %s -b 4096 %s -C %d", n.Volume, n.socketPath, n.nbdDevicePath, n.connections)) cmd := exec.Command(args[0], args[1:]...) if err := cmd.Run(); err != nil { return err From 4e3931396b47d637e5d9094c07b14c08aeef0ba0 Mon Sep 17 00:00:00 2001 From: Mike Toutou Date: Thu, 30 Nov 2023 18:56:33 +0200 Subject: [PATCH 03/10] NBD server-client option for dataconn --- app/cmd/controller.go | 11 +- app/cmd/replica.go | 9 +- go.mod | 1 + go.sum | 2 + pkg/backend/dynamic/dynamic.go | 4 +- pkg/backend/file/file.go | 2 +- pkg/backend/remote/remote.go | 17 +- pkg/controller/control.go | 8 +- pkg/dataconn/nbd_client.go | 90 + pkg/dataconn/nbd_server.go | 72 + pkg/replica/rpc/dataserver.go | 32 +- pkg/types/types.go | 2 +- vendor/libguestfs.org/libnbd/LICENSE | 502 ++++ vendor/libguestfs.org/libnbd/README.md | 16 + vendor/libguestfs.org/libnbd/aio_buffer.go | 101 + vendor/libguestfs.org/libnbd/bindings.go | 2857 ++++++++++++++++++++ vendor/libguestfs.org/libnbd/callbacks.go | 102 + vendor/libguestfs.org/libnbd/closures.go | 131 + vendor/libguestfs.org/libnbd/handle.go | 133 + vendor/libguestfs.org/libnbd/wrappers.go | 2215 +++++++++++++++ vendor/libguestfs.org/libnbd/wrappers.h | 382 +++ vendor/modules.txt | 3 + 22 files changed, 6666 insertions(+), 26 deletions(-) create mode 100644 pkg/dataconn/nbd_client.go create mode 100644 pkg/dataconn/nbd_server.go create mode 100644 vendor/libguestfs.org/libnbd/LICENSE create mode 100644 vendor/libguestfs.org/libnbd/README.md create mode 100644 vendor/libguestfs.org/libnbd/aio_buffer.go create mode 100644 vendor/libguestfs.org/libnbd/bindings.go create mode 100644 vendor/libguestfs.org/libnbd/callbacks.go create mode 100644 vendor/libguestfs.org/libnbd/closures.go create mode 100644 vendor/libguestfs.org/libnbd/handle.go create mode 100644 vendor/libguestfs.org/libnbd/wrappers.go create mode 100644 vendor/libguestfs.org/libnbd/wrappers.h diff --git a/app/cmd/controller.go b/app/cmd/controller.go index c669e8728..c87c23d94 100644 --- a/app/cmd/controller.go +++ b/app/cmd/controller.go @@ -89,6 +89,12 @@ func ControllerCmd() cli.Command { Value: 5, Usage: "HTTP client timeout for replica file sync server", }, + cli.IntFlag{ + Name: "nbd-enabled", + Required: false, + Value: 0, + Usage: "Flag to enable NBD data server. Option 0 to disable, options >0 for number of connections", + }, }, Action: func(c *cli.Context) { if err := startController(c); err != nil { @@ -120,6 +126,7 @@ func startController(c *cli.Context) error { dataServerProtocol := c.String("data-server-protocol") fileSyncHTTPClientTimeout := c.Int("file-sync-http-client-timeout") engineInstanceName := c.GlobalString("engine-instance-name") + nbdEnabled := c.Int("nbd-enabled") size := c.String("size") if size == "" { @@ -144,7 +151,7 @@ func startController(c *cli.Context) error { engineReplicaTimeout = controller.DetermineEngineReplicaTimeout(engineReplicaTimeout) iscsiTargetRequestTimeout := controller.DetermineIscsiTargetRequestTimeout(engineReplicaTimeout) - frontendStreams := c.Int("replica-streams") + frontendStreams := c.Int("frontend-streams") if frontendStreams < 1 { return errors.New("at least one stream to the frontend is required") } @@ -174,7 +181,7 @@ func startController(c *cli.Context) error { volumeName, iscsiTargetRequestTimeout, engineReplicaTimeout) control := controller.NewController(volumeName, dynamic.New(factories), frontend, frontendStreams, isUpgrade, disableRevCounter, salvageRequested, unmapMarkSnapChainRemoved, iscsiTargetRequestTimeout, engineReplicaTimeout, types.DataServerProtocol(dataServerProtocol), - fileSyncHTTPClientTimeout) + fileSyncHTTPClientTimeout, nbdEnabled) // need to wait for Shutdown() completion control.ShutdownWG.Add(1) diff --git a/app/cmd/replica.go b/app/cmd/replica.go index 301769e2d..7726b3355 100644 --- a/app/cmd/replica.go +++ b/app/cmd/replica.go @@ -73,6 +73,12 @@ func ReplicaCmd() cli.Command { Value: "", Usage: "Name of the replica instance (for validation purposes)", }, + cli.IntFlag{ + Name: "nbd-enabled", + Required: false, + Value: 0, + Usage: "Flag to enable NBD data server", + }, }, Action: func(c *cli.Context) { if err := startReplica(c); err != nil { @@ -115,6 +121,7 @@ func startReplica(c *cli.Context) error { volumeName := c.GlobalString("volume-name") replicaInstanceName := c.String("replica-instance-name") dataServerProtocol := c.String("data-server-protocol") + nbdEnabled := c.Int("nbd-enabled") controlAddress, dataAddress, syncAddress, syncPort, err := util.GetAddresses(volumeName, address, types.DataServerProtocol(dataServerProtocol)) @@ -141,7 +148,7 @@ func startReplica(c *cli.Context) error { }() go func() { - rpcServer := replicarpc.NewDataServer(types.DataServerProtocol(dataServerProtocol), dataAddress, s) + rpcServer := replicarpc.NewDataServer(types.DataServerProtocol(dataServerProtocol), dataAddress, s, nbdEnabled) logrus.Infof("Listening on data server %s", dataAddress) err := rpcServer.ListenAndServe() logrus.WithError(err).Warnf("Replica rest server at %v is down", dataAddress) diff --git a/go.mod b/go.mod index ae5e8a7d1..d7268a12b 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,7 @@ require ( google.golang.org/grpc v1.53.0 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c gopkg.in/cheggaaa/pb.v2 v2.0.0-20190301131520-f907f6f5dd81 + libguestfs.org/libnbd v1.13.1 ) require ( diff --git a/go.sum b/go.sum index 079c39079..acca36a1a 100644 --- a/go.sum +++ b/go.sum @@ -223,3 +223,5 @@ k8s.io/mount-utils v0.27.1 h1:RSd0wslbIuwLRaGGNAGMZ3m9FLcvukxJ3FWlOm76W2A= k8s.io/mount-utils v0.27.1/go.mod h1:vmcjYdi2Vg1VTWY7KkhvwJVY6WDHxb/QQhiQKkR8iNs= k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +libguestfs.org/libnbd v1.13.1 h1:5E77fcDS3DRJiSK5JVMvR6IYADPvIxLw05C/IYMv86E= +libguestfs.org/libnbd v1.13.1/go.mod h1:Qd8vaULc6nlNgj9+6qDNm1vSD/J7/wgoIlwmCh8uxAc= diff --git a/pkg/backend/dynamic/dynamic.go b/pkg/backend/dynamic/dynamic.go index 32d3027ba..c12b94260 100644 --- a/pkg/backend/dynamic/dynamic.go +++ b/pkg/backend/dynamic/dynamic.go @@ -18,12 +18,12 @@ func New(factories map[string]types.BackendFactory) types.BackendFactory { } } -func (d *Factory) Create(volumeName, address string, dataServerProtocol types.DataServerProtocol, engineToReplicaTimeout time.Duration) (types.Backend, error) { +func (d *Factory) Create(volumeName, address string, dataServerProtocol types.DataServerProtocol, engineToReplicaTimeout time.Duration, nbdEnabled int) (types.Backend, error) { parts := strings.SplitN(address, "://", 2) if len(parts) == 2 { if factory, ok := d.factories[parts[0]]; ok { - return factory.Create(volumeName, parts[1], dataServerProtocol, engineToReplicaTimeout) + return factory.Create(volumeName, parts[1], dataServerProtocol, engineToReplicaTimeout, nbdEnabled) } } diff --git a/pkg/backend/file/file.go b/pkg/backend/file/file.go index 1a2a6182c..e53cb6d3d 100644 --- a/pkg/backend/file/file.go +++ b/pkg/backend/file/file.go @@ -124,7 +124,7 @@ func (f *Wrapper) ResetRebuild() error { return nil } -func (ff *Factory) Create(volumeName, address string, dataServerProtocol types.DataServerProtocol, engineToReplicaTimeout time.Duration) (types.Backend, error) { +func (ff *Factory) Create(volumeName, address string, dataServerProtocol types.DataServerProtocol, engineToReplicaTimeout time.Duration, nbdEnabled int) (types.Backend, error) { logrus.Infof("Creating file: %s", address) file, err := os.OpenFile(address, os.O_RDWR|os.O_CREATE, 0600) if err != nil { diff --git a/pkg/backend/remote/remote.go b/pkg/backend/remote/remote.go index 9e2aca76b..eb32293c5 100644 --- a/pkg/backend/remote/remote.go +++ b/pkg/backend/remote/remote.go @@ -329,7 +329,7 @@ func (r *Remote) info() (*types.ReplicaInfo, error) { return replicaClient.GetReplicaInfo(resp.Replica), nil } -func (rf *Factory) Create(volumeName, address string, dataServerProtocol types.DataServerProtocol, engineToReplicaTimeout time.Duration) (types.Backend, error) { +func (rf *Factory) Create(volumeName, address string, dataServerProtocol types.DataServerProtocol, engineToReplicaTimeout time.Duration, nbdEnabled int) (types.Backend, error) { logrus.Infof("Connecting to remote: %s (%v)", address, dataServerProtocol) controlAddress, dataAddress, _, _, err := util.GetAddresses(volumeName, address, dataServerProtocol) @@ -360,15 +360,22 @@ func (rf *Factory) Create(volumeName, address string, dataServerProtocol types.D if err != nil { return nil, err } - - dataConnClient := dataconn.NewClient(conn, engineToReplicaTimeout) - r.ReaderWriterUnmapperAt = dataConnClient + var dataConnClient *dataconn.Client + if nbdEnabled > 0 { + dataConnClientNBD := dataconn.NewNBDClientWrapper(conn, engineToReplicaTimeout, nbdEnabled) + r.ReaderWriterUnmapperAt = dataConnClientNBD + } else { + dataConnClient = dataconn.NewClient(conn, engineToReplicaTimeout) + r.ReaderWriterUnmapperAt = dataConnClient + } if err := r.open(); err != nil { return nil, err } - go r.monitorPing(dataConnClient) + if nbdEnabled == 0 { + go r.monitorPing(dataConnClient) + } return r, nil } diff --git a/pkg/controller/control.go b/pkg/controller/control.go index 4b24dfb5a..cce345e93 100644 --- a/pkg/controller/control.go +++ b/pkg/controller/control.go @@ -35,6 +35,7 @@ type Controller struct { iscsiTargetRequestTimeout time.Duration engineReplicaTimeout time.Duration DataServerProtocol types.DataServerProtocol + nbdEnabled int isExpanding bool revisionCounterDisabled bool @@ -68,7 +69,7 @@ const ( ) func NewController(name string, factory types.BackendFactory, frontend types.Frontend, frontendStreams int, isUpgrade, disableRevCounter, salvageRequested, unmapMarkSnapChainRemoved bool, - iscsiTargetRequestTimeout, engineReplicaTimeout time.Duration, dataServerProtocol types.DataServerProtocol, fileSyncHTTPClientTimeout int) *Controller { + iscsiTargetRequestTimeout, engineReplicaTimeout time.Duration, dataServerProtocol types.DataServerProtocol, fileSyncHTTPClientTimeout int, nbdEnabled int) *Controller { c := &Controller{ factory: factory, VolumeName: name, @@ -87,6 +88,7 @@ func NewController(name string, factory types.BackendFactory, frontend types.Fro DataServerProtocol: dataServerProtocol, fileSyncHTTPClientTimeout: fileSyncHTTPClientTimeout, + nbdEnabled: nbdEnabled, } c.reset() c.metricsStart() @@ -166,7 +168,7 @@ func (c *Controller) addReplica(address string, snapshotRequired bool, mode type return err } - newBackend, err := c.factory.Create(c.VolumeName, address, c.DataServerProtocol, c.engineReplicaTimeout) + newBackend, err := c.factory.Create(c.VolumeName, address, c.DataServerProtocol, c.engineReplicaTimeout, c.nbdEnabled) if err != nil { return err } @@ -730,7 +732,7 @@ func (c *Controller) Start(volumeSize, volumeCurrentSize int64, addresses ...str errorCodes := map[string]codes.Code{} first := true for _, address := range addresses { - newBackend, err := c.factory.Create(c.VolumeName, address, c.DataServerProtocol, c.engineReplicaTimeout) + newBackend, err := c.factory.Create(c.VolumeName, address, c.DataServerProtocol, c.engineReplicaTimeout, c.nbdEnabled) if err != nil { if strings.Contains(err.Error(), "rpc error: code = Unavailable") { errorCodes[address] = codes.Unavailable diff --git a/pkg/dataconn/nbd_client.go b/pkg/dataconn/nbd_client.go new file mode 100644 index 000000000..16a81b736 --- /dev/null +++ b/pkg/dataconn/nbd_client.go @@ -0,0 +1,90 @@ +package dataconn + +import ( + "net" + "sync" + "time" + + "libguestfs.org/libnbd" +) + +type nbdClientWrapper struct { + handles []*libnbd.Libnbd + conn net.Conn + maxConnections int + next int + indexLock sync.Mutex + end chan struct{} +} + +func NewNBDClientWrapper(conn net.Conn, engineToReplicaTimeout time.Duration, nbdEnabled int) *nbdClientWrapper { + wrapper := &nbdClientWrapper{ + handles: make([]*libnbd.Libnbd, nbdEnabled), + conn: conn, + maxConnections: nbdEnabled, + next: 0, + end: make(chan struct{}), + } + go wrapper.handle() + + return wrapper +} + +func (w *nbdClientWrapper) handle() { + for i := 0; i < w.maxConnections; i++ { + h, err := libnbd.Create() + if err != nil { + panic(err) + } + + w.handles[i] = h + uri := "nbd://" + w.conn.RemoteAddr().String() + err = w.handles[i].ConnectUri(uri) + if err != nil { + panic(err) + } + } + + for { + <-w.end + return + } +} + +func (w *nbdClientWrapper) ReadAt(buf []byte, offset int64) (int, error) { + w.indexLock.Lock() + w.next = (w.next + 1) % w.maxConnections + index := w.next + w.indexLock.Unlock() + err := w.handles[index].Pread(buf, uint64(offset), nil) + if err != nil { + return 0, err + } + + return len(buf), nil +} + +func (w *nbdClientWrapper) WriteAt(buf []byte, offset int64) (int, error) { + w.indexLock.Lock() + w.next = (w.next + 1) % w.maxConnections + index := w.next + w.indexLock.Unlock() + err := w.handles[index].Pwrite(buf, uint64(offset), nil) + if err != nil { + return 0, err + } + + return len(buf), nil +} + +func (w *nbdClientWrapper) UnmapAt(length uint32, offset int64) (int, error) { + return int(length), nil + +} + +func (w *nbdClientWrapper) Close() { + for i := 0; i < w.maxConnections; i++ { + w.handles[i].Close() + } + w.end <- struct{}{} +} diff --git a/pkg/dataconn/nbd_server.go b/pkg/dataconn/nbd_server.go new file mode 100644 index 000000000..97f568b41 --- /dev/null +++ b/pkg/dataconn/nbd_server.go @@ -0,0 +1,72 @@ +package dataconn + +import ( + "fmt" + "net" + + "github.com/longhorn/longhorn-engine/pkg/replica" + "github.com/longhorn/longhorn-engine/pkg/types" + "github.com/pojntfx/go-nbd/pkg/server" +) + +type nbdServer struct { + conn net.Conn + s *replica.Server +} + +func NewNBDServer(conn net.Conn, s *replica.Server) *nbdServer { + return &nbdServer{ + conn: conn, + s: s, + } +} + +func (s *nbdServer) Handle() { + if err := server.Handle( + s.conn, + []*server.Export{ + { + Name: "", + Description: "", + Backend: s, + }, + }, + &server.Options{ + ReadOnly: false, + MinimumBlockSize: uint32(512), + PreferredBlockSize: uint32(512), + MaximumBlockSize: uint32(512), + }); err != nil { + panic(err) + } +} + +func (b *nbdServer) ReadAt(p []byte, off int64) (n int, err error) { + n, err = b.s.ReadAt(p, off) + return +} + +func (b *nbdServer) WriteAt(p []byte, off int64) (n int, err error) { + n, err = b.s.WriteAt(p, off) + return +} + +func (b *nbdServer) Size() (int64, error) { + _, info := b.s.Status() + return info.Size, nil +} + +func (b *nbdServer) Sync() error { + return nil +} + +func (b *nbdServer) Ping() error { + state, info := b.s.Status() + if state == types.ReplicaStateError { + return fmt.Errorf("ping failure due to %v", info.Error) + } + if state != types.ReplicaStateOpen && state != types.ReplicaStateDirty && state != types.ReplicaStateRebuilding { + return fmt.Errorf("ping failure: replica state %v", state) + } + return nil +} diff --git a/pkg/replica/rpc/dataserver.go b/pkg/replica/rpc/dataserver.go index 6251760ff..7f5e1e95e 100644 --- a/pkg/replica/rpc/dataserver.go +++ b/pkg/replica/rpc/dataserver.go @@ -12,16 +12,18 @@ import ( ) type DataServer struct { - protocol types.DataServerProtocol - address string - s *replica.Server + protocol types.DataServerProtocol + address string + s *replica.Server + nbdEnabled int } -func NewDataServer(protocol types.DataServerProtocol, address string, s *replica.Server) *DataServer { +func NewDataServer(protocol types.DataServerProtocol, address string, s *replica.Server, nbdEnabled int) *DataServer { return &DataServer{ - protocol: protocol, - address: address, - s: s, + protocol: protocol, + address: address, + s: s, + nbdEnabled: nbdEnabled, } } @@ -56,10 +58,18 @@ func (s *DataServer) listenAndServeTCP() error { logrus.Infof("New connection from: %v", conn.RemoteAddr()) - go func(conn net.Conn) { - server := dataconn.NewServer(conn, s.s) - server.Handle() - }(conn) + if s.nbdEnabled > 0 { + go func() { + nbdServer := dataconn.NewNBDServer(conn, s.s) + nbdServer.Handle() + }() + } else { + go func(conn net.Conn) { + server := dataconn.NewServer(conn, s.s) + server.Handle() + }(conn) + } + } } diff --git a/pkg/types/types.go b/pkg/types/types.go index c0d560ebc..3eca45849 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -106,7 +106,7 @@ type Backend interface { } type BackendFactory interface { - Create(volumeName, address string, dataServerProtocol DataServerProtocol, engineReplicaTimeout time.Duration) (Backend, error) + Create(volumeName, address string, dataServerProtocol DataServerProtocol, engineReplicaTimeout time.Duration, nbdEnabled int) (Backend, error) } type Controller interface { diff --git a/vendor/libguestfs.org/libnbd/LICENSE b/vendor/libguestfs.org/libnbd/LICENSE new file mode 100644 index 000000000..4362b4915 --- /dev/null +++ b/vendor/libguestfs.org/libnbd/LICENSE @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/vendor/libguestfs.org/libnbd/README.md b/vendor/libguestfs.org/libnbd/README.md new file mode 100644 index 000000000..2eb00064b --- /dev/null +++ b/vendor/libguestfs.org/libnbd/README.md @@ -0,0 +1,16 @@ +# Libnbd Go binding + +This module provides access to Network Block Device (NBD) servers from +the Go programming language, using the libnbd library. + +Please see the manual to learn how to use this module: +https://libguestfs.org/libnbd-golang.3.html + +This is part of libnbd, please check the project at: +https://gitlab.com/nbdkit/libnbd + +## License + +The software is copyright © Red Hat Inc. and licensed under the GNU +Lesser General Public License version 2 or above (LGPLv2+). See +the file `LICENSE` for details. diff --git a/vendor/libguestfs.org/libnbd/aio_buffer.go b/vendor/libguestfs.org/libnbd/aio_buffer.go new file mode 100644 index 000000000..9b7fdfae5 --- /dev/null +++ b/vendor/libguestfs.org/libnbd/aio_buffer.go @@ -0,0 +1,101 @@ +/* libnbd golang AIO buffer. + * Copyright (C) 2013-2021 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package libnbd + +/* +#cgo pkg-config: libnbd +#cgo CFLAGS: -D_GNU_SOURCE=1 + +#include +#include + +#include "libnbd.h" +#include "wrappers.h" + +*/ +import "C" + +import "unsafe" + +/* Asynchronous I/O buffer. */ +type AioBuffer struct { + P unsafe.Pointer + Size uint +} + +// MakeAioBuffer makes a new buffer backed by an uninitialized C allocated +// array. +func MakeAioBuffer(size uint) AioBuffer { + return AioBuffer{C.malloc(C.ulong(size)), size} +} + +// MakeAioBuffer makes a new buffer backed by a C allocated array. The +// underlying buffer is set to zero. +func MakeAioBufferZero(size uint) AioBuffer { + return AioBuffer{C.calloc(C.ulong(1), C.ulong(size)), size} +} + +// FromBytes makes a new buffer backed by a C allocated array, initialized by +// copying the given Go slice. +func FromBytes(buf []byte) AioBuffer { + ret := MakeAioBuffer(uint(len(buf))) + copy(ret.Slice(), buf) + return ret +} + +// Free deallocates the underlying C allocated array. Using the buffer after +// Free() will panic. +func (b *AioBuffer) Free() { + if b.P != nil { + C.free(b.P) + b.P = nil + } +} + +// Bytes copies the underlying C array to Go allocated memory and return a +// slice. Modifying the returned slice does not modify the underlying buffer +// backing array. +func (b *AioBuffer) Bytes() []byte { + if b.P == nil { + panic("Using AioBuffer after Free()") + } + return C.GoBytes(b.P, C.int(b.Size)) +} + +// Slice creates a slice backed by the underlying C array. The slice can be +// used to access or modify the contents of the underlying array. The slice +// must not be used after caling Free(). +func (b *AioBuffer) Slice() []byte { + if b.P == nil { + panic("Using AioBuffer after Free()") + } + // See https://github.com/golang/go/wiki/cgo#turning-c-arrays-into-go-slices + // TODO: Use unsafe.Slice() when we require Go 1.17. + return (*[1 << 30]byte)(b.P)[:b.Size:b.Size] +} + +// Get returns a pointer to a byte in the underlying C array. The pointer can +// be used to modify the underlying array. The pointer must not be used after +// calling Free(). +func (b *AioBuffer) Get(i uint) *byte { + if b.P == nil { + panic("Using AioBuffer after Free()") + } + return (*byte)(unsafe.Pointer(uintptr(b.P) + uintptr(i))) +} diff --git a/vendor/libguestfs.org/libnbd/bindings.go b/vendor/libguestfs.org/libnbd/bindings.go new file mode 100644 index 000000000..7771b3ab9 --- /dev/null +++ b/vendor/libguestfs.org/libnbd/bindings.go @@ -0,0 +1,2857 @@ +/* NBD client library in userspace + * WARNING: THIS FILE IS GENERATED FROM + * generator/generator + * ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST. + * + * Copyright (C) 2013-2021 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package libnbd + +/* +#cgo pkg-config: libnbd +#cgo CFLAGS: -D_GNU_SOURCE=1 + +#include +#include +#include + +#include "libnbd.h" +#include "wrappers.h" + +// There must be no blank line between end comment and import! +// https://github.com/golang/go/issues/9733 +*/ +import "C" + +import ( + "runtime" + "unsafe" +) + +/* Enums. */ +type Tls int +const ( + TLS_DISABLE = Tls(0) + TLS_ALLOW = Tls(1) + TLS_REQUIRE = Tls(2) +) + +type Size int +const ( + SIZE_MINIMUM = Size(0) + SIZE_PREFERRED = Size(1) + SIZE_MAXIMUM = Size(2) +) + +/* Flags. */ +type CmdFlag uint32 +const ( + CMD_FLAG_FUA = CmdFlag(0x01) + CMD_FLAG_NO_HOLE = CmdFlag(0x02) + CMD_FLAG_DF = CmdFlag(0x04) + CMD_FLAG_REQ_ONE = CmdFlag(0x08) + CMD_FLAG_FAST_ZERO = CmdFlag(0x10) + CMD_FLAG_MASK = CmdFlag(0x1f) +) + +type HandshakeFlag uint32 +const ( + HANDSHAKE_FLAG_FIXED_NEWSTYLE = HandshakeFlag(0x01) + HANDSHAKE_FLAG_NO_ZEROES = HandshakeFlag(0x02) + HANDSHAKE_FLAG_MASK = HandshakeFlag(0x03) +) + +type Strict uint32 +const ( + STRICT_COMMANDS = Strict(0x01) + STRICT_FLAGS = Strict(0x02) + STRICT_BOUNDS = Strict(0x04) + STRICT_ZERO_SIZE = Strict(0x08) + STRICT_ALIGN = Strict(0x10) + STRICT_MASK = Strict(0x1f) +) + +type AllowTransport uint32 +const ( + ALLOW_TRANSPORT_TCP = AllowTransport(0x01) + ALLOW_TRANSPORT_UNIX = AllowTransport(0x02) + ALLOW_TRANSPORT_VSOCK = AllowTransport(0x04) + ALLOW_TRANSPORT_MASK = AllowTransport(0x07) +) + +type Shutdown uint32 +const ( + SHUTDOWN_ABANDON_PENDING = Shutdown(0x10000) + SHUTDOWN_MASK = Shutdown(0x10000) +) + +/* Constants. */ +const ( + AIO_DIRECTION_READ uint32 = 1 + AIO_DIRECTION_WRITE uint32 = 2 + AIO_DIRECTION_BOTH uint32 = 3 + READ_DATA uint32 = 1 + READ_HOLE uint32 = 2 + READ_ERROR uint32 = 3 + namespace_base = "base:" + context_base_allocation = "base:allocation" + STATE_HOLE uint32 = 1 + STATE_ZERO uint32 = 2 +) + +/* SetDebug: set or clear the debug flag */ +func (h *Libnbd) SetDebug (debug bool) error { + if h.h == nil { + return closed_handle_error ("set_debug") + } + + var c_err C.struct_error + c_debug := C.bool (debug) + + ret := C._nbd_set_debug_wrapper (&c_err, h.h, c_debug) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("set_debug", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* GetDebug: return the state of the debug flag */ +func (h *Libnbd) GetDebug () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("get_debug") + } + + var c_err C.struct_error + + ret := C._nbd_get_debug_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("get_debug", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* SetDebugCallback: set the debug callback */ +func (h *Libnbd) SetDebugCallback (debug DebugCallback) error { + if h.h == nil { + return closed_handle_error ("set_debug_callback") + } + + var c_err C.struct_error + var c_debug C.nbd_debug_callback + c_debug.callback = (*[0]byte)(C._nbd_debug_callback_wrapper) + c_debug.free = (*[0]byte)(C._nbd_debug_callback_free) + debug_cbid := registerCallbackId(debug) + c_debug.user_data = C.alloc_cbid(C.long(debug_cbid)) + + ret := C._nbd_set_debug_callback_wrapper (&c_err, h.h, c_debug) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("set_debug_callback", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* ClearDebugCallback: clear the debug callback */ +func (h *Libnbd) ClearDebugCallback () error { + if h.h == nil { + return closed_handle_error ("clear_debug_callback") + } + + var c_err C.struct_error + + ret := C._nbd_clear_debug_callback_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("clear_debug_callback", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* SetHandleName: set the handle name */ +func (h *Libnbd) SetHandleName (handle_name string) error { + if h.h == nil { + return closed_handle_error ("set_handle_name") + } + + var c_err C.struct_error + c_handle_name := C.CString (handle_name) + defer C.free (unsafe.Pointer (c_handle_name)) + + ret := C._nbd_set_handle_name_wrapper (&c_err, h.h, c_handle_name) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("set_handle_name", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* GetHandleName: get the handle name */ +func (h *Libnbd) GetHandleName () (*string, error) { + if h.h == nil { + return nil, closed_handle_error ("get_handle_name") + } + + var c_err C.struct_error + + ret := C._nbd_get_handle_name_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == nil { + err := get_error ("get_handle_name", c_err) + C.free_error (&c_err) + return nil, err + } + r := C.GoString (ret) + C.free (unsafe.Pointer (ret)) + return &r, nil +} + +/* SetPrivateData: set the per-handle private data */ +func (h *Libnbd) SetPrivateData (private_data uint) (uint, error) { + if h.h == nil { + return 0, closed_handle_error ("set_private_data") + } + + var c_err C.struct_error + c_private_data := C.uintptr_t (private_data) + + ret := C._nbd_set_private_data_wrapper (&c_err, h.h, c_private_data) + runtime.KeepAlive (h.h) + return uint (ret), nil +} + +/* GetPrivateData: get the per-handle private data */ +func (h *Libnbd) GetPrivateData () (uint, error) { + if h.h == nil { + return 0, closed_handle_error ("get_private_data") + } + + var c_err C.struct_error + + ret := C._nbd_get_private_data_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + return uint (ret), nil +} + +/* SetExportName: set the export name */ +func (h *Libnbd) SetExportName (export_name string) error { + if h.h == nil { + return closed_handle_error ("set_export_name") + } + + var c_err C.struct_error + c_export_name := C.CString (export_name) + defer C.free (unsafe.Pointer (c_export_name)) + + ret := C._nbd_set_export_name_wrapper (&c_err, h.h, c_export_name) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("set_export_name", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* GetExportName: get the export name */ +func (h *Libnbd) GetExportName () (*string, error) { + if h.h == nil { + return nil, closed_handle_error ("get_export_name") + } + + var c_err C.struct_error + + ret := C._nbd_get_export_name_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == nil { + err := get_error ("get_export_name", c_err) + C.free_error (&c_err) + return nil, err + } + r := C.GoString (ret) + C.free (unsafe.Pointer (ret)) + return &r, nil +} + +/* SetRequestBlockSize: control whether NBD_OPT_GO requests block size */ +func (h *Libnbd) SetRequestBlockSize (request bool) error { + if h.h == nil { + return closed_handle_error ("set_request_block_size") + } + + var c_err C.struct_error + c_request := C.bool (request) + + ret := C._nbd_set_request_block_size_wrapper (&c_err, h.h, c_request) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("set_request_block_size", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* GetRequestBlockSize: see if NBD_OPT_GO requests block size */ +func (h *Libnbd) GetRequestBlockSize () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("get_request_block_size") + } + + var c_err C.struct_error + + ret := C._nbd_get_request_block_size_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("get_request_block_size", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* SetFullInfo: control whether NBD_OPT_GO requests extra details */ +func (h *Libnbd) SetFullInfo (request bool) error { + if h.h == nil { + return closed_handle_error ("set_full_info") + } + + var c_err C.struct_error + c_request := C.bool (request) + + ret := C._nbd_set_full_info_wrapper (&c_err, h.h, c_request) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("set_full_info", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* GetFullInfo: see if NBD_OPT_GO requests extra details */ +func (h *Libnbd) GetFullInfo () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("get_full_info") + } + + var c_err C.struct_error + + ret := C._nbd_get_full_info_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("get_full_info", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* GetCanonicalExportName: return the canonical export name, if the server has one */ +func (h *Libnbd) GetCanonicalExportName () (*string, error) { + if h.h == nil { + return nil, closed_handle_error ("get_canonical_export_name") + } + + var c_err C.struct_error + + ret := C._nbd_get_canonical_export_name_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == nil { + err := get_error ("get_canonical_export_name", c_err) + C.free_error (&c_err) + return nil, err + } + r := C.GoString (ret) + C.free (unsafe.Pointer (ret)) + return &r, nil +} + +/* GetExportDescription: return the export description, if the server has one */ +func (h *Libnbd) GetExportDescription () (*string, error) { + if h.h == nil { + return nil, closed_handle_error ("get_export_description") + } + + var c_err C.struct_error + + ret := C._nbd_get_export_description_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == nil { + err := get_error ("get_export_description", c_err) + C.free_error (&c_err) + return nil, err + } + r := C.GoString (ret) + C.free (unsafe.Pointer (ret)) + return &r, nil +} + +/* SetTls: enable or require TLS (authentication and encryption) */ +func (h *Libnbd) SetTls (tls Tls) error { + if h.h == nil { + return closed_handle_error ("set_tls") + } + + var c_err C.struct_error + c_tls := C.int (tls) + + ret := C._nbd_set_tls_wrapper (&c_err, h.h, c_tls) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("set_tls", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* GetTls: get the TLS request setting */ +func (h *Libnbd) GetTls () (Tls, error) { + if h.h == nil { + return 0, closed_handle_error ("get_tls") + } + + var c_err C.struct_error + + ret := C._nbd_get_tls_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + return Tls (ret), nil +} + +/* GetTlsNegotiated: find out if TLS was negotiated on a connection */ +func (h *Libnbd) GetTlsNegotiated () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("get_tls_negotiated") + } + + var c_err C.struct_error + + ret := C._nbd_get_tls_negotiated_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("get_tls_negotiated", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* SetTlsCertificates: set the path to the TLS certificates directory */ +func (h *Libnbd) SetTlsCertificates (dir string) error { + if h.h == nil { + return closed_handle_error ("set_tls_certificates") + } + + var c_err C.struct_error + c_dir := C.CString (dir) + defer C.free (unsafe.Pointer (c_dir)) + + ret := C._nbd_set_tls_certificates_wrapper (&c_err, h.h, c_dir) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("set_tls_certificates", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* SetTlsVerifyPeer: set whether we verify the identity of the server */ +func (h *Libnbd) SetTlsVerifyPeer (verify bool) error { + if h.h == nil { + return closed_handle_error ("set_tls_verify_peer") + } + + var c_err C.struct_error + c_verify := C.bool (verify) + + ret := C._nbd_set_tls_verify_peer_wrapper (&c_err, h.h, c_verify) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("set_tls_verify_peer", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* GetTlsVerifyPeer: get whether we verify the identity of the server */ +func (h *Libnbd) GetTlsVerifyPeer () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("get_tls_verify_peer") + } + + var c_err C.struct_error + + ret := C._nbd_get_tls_verify_peer_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("get_tls_verify_peer", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* SetTlsUsername: set the TLS username */ +func (h *Libnbd) SetTlsUsername (username string) error { + if h.h == nil { + return closed_handle_error ("set_tls_username") + } + + var c_err C.struct_error + c_username := C.CString (username) + defer C.free (unsafe.Pointer (c_username)) + + ret := C._nbd_set_tls_username_wrapper (&c_err, h.h, c_username) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("set_tls_username", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* GetTlsUsername: get the current TLS username */ +func (h *Libnbd) GetTlsUsername () (*string, error) { + if h.h == nil { + return nil, closed_handle_error ("get_tls_username") + } + + var c_err C.struct_error + + ret := C._nbd_get_tls_username_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == nil { + err := get_error ("get_tls_username", c_err) + C.free_error (&c_err) + return nil, err + } + r := C.GoString (ret) + C.free (unsafe.Pointer (ret)) + return &r, nil +} + +/* SetTlsPskFile: set the TLS Pre-Shared Keys (PSK) filename */ +func (h *Libnbd) SetTlsPskFile (filename string) error { + if h.h == nil { + return closed_handle_error ("set_tls_psk_file") + } + + var c_err C.struct_error + c_filename := C.CString (filename) + defer C.free (unsafe.Pointer (c_filename)) + + ret := C._nbd_set_tls_psk_file_wrapper (&c_err, h.h, c_filename) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("set_tls_psk_file", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* SetRequestStructuredReplies: control use of structured replies */ +func (h *Libnbd) SetRequestStructuredReplies (request bool) error { + if h.h == nil { + return closed_handle_error ("set_request_structured_replies") + } + + var c_err C.struct_error + c_request := C.bool (request) + + ret := C._nbd_set_request_structured_replies_wrapper (&c_err, h.h, c_request) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("set_request_structured_replies", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* GetRequestStructuredReplies: see if structured replies are attempted */ +func (h *Libnbd) GetRequestStructuredReplies () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("get_request_structured_replies") + } + + var c_err C.struct_error + + ret := C._nbd_get_request_structured_replies_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("get_request_structured_replies", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* GetStructuredRepliesNegotiated: see if structured replies are in use */ +func (h *Libnbd) GetStructuredRepliesNegotiated () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("get_structured_replies_negotiated") + } + + var c_err C.struct_error + + ret := C._nbd_get_structured_replies_negotiated_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("get_structured_replies_negotiated", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* SetHandshakeFlags: control use of handshake flags */ +func (h *Libnbd) SetHandshakeFlags (flags HandshakeFlag) error { + if h.h == nil { + return closed_handle_error ("set_handshake_flags") + } + + var c_err C.struct_error + c_flags := C.uint32_t (flags) + + ret := C._nbd_set_handshake_flags_wrapper (&c_err, h.h, c_flags) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("set_handshake_flags", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* GetHandshakeFlags: see which handshake flags are supported */ +func (h *Libnbd) GetHandshakeFlags () (HandshakeFlag, error) { + if h.h == nil { + return 0, closed_handle_error ("get_handshake_flags") + } + + var c_err C.struct_error + + ret := C._nbd_get_handshake_flags_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + return HandshakeFlag (ret), nil +} + +/* SetPreadInitialize: control whether libnbd pre-initializes read buffers */ +func (h *Libnbd) SetPreadInitialize (request bool) error { + if h.h == nil { + return closed_handle_error ("set_pread_initialize") + } + + var c_err C.struct_error + c_request := C.bool (request) + + ret := C._nbd_set_pread_initialize_wrapper (&c_err, h.h, c_request) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("set_pread_initialize", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* GetPreadInitialize: see whether libnbd pre-initializes read buffers */ +func (h *Libnbd) GetPreadInitialize () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("get_pread_initialize") + } + + var c_err C.struct_error + + ret := C._nbd_get_pread_initialize_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("get_pread_initialize", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* SetStrictMode: control how strictly to follow NBD protocol */ +func (h *Libnbd) SetStrictMode (flags Strict) error { + if h.h == nil { + return closed_handle_error ("set_strict_mode") + } + + var c_err C.struct_error + c_flags := C.uint32_t (flags) + + ret := C._nbd_set_strict_mode_wrapper (&c_err, h.h, c_flags) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("set_strict_mode", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* GetStrictMode: see which strictness flags are in effect */ +func (h *Libnbd) GetStrictMode () (Strict, error) { + if h.h == nil { + return 0, closed_handle_error ("get_strict_mode") + } + + var c_err C.struct_error + + ret := C._nbd_get_strict_mode_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + return Strict (ret), nil +} + +/* SetOptMode: control option mode, for pausing during option negotiation */ +func (h *Libnbd) SetOptMode (enable bool) error { + if h.h == nil { + return closed_handle_error ("set_opt_mode") + } + + var c_err C.struct_error + c_enable := C.bool (enable) + + ret := C._nbd_set_opt_mode_wrapper (&c_err, h.h, c_enable) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("set_opt_mode", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* GetOptMode: return whether option mode was enabled */ +func (h *Libnbd) GetOptMode () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("get_opt_mode") + } + + var c_err C.struct_error + + ret := C._nbd_get_opt_mode_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("get_opt_mode", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* OptGo: end negotiation and move on to using an export */ +func (h *Libnbd) OptGo () error { + if h.h == nil { + return closed_handle_error ("opt_go") + } + + var c_err C.struct_error + + ret := C._nbd_opt_go_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("opt_go", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* OptAbort: end negotiation and close the connection */ +func (h *Libnbd) OptAbort () error { + if h.h == nil { + return closed_handle_error ("opt_abort") + } + + var c_err C.struct_error + + ret := C._nbd_opt_abort_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("opt_abort", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* OptList: request the server to list all exports during negotiation */ +func (h *Libnbd) OptList (list ListCallback) (uint, error) { + if h.h == nil { + return 0, closed_handle_error ("opt_list") + } + + var c_err C.struct_error + var c_list C.nbd_list_callback + c_list.callback = (*[0]byte)(C._nbd_list_callback_wrapper) + c_list.free = (*[0]byte)(C._nbd_list_callback_free) + list_cbid := registerCallbackId(list) + c_list.user_data = C.alloc_cbid(C.long(list_cbid)) + + ret := C._nbd_opt_list_wrapper (&c_err, h.h, c_list) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("opt_list", c_err) + C.free_error (&c_err) + return 0, err + } + return uint (ret), nil +} + +/* OptInfo: request the server for information about an export */ +func (h *Libnbd) OptInfo () error { + if h.h == nil { + return closed_handle_error ("opt_info") + } + + var c_err C.struct_error + + ret := C._nbd_opt_info_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("opt_info", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* OptListMetaContext: request the server to list available meta contexts */ +func (h *Libnbd) OptListMetaContext (context ContextCallback) (uint, error) { + if h.h == nil { + return 0, closed_handle_error ("opt_list_meta_context") + } + + var c_err C.struct_error + var c_context C.nbd_context_callback + c_context.callback = (*[0]byte)(C._nbd_context_callback_wrapper) + c_context.free = (*[0]byte)(C._nbd_context_callback_free) + context_cbid := registerCallbackId(context) + c_context.user_data = C.alloc_cbid(C.long(context_cbid)) + + ret := C._nbd_opt_list_meta_context_wrapper (&c_err, h.h, c_context) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("opt_list_meta_context", c_err) + C.free_error (&c_err) + return 0, err + } + return uint (ret), nil +} + +/* AddMetaContext: ask server to negotiate metadata context */ +func (h *Libnbd) AddMetaContext (name string) error { + if h.h == nil { + return closed_handle_error ("add_meta_context") + } + + var c_err C.struct_error + c_name := C.CString (name) + defer C.free (unsafe.Pointer (c_name)) + + ret := C._nbd_add_meta_context_wrapper (&c_err, h.h, c_name) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("add_meta_context", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* GetNrMetaContexts: return the current number of requested meta contexts */ +func (h *Libnbd) GetNrMetaContexts () (uint, error) { + if h.h == nil { + return 0, closed_handle_error ("get_nr_meta_contexts") + } + + var c_err C.struct_error + + ret := C._nbd_get_nr_meta_contexts_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("get_nr_meta_contexts", c_err) + C.free_error (&c_err) + return 0, err + } + return uint (ret), nil +} + +/* GetMetaContext: return the i'th meta context request */ +func (h *Libnbd) GetMetaContext (i int) (*string, error) { + if h.h == nil { + return nil, closed_handle_error ("get_meta_context") + } + + var c_err C.struct_error + c_i := C.size_t (i) + + ret := C._nbd_get_meta_context_wrapper (&c_err, h.h, c_i) + runtime.KeepAlive (h.h) + if ret == nil { + err := get_error ("get_meta_context", c_err) + C.free_error (&c_err) + return nil, err + } + r := C.GoString (ret) + C.free (unsafe.Pointer (ret)) + return &r, nil +} + +/* ClearMetaContexts: reset the list of requested meta contexts */ +func (h *Libnbd) ClearMetaContexts () error { + if h.h == nil { + return closed_handle_error ("clear_meta_contexts") + } + + var c_err C.struct_error + + ret := C._nbd_clear_meta_contexts_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("clear_meta_contexts", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* SetUriAllowTransports: set the allowed transports in NBD URIs */ +func (h *Libnbd) SetUriAllowTransports (mask AllowTransport) error { + if h.h == nil { + return closed_handle_error ("set_uri_allow_transports") + } + + var c_err C.struct_error + c_mask := C.uint32_t (mask) + + ret := C._nbd_set_uri_allow_transports_wrapper (&c_err, h.h, c_mask) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("set_uri_allow_transports", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* SetUriAllowTls: set the allowed TLS settings in NBD URIs */ +func (h *Libnbd) SetUriAllowTls (tls Tls) error { + if h.h == nil { + return closed_handle_error ("set_uri_allow_tls") + } + + var c_err C.struct_error + c_tls := C.int (tls) + + ret := C._nbd_set_uri_allow_tls_wrapper (&c_err, h.h, c_tls) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("set_uri_allow_tls", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* SetUriAllowLocalFile: set the allowed transports in NBD URIs */ +func (h *Libnbd) SetUriAllowLocalFile (allow bool) error { + if h.h == nil { + return closed_handle_error ("set_uri_allow_local_file") + } + + var c_err C.struct_error + c_allow := C.bool (allow) + + ret := C._nbd_set_uri_allow_local_file_wrapper (&c_err, h.h, c_allow) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("set_uri_allow_local_file", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* ConnectUri: connect to NBD URI */ +func (h *Libnbd) ConnectUri (uri string) error { + if h.h == nil { + return closed_handle_error ("connect_uri") + } + + var c_err C.struct_error + c_uri := C.CString (uri) + defer C.free (unsafe.Pointer (c_uri)) + + ret := C._nbd_connect_uri_wrapper (&c_err, h.h, c_uri) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("connect_uri", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* ConnectUnix: connect to NBD server over a Unix domain socket */ +func (h *Libnbd) ConnectUnix (unixsocket string) error { + if h.h == nil { + return closed_handle_error ("connect_unix") + } + + var c_err C.struct_error + c_unixsocket := C.CString (unixsocket) + defer C.free (unsafe.Pointer (c_unixsocket)) + + ret := C._nbd_connect_unix_wrapper (&c_err, h.h, c_unixsocket) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("connect_unix", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* ConnectVsock: connect to NBD server over AF_VSOCK protocol */ +func (h *Libnbd) ConnectVsock (cid uint32, port uint32) error { + if h.h == nil { + return closed_handle_error ("connect_vsock") + } + + var c_err C.struct_error + c_cid := C.uint32_t (cid) + c_port := C.uint32_t (port) + + ret := C._nbd_connect_vsock_wrapper (&c_err, h.h, c_cid, c_port) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("connect_vsock", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* ConnectTcp: connect to NBD server over a TCP port */ +func (h *Libnbd) ConnectTcp (hostname string, port string) error { + if h.h == nil { + return closed_handle_error ("connect_tcp") + } + + var c_err C.struct_error + c_hostname := C.CString (hostname) + defer C.free (unsafe.Pointer (c_hostname)) + c_port := C.CString (port) + defer C.free (unsafe.Pointer (c_port)) + + ret := C._nbd_connect_tcp_wrapper (&c_err, h.h, c_hostname, c_port) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("connect_tcp", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* ConnectSocket: connect directly to a connected socket */ +func (h *Libnbd) ConnectSocket (sock int) error { + if h.h == nil { + return closed_handle_error ("connect_socket") + } + + var c_err C.struct_error + c_sock := C.int (sock) + + ret := C._nbd_connect_socket_wrapper (&c_err, h.h, c_sock) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("connect_socket", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* ConnectCommand: connect to NBD server command */ +func (h *Libnbd) ConnectCommand (argv []string) error { + if h.h == nil { + return closed_handle_error ("connect_command") + } + + var c_err C.struct_error + c_argv := arg_string_list (argv) + defer free_string_list (c_argv) + + ret := C._nbd_connect_command_wrapper (&c_err, h.h, &c_argv[0]) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("connect_command", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* ConnectSystemdSocketActivation: connect using systemd socket activation */ +func (h *Libnbd) ConnectSystemdSocketActivation (argv []string) error { + if h.h == nil { + return closed_handle_error ("connect_systemd_socket_activation") + } + + var c_err C.struct_error + c_argv := arg_string_list (argv) + defer free_string_list (c_argv) + + ret := C._nbd_connect_systemd_socket_activation_wrapper (&c_err, h.h, &c_argv[0]) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("connect_systemd_socket_activation", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* IsReadOnly: is the NBD export read-only? */ +func (h *Libnbd) IsReadOnly () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("is_read_only") + } + + var c_err C.struct_error + + ret := C._nbd_is_read_only_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("is_read_only", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* CanFlush: does the server support the flush command? */ +func (h *Libnbd) CanFlush () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("can_flush") + } + + var c_err C.struct_error + + ret := C._nbd_can_flush_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("can_flush", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* CanFua: does the server support the FUA flag? */ +func (h *Libnbd) CanFua () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("can_fua") + } + + var c_err C.struct_error + + ret := C._nbd_can_fua_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("can_fua", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* IsRotational: is the NBD disk rotational (like a disk)? */ +func (h *Libnbd) IsRotational () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("is_rotational") + } + + var c_err C.struct_error + + ret := C._nbd_is_rotational_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("is_rotational", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* CanTrim: does the server support the trim command? */ +func (h *Libnbd) CanTrim () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("can_trim") + } + + var c_err C.struct_error + + ret := C._nbd_can_trim_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("can_trim", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* CanZero: does the server support the zero command? */ +func (h *Libnbd) CanZero () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("can_zero") + } + + var c_err C.struct_error + + ret := C._nbd_can_zero_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("can_zero", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* CanFastZero: does the server support the fast zero flag? */ +func (h *Libnbd) CanFastZero () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("can_fast_zero") + } + + var c_err C.struct_error + + ret := C._nbd_can_fast_zero_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("can_fast_zero", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* CanDf: does the server support the don't fragment flag to pread? */ +func (h *Libnbd) CanDf () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("can_df") + } + + var c_err C.struct_error + + ret := C._nbd_can_df_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("can_df", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* CanMultiConn: does the server support multi-conn? */ +func (h *Libnbd) CanMultiConn () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("can_multi_conn") + } + + var c_err C.struct_error + + ret := C._nbd_can_multi_conn_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("can_multi_conn", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* CanCache: does the server support the cache command? */ +func (h *Libnbd) CanCache () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("can_cache") + } + + var c_err C.struct_error + + ret := C._nbd_can_cache_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("can_cache", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* CanMetaContext: does the server support a specific meta context? */ +func (h *Libnbd) CanMetaContext (metacontext string) (bool, error) { + if h.h == nil { + return false, closed_handle_error ("can_meta_context") + } + + var c_err C.struct_error + c_metacontext := C.CString (metacontext) + defer C.free (unsafe.Pointer (c_metacontext)) + + ret := C._nbd_can_meta_context_wrapper (&c_err, h.h, c_metacontext) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("can_meta_context", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* GetProtocol: return the NBD protocol variant */ +func (h *Libnbd) GetProtocol () (*string, error) { + if h.h == nil { + return nil, closed_handle_error ("get_protocol") + } + + var c_err C.struct_error + + ret := C._nbd_get_protocol_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == nil { + err := get_error ("get_protocol", c_err) + C.free_error (&c_err) + return nil, err + } + /* ret is statically allocated, do not free it. */ + r := C.GoString (ret); + return &r, nil +} + +/* GetSize: return the export size */ +func (h *Libnbd) GetSize () (uint64, error) { + if h.h == nil { + return 0, closed_handle_error ("get_size") + } + + var c_err C.struct_error + + ret := C._nbd_get_size_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("get_size", c_err) + C.free_error (&c_err) + return 0, err + } + return uint64 (ret), nil +} + +/* GetBlockSize: return a specific server block size constraint */ +func (h *Libnbd) GetBlockSize (size_type Size) (uint64, error) { + if h.h == nil { + return 0, closed_handle_error ("get_block_size") + } + + var c_err C.struct_error + c_size_type := C.int (size_type) + + ret := C._nbd_get_block_size_wrapper (&c_err, h.h, c_size_type) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("get_block_size", c_err) + C.free_error (&c_err) + return 0, err + } + return uint64 (ret), nil +} + +/* Struct carrying optional arguments for Pread. */ +type PreadOptargs struct { + /* Flags field is ignored unless FlagsSet == true. */ + FlagsSet bool + Flags CmdFlag +} + +/* Pread: read from the NBD server */ +func (h *Libnbd) Pread (buf []byte, offset uint64, optargs *PreadOptargs) error { + if h.h == nil { + return closed_handle_error ("pread") + } + + var c_err C.struct_error + c_buf := unsafe.Pointer (&buf[0]) + c_count := C.size_t (len (buf)) + c_offset := C.uint64_t (offset) + var c_flags C.uint32_t + if optargs != nil { + if optargs.FlagsSet { + c_flags = C.uint32_t (optargs.Flags) + } + } + + ret := C._nbd_pread_wrapper (&c_err, h.h, c_buf, c_count, c_offset, c_flags) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("pread", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* Struct carrying optional arguments for PreadStructured. */ +type PreadStructuredOptargs struct { + /* Flags field is ignored unless FlagsSet == true. */ + FlagsSet bool + Flags CmdFlag +} + +/* PreadStructured: read from the NBD server */ +func (h *Libnbd) PreadStructured (buf []byte, offset uint64, chunk ChunkCallback, optargs *PreadStructuredOptargs) error { + if h.h == nil { + return closed_handle_error ("pread_structured") + } + + var c_err C.struct_error + c_buf := unsafe.Pointer (&buf[0]) + c_count := C.size_t (len (buf)) + c_offset := C.uint64_t (offset) + var c_chunk C.nbd_chunk_callback + c_chunk.callback = (*[0]byte)(C._nbd_chunk_callback_wrapper) + c_chunk.free = (*[0]byte)(C._nbd_chunk_callback_free) + chunk_cbid := registerCallbackId(chunk) + c_chunk.user_data = C.alloc_cbid(C.long(chunk_cbid)) + var c_flags C.uint32_t + if optargs != nil { + if optargs.FlagsSet { + c_flags = C.uint32_t (optargs.Flags) + } + } + + ret := C._nbd_pread_structured_wrapper (&c_err, h.h, c_buf, c_count, c_offset, c_chunk, c_flags) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("pread_structured", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* Struct carrying optional arguments for Pwrite. */ +type PwriteOptargs struct { + /* Flags field is ignored unless FlagsSet == true. */ + FlagsSet bool + Flags CmdFlag +} + +/* Pwrite: write to the NBD server */ +func (h *Libnbd) Pwrite (buf []byte, offset uint64, optargs *PwriteOptargs) error { + if h.h == nil { + return closed_handle_error ("pwrite") + } + + var c_err C.struct_error + c_buf := unsafe.Pointer (&buf[0]) + c_count := C.size_t (len (buf)) + c_offset := C.uint64_t (offset) + var c_flags C.uint32_t + if optargs != nil { + if optargs.FlagsSet { + c_flags = C.uint32_t (optargs.Flags) + } + } + + ret := C._nbd_pwrite_wrapper (&c_err, h.h, c_buf, c_count, c_offset, c_flags) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("pwrite", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* Struct carrying optional arguments for Shutdown. */ +type ShutdownOptargs struct { + /* Flags field is ignored unless FlagsSet == true. */ + FlagsSet bool + Flags Shutdown +} + +/* Shutdown: disconnect from the NBD server */ +func (h *Libnbd) Shutdown (optargs *ShutdownOptargs) error { + if h.h == nil { + return closed_handle_error ("shutdown") + } + + var c_err C.struct_error + var c_flags C.uint32_t + if optargs != nil { + if optargs.FlagsSet { + c_flags = C.uint32_t (optargs.Flags) + } + } + + ret := C._nbd_shutdown_wrapper (&c_err, h.h, c_flags) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("shutdown", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* Struct carrying optional arguments for Flush. */ +type FlushOptargs struct { + /* Flags field is ignored unless FlagsSet == true. */ + FlagsSet bool + Flags CmdFlag +} + +/* Flush: send flush command to the NBD server */ +func (h *Libnbd) Flush (optargs *FlushOptargs) error { + if h.h == nil { + return closed_handle_error ("flush") + } + + var c_err C.struct_error + var c_flags C.uint32_t + if optargs != nil { + if optargs.FlagsSet { + c_flags = C.uint32_t (optargs.Flags) + } + } + + ret := C._nbd_flush_wrapper (&c_err, h.h, c_flags) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("flush", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* Struct carrying optional arguments for Trim. */ +type TrimOptargs struct { + /* Flags field is ignored unless FlagsSet == true. */ + FlagsSet bool + Flags CmdFlag +} + +/* Trim: send trim command to the NBD server */ +func (h *Libnbd) Trim (count uint64, offset uint64, optargs *TrimOptargs) error { + if h.h == nil { + return closed_handle_error ("trim") + } + + var c_err C.struct_error + c_count := C.uint64_t (count) + c_offset := C.uint64_t (offset) + var c_flags C.uint32_t + if optargs != nil { + if optargs.FlagsSet { + c_flags = C.uint32_t (optargs.Flags) + } + } + + ret := C._nbd_trim_wrapper (&c_err, h.h, c_count, c_offset, c_flags) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("trim", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* Struct carrying optional arguments for Cache. */ +type CacheOptargs struct { + /* Flags field is ignored unless FlagsSet == true. */ + FlagsSet bool + Flags CmdFlag +} + +/* Cache: send cache (prefetch) command to the NBD server */ +func (h *Libnbd) Cache (count uint64, offset uint64, optargs *CacheOptargs) error { + if h.h == nil { + return closed_handle_error ("cache") + } + + var c_err C.struct_error + c_count := C.uint64_t (count) + c_offset := C.uint64_t (offset) + var c_flags C.uint32_t + if optargs != nil { + if optargs.FlagsSet { + c_flags = C.uint32_t (optargs.Flags) + } + } + + ret := C._nbd_cache_wrapper (&c_err, h.h, c_count, c_offset, c_flags) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("cache", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* Struct carrying optional arguments for Zero. */ +type ZeroOptargs struct { + /* Flags field is ignored unless FlagsSet == true. */ + FlagsSet bool + Flags CmdFlag +} + +/* Zero: send write zeroes command to the NBD server */ +func (h *Libnbd) Zero (count uint64, offset uint64, optargs *ZeroOptargs) error { + if h.h == nil { + return closed_handle_error ("zero") + } + + var c_err C.struct_error + c_count := C.uint64_t (count) + c_offset := C.uint64_t (offset) + var c_flags C.uint32_t + if optargs != nil { + if optargs.FlagsSet { + c_flags = C.uint32_t (optargs.Flags) + } + } + + ret := C._nbd_zero_wrapper (&c_err, h.h, c_count, c_offset, c_flags) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("zero", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* Struct carrying optional arguments for BlockStatus. */ +type BlockStatusOptargs struct { + /* Flags field is ignored unless FlagsSet == true. */ + FlagsSet bool + Flags CmdFlag +} + +/* BlockStatus: send block status command to the NBD server */ +func (h *Libnbd) BlockStatus (count uint64, offset uint64, extent ExtentCallback, optargs *BlockStatusOptargs) error { + if h.h == nil { + return closed_handle_error ("block_status") + } + + var c_err C.struct_error + c_count := C.uint64_t (count) + c_offset := C.uint64_t (offset) + var c_extent C.nbd_extent_callback + c_extent.callback = (*[0]byte)(C._nbd_extent_callback_wrapper) + c_extent.free = (*[0]byte)(C._nbd_extent_callback_free) + extent_cbid := registerCallbackId(extent) + c_extent.user_data = C.alloc_cbid(C.long(extent_cbid)) + var c_flags C.uint32_t + if optargs != nil { + if optargs.FlagsSet { + c_flags = C.uint32_t (optargs.Flags) + } + } + + ret := C._nbd_block_status_wrapper (&c_err, h.h, c_count, c_offset, c_extent, c_flags) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("block_status", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* Poll: poll the handle once */ +func (h *Libnbd) Poll (timeout int) (uint, error) { + if h.h == nil { + return 0, closed_handle_error ("poll") + } + + var c_err C.struct_error + c_timeout := C.int (timeout) + + ret := C._nbd_poll_wrapper (&c_err, h.h, c_timeout) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("poll", c_err) + C.free_error (&c_err) + return 0, err + } + return uint (ret), nil +} + +/* AioConnect: connect to the NBD server */ +func (h *Libnbd) AioConnect (addr string) error { + if h.h == nil { + return closed_handle_error ("aio_connect") + } + + var c_err C.struct_error + panic ("SockAddrAndLen not supported") + var c_addr *C.struct_sockaddr + var c_addrlen C.uint + + ret := C._nbd_aio_connect_wrapper (&c_err, h.h, c_addr, c_addrlen) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_connect", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* AioConnectUri: connect to an NBD URI */ +func (h *Libnbd) AioConnectUri (uri string) error { + if h.h == nil { + return closed_handle_error ("aio_connect_uri") + } + + var c_err C.struct_error + c_uri := C.CString (uri) + defer C.free (unsafe.Pointer (c_uri)) + + ret := C._nbd_aio_connect_uri_wrapper (&c_err, h.h, c_uri) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_connect_uri", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* AioConnectUnix: connect to the NBD server over a Unix domain socket */ +func (h *Libnbd) AioConnectUnix (unixsocket string) error { + if h.h == nil { + return closed_handle_error ("aio_connect_unix") + } + + var c_err C.struct_error + c_unixsocket := C.CString (unixsocket) + defer C.free (unsafe.Pointer (c_unixsocket)) + + ret := C._nbd_aio_connect_unix_wrapper (&c_err, h.h, c_unixsocket) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_connect_unix", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* AioConnectVsock: connect to the NBD server over AF_VSOCK socket */ +func (h *Libnbd) AioConnectVsock (cid uint32, port uint32) error { + if h.h == nil { + return closed_handle_error ("aio_connect_vsock") + } + + var c_err C.struct_error + c_cid := C.uint32_t (cid) + c_port := C.uint32_t (port) + + ret := C._nbd_aio_connect_vsock_wrapper (&c_err, h.h, c_cid, c_port) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_connect_vsock", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* AioConnectTcp: connect to the NBD server over a TCP port */ +func (h *Libnbd) AioConnectTcp (hostname string, port string) error { + if h.h == nil { + return closed_handle_error ("aio_connect_tcp") + } + + var c_err C.struct_error + c_hostname := C.CString (hostname) + defer C.free (unsafe.Pointer (c_hostname)) + c_port := C.CString (port) + defer C.free (unsafe.Pointer (c_port)) + + ret := C._nbd_aio_connect_tcp_wrapper (&c_err, h.h, c_hostname, c_port) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_connect_tcp", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* AioConnectSocket: connect directly to a connected socket */ +func (h *Libnbd) AioConnectSocket (sock int) error { + if h.h == nil { + return closed_handle_error ("aio_connect_socket") + } + + var c_err C.struct_error + c_sock := C.int (sock) + + ret := C._nbd_aio_connect_socket_wrapper (&c_err, h.h, c_sock) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_connect_socket", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* AioConnectCommand: connect to the NBD server */ +func (h *Libnbd) AioConnectCommand (argv []string) error { + if h.h == nil { + return closed_handle_error ("aio_connect_command") + } + + var c_err C.struct_error + c_argv := arg_string_list (argv) + defer free_string_list (c_argv) + + ret := C._nbd_aio_connect_command_wrapper (&c_err, h.h, &c_argv[0]) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_connect_command", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* AioConnectSystemdSocketActivation: connect using systemd socket activation */ +func (h *Libnbd) AioConnectSystemdSocketActivation (argv []string) error { + if h.h == nil { + return closed_handle_error ("aio_connect_systemd_socket_activation") + } + + var c_err C.struct_error + c_argv := arg_string_list (argv) + defer free_string_list (c_argv) + + ret := C._nbd_aio_connect_systemd_socket_activation_wrapper (&c_err, h.h, &c_argv[0]) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_connect_systemd_socket_activation", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* Struct carrying optional arguments for AioOptGo. */ +type AioOptGoOptargs struct { + /* CompletionCallback field is ignored unless CompletionCallbackSet == true. */ + CompletionCallbackSet bool + CompletionCallback CompletionCallback +} + +/* AioOptGo: end negotiation and move on to using an export */ +func (h *Libnbd) AioOptGo (optargs *AioOptGoOptargs) error { + if h.h == nil { + return closed_handle_error ("aio_opt_go") + } + + var c_err C.struct_error + var c_completion C.nbd_completion_callback + if optargs != nil { + if optargs.CompletionCallbackSet { + c_completion.callback = (*[0]byte)(C._nbd_completion_callback_wrapper) + c_completion.free = (*[0]byte)(C._nbd_completion_callback_free) + completion_cbid := registerCallbackId(optargs.CompletionCallback) + c_completion.user_data = C.alloc_cbid(C.long(completion_cbid)) + } + } + + ret := C._nbd_aio_opt_go_wrapper (&c_err, h.h, c_completion) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_opt_go", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* AioOptAbort: end negotiation and close the connection */ +func (h *Libnbd) AioOptAbort () error { + if h.h == nil { + return closed_handle_error ("aio_opt_abort") + } + + var c_err C.struct_error + + ret := C._nbd_aio_opt_abort_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_opt_abort", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* Struct carrying optional arguments for AioOptList. */ +type AioOptListOptargs struct { + /* CompletionCallback field is ignored unless CompletionCallbackSet == true. */ + CompletionCallbackSet bool + CompletionCallback CompletionCallback +} + +/* AioOptList: request the server to list all exports during negotiation */ +func (h *Libnbd) AioOptList (list ListCallback, optargs *AioOptListOptargs) error { + if h.h == nil { + return closed_handle_error ("aio_opt_list") + } + + var c_err C.struct_error + var c_list C.nbd_list_callback + c_list.callback = (*[0]byte)(C._nbd_list_callback_wrapper) + c_list.free = (*[0]byte)(C._nbd_list_callback_free) + list_cbid := registerCallbackId(list) + c_list.user_data = C.alloc_cbid(C.long(list_cbid)) + var c_completion C.nbd_completion_callback + if optargs != nil { + if optargs.CompletionCallbackSet { + c_completion.callback = (*[0]byte)(C._nbd_completion_callback_wrapper) + c_completion.free = (*[0]byte)(C._nbd_completion_callback_free) + completion_cbid := registerCallbackId(optargs.CompletionCallback) + c_completion.user_data = C.alloc_cbid(C.long(completion_cbid)) + } + } + + ret := C._nbd_aio_opt_list_wrapper (&c_err, h.h, c_list, c_completion) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_opt_list", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* Struct carrying optional arguments for AioOptInfo. */ +type AioOptInfoOptargs struct { + /* CompletionCallback field is ignored unless CompletionCallbackSet == true. */ + CompletionCallbackSet bool + CompletionCallback CompletionCallback +} + +/* AioOptInfo: request the server for information about an export */ +func (h *Libnbd) AioOptInfo (optargs *AioOptInfoOptargs) error { + if h.h == nil { + return closed_handle_error ("aio_opt_info") + } + + var c_err C.struct_error + var c_completion C.nbd_completion_callback + if optargs != nil { + if optargs.CompletionCallbackSet { + c_completion.callback = (*[0]byte)(C._nbd_completion_callback_wrapper) + c_completion.free = (*[0]byte)(C._nbd_completion_callback_free) + completion_cbid := registerCallbackId(optargs.CompletionCallback) + c_completion.user_data = C.alloc_cbid(C.long(completion_cbid)) + } + } + + ret := C._nbd_aio_opt_info_wrapper (&c_err, h.h, c_completion) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_opt_info", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* Struct carrying optional arguments for AioOptListMetaContext. */ +type AioOptListMetaContextOptargs struct { + /* CompletionCallback field is ignored unless CompletionCallbackSet == true. */ + CompletionCallbackSet bool + CompletionCallback CompletionCallback +} + +/* AioOptListMetaContext: request the server to list available meta contexts */ +func (h *Libnbd) AioOptListMetaContext (context ContextCallback, optargs *AioOptListMetaContextOptargs) (uint, error) { + if h.h == nil { + return 0, closed_handle_error ("aio_opt_list_meta_context") + } + + var c_err C.struct_error + var c_context C.nbd_context_callback + c_context.callback = (*[0]byte)(C._nbd_context_callback_wrapper) + c_context.free = (*[0]byte)(C._nbd_context_callback_free) + context_cbid := registerCallbackId(context) + c_context.user_data = C.alloc_cbid(C.long(context_cbid)) + var c_completion C.nbd_completion_callback + if optargs != nil { + if optargs.CompletionCallbackSet { + c_completion.callback = (*[0]byte)(C._nbd_completion_callback_wrapper) + c_completion.free = (*[0]byte)(C._nbd_completion_callback_free) + completion_cbid := registerCallbackId(optargs.CompletionCallback) + c_completion.user_data = C.alloc_cbid(C.long(completion_cbid)) + } + } + + ret := C._nbd_aio_opt_list_meta_context_wrapper (&c_err, h.h, c_context, c_completion) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_opt_list_meta_context", c_err) + C.free_error (&c_err) + return 0, err + } + return uint (ret), nil +} + +/* Struct carrying optional arguments for AioPread. */ +type AioPreadOptargs struct { + /* CompletionCallback field is ignored unless CompletionCallbackSet == true. */ + CompletionCallbackSet bool + CompletionCallback CompletionCallback + /* Flags field is ignored unless FlagsSet == true. */ + FlagsSet bool + Flags CmdFlag +} + +/* AioPread: read from the NBD server */ +func (h *Libnbd) AioPread (buf AioBuffer, offset uint64, optargs *AioPreadOptargs) (uint64, error) { + if h.h == nil { + return 0, closed_handle_error ("aio_pread") + } + + var c_err C.struct_error + c_buf := buf.P + c_count := C.size_t (buf.Size) + c_offset := C.uint64_t (offset) + var c_completion C.nbd_completion_callback + var c_flags C.uint32_t + if optargs != nil { + if optargs.CompletionCallbackSet { + c_completion.callback = (*[0]byte)(C._nbd_completion_callback_wrapper) + c_completion.free = (*[0]byte)(C._nbd_completion_callback_free) + completion_cbid := registerCallbackId(optargs.CompletionCallback) + c_completion.user_data = C.alloc_cbid(C.long(completion_cbid)) + } + if optargs.FlagsSet { + c_flags = C.uint32_t (optargs.Flags) + } + } + + ret := C._nbd_aio_pread_wrapper (&c_err, h.h, c_buf, c_count, c_offset, c_completion, c_flags) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_pread", c_err) + C.free_error (&c_err) + return 0, err + } + return uint64 (ret), nil +} + +/* Struct carrying optional arguments for AioPreadStructured. */ +type AioPreadStructuredOptargs struct { + /* CompletionCallback field is ignored unless CompletionCallbackSet == true. */ + CompletionCallbackSet bool + CompletionCallback CompletionCallback + /* Flags field is ignored unless FlagsSet == true. */ + FlagsSet bool + Flags CmdFlag +} + +/* AioPreadStructured: read from the NBD server */ +func (h *Libnbd) AioPreadStructured (buf AioBuffer, offset uint64, chunk ChunkCallback, optargs *AioPreadStructuredOptargs) (uint64, error) { + if h.h == nil { + return 0, closed_handle_error ("aio_pread_structured") + } + + var c_err C.struct_error + c_buf := buf.P + c_count := C.size_t (buf.Size) + c_offset := C.uint64_t (offset) + var c_chunk C.nbd_chunk_callback + c_chunk.callback = (*[0]byte)(C._nbd_chunk_callback_wrapper) + c_chunk.free = (*[0]byte)(C._nbd_chunk_callback_free) + chunk_cbid := registerCallbackId(chunk) + c_chunk.user_data = C.alloc_cbid(C.long(chunk_cbid)) + var c_completion C.nbd_completion_callback + var c_flags C.uint32_t + if optargs != nil { + if optargs.CompletionCallbackSet { + c_completion.callback = (*[0]byte)(C._nbd_completion_callback_wrapper) + c_completion.free = (*[0]byte)(C._nbd_completion_callback_free) + completion_cbid := registerCallbackId(optargs.CompletionCallback) + c_completion.user_data = C.alloc_cbid(C.long(completion_cbid)) + } + if optargs.FlagsSet { + c_flags = C.uint32_t (optargs.Flags) + } + } + + ret := C._nbd_aio_pread_structured_wrapper (&c_err, h.h, c_buf, c_count, c_offset, c_chunk, c_completion, c_flags) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_pread_structured", c_err) + C.free_error (&c_err) + return 0, err + } + return uint64 (ret), nil +} + +/* Struct carrying optional arguments for AioPwrite. */ +type AioPwriteOptargs struct { + /* CompletionCallback field is ignored unless CompletionCallbackSet == true. */ + CompletionCallbackSet bool + CompletionCallback CompletionCallback + /* Flags field is ignored unless FlagsSet == true. */ + FlagsSet bool + Flags CmdFlag +} + +/* AioPwrite: write to the NBD server */ +func (h *Libnbd) AioPwrite (buf AioBuffer, offset uint64, optargs *AioPwriteOptargs) (uint64, error) { + if h.h == nil { + return 0, closed_handle_error ("aio_pwrite") + } + + var c_err C.struct_error + c_buf := buf.P + c_count := C.size_t (buf.Size) + c_offset := C.uint64_t (offset) + var c_completion C.nbd_completion_callback + var c_flags C.uint32_t + if optargs != nil { + if optargs.CompletionCallbackSet { + c_completion.callback = (*[0]byte)(C._nbd_completion_callback_wrapper) + c_completion.free = (*[0]byte)(C._nbd_completion_callback_free) + completion_cbid := registerCallbackId(optargs.CompletionCallback) + c_completion.user_data = C.alloc_cbid(C.long(completion_cbid)) + } + if optargs.FlagsSet { + c_flags = C.uint32_t (optargs.Flags) + } + } + + ret := C._nbd_aio_pwrite_wrapper (&c_err, h.h, c_buf, c_count, c_offset, c_completion, c_flags) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_pwrite", c_err) + C.free_error (&c_err) + return 0, err + } + return uint64 (ret), nil +} + +/* Struct carrying optional arguments for AioDisconnect. */ +type AioDisconnectOptargs struct { + /* Flags field is ignored unless FlagsSet == true. */ + FlagsSet bool + Flags CmdFlag +} + +/* AioDisconnect: disconnect from the NBD server */ +func (h *Libnbd) AioDisconnect (optargs *AioDisconnectOptargs) error { + if h.h == nil { + return closed_handle_error ("aio_disconnect") + } + + var c_err C.struct_error + var c_flags C.uint32_t + if optargs != nil { + if optargs.FlagsSet { + c_flags = C.uint32_t (optargs.Flags) + } + } + + ret := C._nbd_aio_disconnect_wrapper (&c_err, h.h, c_flags) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_disconnect", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* Struct carrying optional arguments for AioFlush. */ +type AioFlushOptargs struct { + /* CompletionCallback field is ignored unless CompletionCallbackSet == true. */ + CompletionCallbackSet bool + CompletionCallback CompletionCallback + /* Flags field is ignored unless FlagsSet == true. */ + FlagsSet bool + Flags CmdFlag +} + +/* AioFlush: send flush command to the NBD server */ +func (h *Libnbd) AioFlush (optargs *AioFlushOptargs) (uint64, error) { + if h.h == nil { + return 0, closed_handle_error ("aio_flush") + } + + var c_err C.struct_error + var c_completion C.nbd_completion_callback + var c_flags C.uint32_t + if optargs != nil { + if optargs.CompletionCallbackSet { + c_completion.callback = (*[0]byte)(C._nbd_completion_callback_wrapper) + c_completion.free = (*[0]byte)(C._nbd_completion_callback_free) + completion_cbid := registerCallbackId(optargs.CompletionCallback) + c_completion.user_data = C.alloc_cbid(C.long(completion_cbid)) + } + if optargs.FlagsSet { + c_flags = C.uint32_t (optargs.Flags) + } + } + + ret := C._nbd_aio_flush_wrapper (&c_err, h.h, c_completion, c_flags) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_flush", c_err) + C.free_error (&c_err) + return 0, err + } + return uint64 (ret), nil +} + +/* Struct carrying optional arguments for AioTrim. */ +type AioTrimOptargs struct { + /* CompletionCallback field is ignored unless CompletionCallbackSet == true. */ + CompletionCallbackSet bool + CompletionCallback CompletionCallback + /* Flags field is ignored unless FlagsSet == true. */ + FlagsSet bool + Flags CmdFlag +} + +/* AioTrim: send trim command to the NBD server */ +func (h *Libnbd) AioTrim (count uint64, offset uint64, optargs *AioTrimOptargs) (uint64, error) { + if h.h == nil { + return 0, closed_handle_error ("aio_trim") + } + + var c_err C.struct_error + c_count := C.uint64_t (count) + c_offset := C.uint64_t (offset) + var c_completion C.nbd_completion_callback + var c_flags C.uint32_t + if optargs != nil { + if optargs.CompletionCallbackSet { + c_completion.callback = (*[0]byte)(C._nbd_completion_callback_wrapper) + c_completion.free = (*[0]byte)(C._nbd_completion_callback_free) + completion_cbid := registerCallbackId(optargs.CompletionCallback) + c_completion.user_data = C.alloc_cbid(C.long(completion_cbid)) + } + if optargs.FlagsSet { + c_flags = C.uint32_t (optargs.Flags) + } + } + + ret := C._nbd_aio_trim_wrapper (&c_err, h.h, c_count, c_offset, c_completion, c_flags) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_trim", c_err) + C.free_error (&c_err) + return 0, err + } + return uint64 (ret), nil +} + +/* Struct carrying optional arguments for AioCache. */ +type AioCacheOptargs struct { + /* CompletionCallback field is ignored unless CompletionCallbackSet == true. */ + CompletionCallbackSet bool + CompletionCallback CompletionCallback + /* Flags field is ignored unless FlagsSet == true. */ + FlagsSet bool + Flags CmdFlag +} + +/* AioCache: send cache (prefetch) command to the NBD server */ +func (h *Libnbd) AioCache (count uint64, offset uint64, optargs *AioCacheOptargs) (uint64, error) { + if h.h == nil { + return 0, closed_handle_error ("aio_cache") + } + + var c_err C.struct_error + c_count := C.uint64_t (count) + c_offset := C.uint64_t (offset) + var c_completion C.nbd_completion_callback + var c_flags C.uint32_t + if optargs != nil { + if optargs.CompletionCallbackSet { + c_completion.callback = (*[0]byte)(C._nbd_completion_callback_wrapper) + c_completion.free = (*[0]byte)(C._nbd_completion_callback_free) + completion_cbid := registerCallbackId(optargs.CompletionCallback) + c_completion.user_data = C.alloc_cbid(C.long(completion_cbid)) + } + if optargs.FlagsSet { + c_flags = C.uint32_t (optargs.Flags) + } + } + + ret := C._nbd_aio_cache_wrapper (&c_err, h.h, c_count, c_offset, c_completion, c_flags) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_cache", c_err) + C.free_error (&c_err) + return 0, err + } + return uint64 (ret), nil +} + +/* Struct carrying optional arguments for AioZero. */ +type AioZeroOptargs struct { + /* CompletionCallback field is ignored unless CompletionCallbackSet == true. */ + CompletionCallbackSet bool + CompletionCallback CompletionCallback + /* Flags field is ignored unless FlagsSet == true. */ + FlagsSet bool + Flags CmdFlag +} + +/* AioZero: send write zeroes command to the NBD server */ +func (h *Libnbd) AioZero (count uint64, offset uint64, optargs *AioZeroOptargs) (uint64, error) { + if h.h == nil { + return 0, closed_handle_error ("aio_zero") + } + + var c_err C.struct_error + c_count := C.uint64_t (count) + c_offset := C.uint64_t (offset) + var c_completion C.nbd_completion_callback + var c_flags C.uint32_t + if optargs != nil { + if optargs.CompletionCallbackSet { + c_completion.callback = (*[0]byte)(C._nbd_completion_callback_wrapper) + c_completion.free = (*[0]byte)(C._nbd_completion_callback_free) + completion_cbid := registerCallbackId(optargs.CompletionCallback) + c_completion.user_data = C.alloc_cbid(C.long(completion_cbid)) + } + if optargs.FlagsSet { + c_flags = C.uint32_t (optargs.Flags) + } + } + + ret := C._nbd_aio_zero_wrapper (&c_err, h.h, c_count, c_offset, c_completion, c_flags) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_zero", c_err) + C.free_error (&c_err) + return 0, err + } + return uint64 (ret), nil +} + +/* Struct carrying optional arguments for AioBlockStatus. */ +type AioBlockStatusOptargs struct { + /* CompletionCallback field is ignored unless CompletionCallbackSet == true. */ + CompletionCallbackSet bool + CompletionCallback CompletionCallback + /* Flags field is ignored unless FlagsSet == true. */ + FlagsSet bool + Flags CmdFlag +} + +/* AioBlockStatus: send block status command to the NBD server */ +func (h *Libnbd) AioBlockStatus (count uint64, offset uint64, extent ExtentCallback, optargs *AioBlockStatusOptargs) (uint64, error) { + if h.h == nil { + return 0, closed_handle_error ("aio_block_status") + } + + var c_err C.struct_error + c_count := C.uint64_t (count) + c_offset := C.uint64_t (offset) + var c_extent C.nbd_extent_callback + c_extent.callback = (*[0]byte)(C._nbd_extent_callback_wrapper) + c_extent.free = (*[0]byte)(C._nbd_extent_callback_free) + extent_cbid := registerCallbackId(extent) + c_extent.user_data = C.alloc_cbid(C.long(extent_cbid)) + var c_completion C.nbd_completion_callback + var c_flags C.uint32_t + if optargs != nil { + if optargs.CompletionCallbackSet { + c_completion.callback = (*[0]byte)(C._nbd_completion_callback_wrapper) + c_completion.free = (*[0]byte)(C._nbd_completion_callback_free) + completion_cbid := registerCallbackId(optargs.CompletionCallback) + c_completion.user_data = C.alloc_cbid(C.long(completion_cbid)) + } + if optargs.FlagsSet { + c_flags = C.uint32_t (optargs.Flags) + } + } + + ret := C._nbd_aio_block_status_wrapper (&c_err, h.h, c_count, c_offset, c_extent, c_completion, c_flags) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_block_status", c_err) + C.free_error (&c_err) + return 0, err + } + return uint64 (ret), nil +} + +/* AioGetFd: return file descriptor associated with this connection */ +func (h *Libnbd) AioGetFd () (int, error) { + if h.h == nil { + return 0, closed_handle_error ("aio_get_fd") + } + + var c_err C.struct_error + + ret := C._nbd_aio_get_fd_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_get_fd", c_err) + C.free_error (&c_err) + return 0, err + } + return int (ret), nil +} + +/* AioGetDirection: return the read or write direction */ +func (h *Libnbd) AioGetDirection () (uint, error) { + if h.h == nil { + return 0, closed_handle_error ("aio_get_direction") + } + + var c_err C.struct_error + + ret := C._nbd_aio_get_direction_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + return uint (ret), nil +} + +/* AioNotifyRead: notify that the connection is readable */ +func (h *Libnbd) AioNotifyRead () error { + if h.h == nil { + return closed_handle_error ("aio_notify_read") + } + + var c_err C.struct_error + + ret := C._nbd_aio_notify_read_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_notify_read", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* AioNotifyWrite: notify that the connection is writable */ +func (h *Libnbd) AioNotifyWrite () error { + if h.h == nil { + return closed_handle_error ("aio_notify_write") + } + + var c_err C.struct_error + + ret := C._nbd_aio_notify_write_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_notify_write", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* AioIsCreated: check if the connection has just been created */ +func (h *Libnbd) AioIsCreated () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("aio_is_created") + } + + var c_err C.struct_error + + ret := C._nbd_aio_is_created_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_is_created", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* AioIsConnecting: check if the connection is connecting or handshaking */ +func (h *Libnbd) AioIsConnecting () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("aio_is_connecting") + } + + var c_err C.struct_error + + ret := C._nbd_aio_is_connecting_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_is_connecting", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* AioIsNegotiating: check if connection is ready to send handshake option */ +func (h *Libnbd) AioIsNegotiating () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("aio_is_negotiating") + } + + var c_err C.struct_error + + ret := C._nbd_aio_is_negotiating_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_is_negotiating", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* AioIsReady: check if the connection is in the ready state */ +func (h *Libnbd) AioIsReady () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("aio_is_ready") + } + + var c_err C.struct_error + + ret := C._nbd_aio_is_ready_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_is_ready", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* AioIsProcessing: check if the connection is processing a command */ +func (h *Libnbd) AioIsProcessing () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("aio_is_processing") + } + + var c_err C.struct_error + + ret := C._nbd_aio_is_processing_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_is_processing", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* AioIsDead: check if the connection is dead */ +func (h *Libnbd) AioIsDead () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("aio_is_dead") + } + + var c_err C.struct_error + + ret := C._nbd_aio_is_dead_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_is_dead", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* AioIsClosed: check if the connection is closed */ +func (h *Libnbd) AioIsClosed () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("aio_is_closed") + } + + var c_err C.struct_error + + ret := C._nbd_aio_is_closed_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_is_closed", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* AioCommandCompleted: check if the command completed */ +func (h *Libnbd) AioCommandCompleted (cookie uint64) (bool, error) { + if h.h == nil { + return false, closed_handle_error ("aio_command_completed") + } + + var c_err C.struct_error + c_cookie := C.uint64_t (cookie) + + ret := C._nbd_aio_command_completed_wrapper (&c_err, h.h, c_cookie) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_command_completed", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* AioPeekCommandCompleted: check if any command has completed */ +func (h *Libnbd) AioPeekCommandCompleted () (uint64, error) { + if h.h == nil { + return 0, closed_handle_error ("aio_peek_command_completed") + } + + var c_err C.struct_error + + ret := C._nbd_aio_peek_command_completed_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_peek_command_completed", c_err) + C.free_error (&c_err) + return 0, err + } + return uint64 (ret), nil +} + +/* AioInFlight: check how many aio commands are still in flight */ +func (h *Libnbd) AioInFlight () (uint, error) { + if h.h == nil { + return 0, closed_handle_error ("aio_in_flight") + } + + var c_err C.struct_error + + ret := C._nbd_aio_in_flight_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("aio_in_flight", c_err) + C.free_error (&c_err) + return 0, err + } + return uint (ret), nil +} + +/* ConnectionState: return string describing the state of the connection */ +func (h *Libnbd) ConnectionState () (*string, error) { + if h.h == nil { + return nil, closed_handle_error ("connection_state") + } + + var c_err C.struct_error + + ret := C._nbd_connection_state_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == nil { + err := get_error ("connection_state", c_err) + C.free_error (&c_err) + return nil, err + } + /* ret is statically allocated, do not free it. */ + r := C.GoString (ret); + return &r, nil +} + +/* GetPackageName: return the name of the library */ +func (h *Libnbd) GetPackageName () (*string, error) { + if h.h == nil { + return nil, closed_handle_error ("get_package_name") + } + + var c_err C.struct_error + + ret := C._nbd_get_package_name_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == nil { + err := get_error ("get_package_name", c_err) + C.free_error (&c_err) + return nil, err + } + /* ret is statically allocated, do not free it. */ + r := C.GoString (ret); + return &r, nil +} + +/* GetVersion: return the version of the library */ +func (h *Libnbd) GetVersion () (*string, error) { + if h.h == nil { + return nil, closed_handle_error ("get_version") + } + + var c_err C.struct_error + + ret := C._nbd_get_version_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == nil { + err := get_error ("get_version", c_err) + C.free_error (&c_err) + return nil, err + } + /* ret is statically allocated, do not free it. */ + r := C.GoString (ret); + return &r, nil +} + +/* KillSubprocess: kill server running as a subprocess */ +func (h *Libnbd) KillSubprocess (signum int) error { + if h.h == nil { + return closed_handle_error ("kill_subprocess") + } + + var c_err C.struct_error + c_signum := C.int (signum) + + ret := C._nbd_kill_subprocess_wrapper (&c_err, h.h, c_signum) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("kill_subprocess", c_err) + C.free_error (&c_err) + return err + } + return nil +} + +/* SupportsTls: true if libnbd was compiled with support for TLS */ +func (h *Libnbd) SupportsTls () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("supports_tls") + } + + var c_err C.struct_error + + ret := C._nbd_supports_tls_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("supports_tls", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* SupportsUri: true if libnbd was compiled with support for NBD URIs */ +func (h *Libnbd) SupportsUri () (bool, error) { + if h.h == nil { + return false, closed_handle_error ("supports_uri") + } + + var c_err C.struct_error + + ret := C._nbd_supports_uri_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == -1 { + err := get_error ("supports_uri", c_err) + C.free_error (&c_err) + return false, err + } + r := int (ret) + if r != 0 { return true, nil } else { return false, nil } +} + +/* GetUri: construct an NBD URI for a connection */ +func (h *Libnbd) GetUri () (*string, error) { + if h.h == nil { + return nil, closed_handle_error ("get_uri") + } + + var c_err C.struct_error + + ret := C._nbd_get_uri_wrapper (&c_err, h.h) + runtime.KeepAlive (h.h) + if ret == nil { + err := get_error ("get_uri", c_err) + C.free_error (&c_err) + return nil, err + } + r := C.GoString (ret) + C.free (unsafe.Pointer (ret)) + return &r, nil +} + diff --git a/vendor/libguestfs.org/libnbd/callbacks.go b/vendor/libguestfs.org/libnbd/callbacks.go new file mode 100644 index 000000000..1ae8d8e59 --- /dev/null +++ b/vendor/libguestfs.org/libnbd/callbacks.go @@ -0,0 +1,102 @@ +/* + * This file is part of the libvirt-go project + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Copyright (c) 2013 Alex Zorin + * Copyright (C) 2016 Red Hat, Inc. + * + */ + +package libnbd + +// Helpers functions to register a Go callback function to a C +// function. For a simple example, look at how SetErrorFunc works in +// error.go. +// +// - Create a struct that will contain at least the Go callback to +// invoke (errorContext). +// +// - Create an exported Golang function whose job will be to retrieve +// the context and execute the callback in it +// (connErrCallback). Such a function should receive a callback ID +// and will use it to retrive the context. +// +// - Create a CGO function similar to the above function but with the +// appropriate signature to be registered as a callback in C code +// (connErrCallbackHelper). Notably, it will have a void* argument +// that should be cast to long to retrieve the callback ID. It +// should be just a thin wrapper to transform the opaque argument to +// a callback ID. +// +// - Create a CGO function which will be a wrapper around the C +// function to register the callback (virConnSetErrorFuncWrapper). Its +// only role is to transform a callback ID (long) to an opaque (void*) +// and call the C function. +// +// - When setting up a callback (SetErrorFunc), register the struct from first step +// with registerCallbackId and invoke the CGO function from the +// previous step with the appropriate ID. +// +// - When unregistering the callback, don't forget to call freecallbackId. +// +// If you need to associate some additional data with the connection, +// look at saveConnectionData, getConnectionData and +// releaseConnectionData. + +import "C" + +import ( + "sync" +) + +const firstGoCallbackId int = 100 // help catch some additional errors during test +var goCallbackLock sync.RWMutex +var goCallbacks = make(map[int]interface{}) +var nextGoCallbackId int = firstGoCallbackId + +//export freeCallbackId +func freeCallbackId(goCallbackId int) { + goCallbackLock.Lock() + delete(goCallbacks, goCallbackId) + goCallbackLock.Unlock() +} + +func getCallbackId(goCallbackId int) interface{} { + goCallbackLock.RLock() + ctx := goCallbacks[goCallbackId] + goCallbackLock.RUnlock() + if ctx == nil { + // If this happens there must be a bug in libvirt + panic("Callback arrived after freeCallbackId was called") + } + return ctx +} + +func registerCallbackId(ctx interface{}) int { + goCallbackLock.Lock() + goCallBackId := nextGoCallbackId + nextGoCallbackId++ + for goCallbacks[nextGoCallbackId] != nil { + nextGoCallbackId++ + } + goCallbacks[goCallBackId] = ctx + goCallbackLock.Unlock() + return goCallBackId +} diff --git a/vendor/libguestfs.org/libnbd/closures.go b/vendor/libguestfs.org/libnbd/closures.go new file mode 100644 index 000000000..b15985d13 --- /dev/null +++ b/vendor/libguestfs.org/libnbd/closures.go @@ -0,0 +1,131 @@ +/* NBD client library in userspace + * WARNING: THIS FILE IS GENERATED FROM + * generator/generator + * ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST. + * + * Copyright (C) 2013-2021 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package libnbd + +/* +#cgo pkg-config: libnbd +#cgo CFLAGS: -D_GNU_SOURCE=1 + +#include + +#include "libnbd.h" +#include "wrappers.h" +*/ +import "C" + +import "unsafe" + +/* Closures. */ + +func copy_uint32_array (entries *C.uint32_t, count C.size_t) []uint32 { + ret := make([]uint32, int (count)) + // See https://github.com/golang/go/wiki/cgo#turning-c-arrays-into-go-slices + // TODO: Use unsafe.Slice() when we require Go 1.17. + s := (*[1<<30]uint32)(unsafe.Pointer(entries))[:count:count] + copy(ret, s) + return ret +} +type ChunkCallback func (subbuf []byte, offset uint64, status uint, error *int) int + +//export chunk_callback +func chunk_callback (callbackid *C.long, subbuf unsafe.Pointer, count C.size_t, offset C.uint64_t, status C.uint, error *C.int) C.int { + callbackFunc := getCallbackId (int (*callbackid)); + callback, ok := callbackFunc.(ChunkCallback); + if !ok { + panic ("inappropriate callback type"); + } + go_error := int (*error) + ret := callback (C.GoBytes (subbuf, C.int (count)), uint64 (offset), uint (status), &go_error) + *error = C.int (go_error) + return C.int (ret); +} + +type CompletionCallback func (error *int) int + +//export completion_callback +func completion_callback (callbackid *C.long, error *C.int) C.int { + callbackFunc := getCallbackId (int (*callbackid)); + callback, ok := callbackFunc.(CompletionCallback); + if !ok { + panic ("inappropriate callback type"); + } + go_error := int (*error) + ret := callback (&go_error) + *error = C.int (go_error) + return C.int (ret); +} + +type DebugCallback func (context string, msg string) int + +//export debug_callback +func debug_callback (callbackid *C.long, context *C.char, msg *C.char) C.int { + callbackFunc := getCallbackId (int (*callbackid)); + callback, ok := callbackFunc.(DebugCallback); + if !ok { + panic ("inappropriate callback type"); + } + ret := callback (C.GoString (context), C.GoString (msg)) + return C.int (ret); +} + +type ExtentCallback func (metacontext string, offset uint64, entries []uint32, error *int) int + +//export extent_callback +func extent_callback (callbackid *C.long, metacontext *C.char, offset C.uint64_t, entries *C.uint32_t, nr_entries C.size_t, error *C.int) C.int { + callbackFunc := getCallbackId (int (*callbackid)); + callback, ok := callbackFunc.(ExtentCallback); + if !ok { + panic ("inappropriate callback type"); + } + go_error := int (*error) + ret := callback (C.GoString (metacontext), uint64 (offset), copy_uint32_array (entries, nr_entries), &go_error) + *error = C.int (go_error) + return C.int (ret); +} + +type ListCallback func (name string, description string) int + +//export list_callback +func list_callback (callbackid *C.long, name *C.char, description *C.char) C.int { + callbackFunc := getCallbackId (int (*callbackid)); + callback, ok := callbackFunc.(ListCallback); + if !ok { + panic ("inappropriate callback type"); + } + ret := callback (C.GoString (name), C.GoString (description)) + return C.int (ret); +} + +type ContextCallback func (name string) int + +//export context_callback +func context_callback (callbackid *C.long, name *C.char) C.int { + callbackFunc := getCallbackId (int (*callbackid)); + callback, ok := callbackFunc.(ContextCallback); + if !ok { + panic ("inappropriate callback type"); + } + ret := callback (C.GoString (name)) + return C.int (ret); +} + diff --git a/vendor/libguestfs.org/libnbd/handle.go b/vendor/libguestfs.org/libnbd/handle.go new file mode 100644 index 000000000..c8d9485dc --- /dev/null +++ b/vendor/libguestfs.org/libnbd/handle.go @@ -0,0 +1,133 @@ +/* libnbd golang handle. + * Copyright (C) 2013-2021 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package libnbd + +/* +#cgo pkg-config: libnbd +#cgo CFLAGS: -D_GNU_SOURCE=1 + +#include +#include + +#include "libnbd.h" +#include "wrappers.h" + +static struct nbd_handle * +_nbd_create_wrapper (struct error *err) +{ + struct nbd_handle *ret; + + ret = nbd_create (); + if (ret == NULL) + save_error (err); + return ret; +} +*/ +import "C" + +import ( + "fmt" + "runtime" + "syscall" + "unsafe" +) + +/* Handle. */ +type Libnbd struct { + h *C.struct_nbd_handle +} + +/* Convert handle to string (just for debugging). */ +func (h *Libnbd) String() string { + return "&Libnbd{}" +} + +/* All functions (except Close) return ([result,] LibnbdError). */ +type LibnbdError struct { + Op string // operation which failed + Errmsg string // string (nbd_get_error) + Errno syscall.Errno // errno (nbd_get_errno) +} + +func (e *LibnbdError) String() string { + if e.Errno != 0 { + return fmt.Sprintf("%s: %s", e.Op, e.Errmsg) + } else { + return fmt.Sprintf("%s: %s: %s", e.Op, e.Errmsg, e.Errno) + } +} + +/* Implement the error interface */ +func (e *LibnbdError) Error() string { + return e.String() +} + +func get_error(op string, c_err C.struct_error) *LibnbdError { + errmsg := C.GoString(c_err.error) + errno := syscall.Errno(c_err.errnum) + return &LibnbdError{Op: op, Errmsg: errmsg, Errno: errno} +} + +func closed_handle_error(op string) *LibnbdError { + return &LibnbdError{Op: op, Errmsg: "handle is closed", + Errno: syscall.Errno(0)} +} + +/* Create a new handle. */ +func Create() (*Libnbd, error) { + var c_err C.struct_error + c_h := C._nbd_create_wrapper(&c_err) + if c_h == nil { + err := get_error("create", c_err) + C.free_error(&c_err) + return nil, err + } + h := &Libnbd{h: c_h} + // Finalizers aren't guaranteed to run, but try having one anyway ... + runtime.SetFinalizer(h, (*Libnbd).Close) + return h, nil +} + +/* Close the handle. */ +func (h *Libnbd) Close() *LibnbdError { + if h.h == nil { + return closed_handle_error("close") + } + C.nbd_close(h.h) + h.h = nil + return nil +} + +/* Functions for translating between NULL-terminated lists of + * C strings and golang []string. + */ +func arg_string_list(xs []string) []*C.char { + r := make([]*C.char, 1+len(xs)) + for i, x := range xs { + r[i] = C.CString(x) + } + r[len(xs)] = nil + return r +} + +func free_string_list(argv []*C.char) { + for i := 0; argv[i] != nil; i++ { + C.free(unsafe.Pointer(argv[i])) + } +} diff --git a/vendor/libguestfs.org/libnbd/wrappers.go b/vendor/libguestfs.org/libnbd/wrappers.go new file mode 100644 index 000000000..341c836f0 --- /dev/null +++ b/vendor/libguestfs.org/libnbd/wrappers.go @@ -0,0 +1,2215 @@ +/* NBD client library in userspace + * WARNING: THIS FILE IS GENERATED FROM + * generator/generator + * ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST. + * + * Copyright (C) 2013-2021 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package libnbd + +/* +#cgo pkg-config: libnbd +#cgo CFLAGS: -D_GNU_SOURCE=1 + +#include +#include +#include + +#include "libnbd.h" +#include "wrappers.h" + +int +_nbd_set_debug_wrapper (struct error *err, + struct nbd_handle *h, bool debug) +{ +#ifdef LIBNBD_HAVE_NBD_SET_DEBUG + int ret; + + ret = nbd_set_debug (h, debug); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_SET_DEBUG + missing_function (err, "set_debug"); + return -1; +#endif +} + +int +_nbd_get_debug_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_GET_DEBUG + int ret; + + ret = nbd_get_debug (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_GET_DEBUG + missing_function (err, "get_debug"); + return -1; +#endif +} + +int +_nbd_set_debug_callback_wrapper (struct error *err, + struct nbd_handle *h, nbd_debug_callback debug_callback) +{ +#ifdef LIBNBD_HAVE_NBD_SET_DEBUG_CALLBACK + int ret; + + ret = nbd_set_debug_callback (h, debug_callback); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_SET_DEBUG_CALLBACK + missing_function (err, "set_debug_callback"); + return -1; +#endif +} + +int +_nbd_clear_debug_callback_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_CLEAR_DEBUG_CALLBACK + int ret; + + ret = nbd_clear_debug_callback (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_CLEAR_DEBUG_CALLBACK + missing_function (err, "clear_debug_callback"); + return -1; +#endif +} + +int +_nbd_set_handle_name_wrapper (struct error *err, + struct nbd_handle *h, const char *handle_name) +{ +#ifdef LIBNBD_HAVE_NBD_SET_HANDLE_NAME + int ret; + + ret = nbd_set_handle_name (h, handle_name); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_SET_HANDLE_NAME + missing_function (err, "set_handle_name"); + return -1; +#endif +} + +char * +_nbd_get_handle_name_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_GET_HANDLE_NAME + char * ret; + + ret = nbd_get_handle_name (h); + if (ret == NULL) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_GET_HANDLE_NAME + missing_function (err, "get_handle_name"); + return NULL; +#endif +} + +uintptr_t +_nbd_set_private_data_wrapper (struct error *err, + struct nbd_handle *h, uintptr_t private_data) +{ +#ifdef LIBNBD_HAVE_NBD_SET_PRIVATE_DATA + uintptr_t ret; + + ret = nbd_set_private_data (h, private_data); + return ret; +#else // !LIBNBD_HAVE_NBD_SET_PRIVATE_DATA + missing_function (err, "set_private_data"); +#endif +} + +uintptr_t +_nbd_get_private_data_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_GET_PRIVATE_DATA + uintptr_t ret; + + ret = nbd_get_private_data (h); + return ret; +#else // !LIBNBD_HAVE_NBD_GET_PRIVATE_DATA + missing_function (err, "get_private_data"); +#endif +} + +int +_nbd_set_export_name_wrapper (struct error *err, + struct nbd_handle *h, const char *export_name) +{ +#ifdef LIBNBD_HAVE_NBD_SET_EXPORT_NAME + int ret; + + ret = nbd_set_export_name (h, export_name); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_SET_EXPORT_NAME + missing_function (err, "set_export_name"); + return -1; +#endif +} + +char * +_nbd_get_export_name_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_GET_EXPORT_NAME + char * ret; + + ret = nbd_get_export_name (h); + if (ret == NULL) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_GET_EXPORT_NAME + missing_function (err, "get_export_name"); + return NULL; +#endif +} + +int +_nbd_set_request_block_size_wrapper (struct error *err, + struct nbd_handle *h, bool request) +{ +#ifdef LIBNBD_HAVE_NBD_SET_REQUEST_BLOCK_SIZE + int ret; + + ret = nbd_set_request_block_size (h, request); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_SET_REQUEST_BLOCK_SIZE + missing_function (err, "set_request_block_size"); + return -1; +#endif +} + +int +_nbd_get_request_block_size_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_GET_REQUEST_BLOCK_SIZE + int ret; + + ret = nbd_get_request_block_size (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_GET_REQUEST_BLOCK_SIZE + missing_function (err, "get_request_block_size"); + return -1; +#endif +} + +int +_nbd_set_full_info_wrapper (struct error *err, + struct nbd_handle *h, bool request) +{ +#ifdef LIBNBD_HAVE_NBD_SET_FULL_INFO + int ret; + + ret = nbd_set_full_info (h, request); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_SET_FULL_INFO + missing_function (err, "set_full_info"); + return -1; +#endif +} + +int +_nbd_get_full_info_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_GET_FULL_INFO + int ret; + + ret = nbd_get_full_info (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_GET_FULL_INFO + missing_function (err, "get_full_info"); + return -1; +#endif +} + +char * +_nbd_get_canonical_export_name_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_GET_CANONICAL_EXPORT_NAME + char * ret; + + ret = nbd_get_canonical_export_name (h); + if (ret == NULL) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_GET_CANONICAL_EXPORT_NAME + missing_function (err, "get_canonical_export_name"); + return NULL; +#endif +} + +char * +_nbd_get_export_description_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_GET_EXPORT_DESCRIPTION + char * ret; + + ret = nbd_get_export_description (h); + if (ret == NULL) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_GET_EXPORT_DESCRIPTION + missing_function (err, "get_export_description"); + return NULL; +#endif +} + +int +_nbd_set_tls_wrapper (struct error *err, + struct nbd_handle *h, int tls) +{ +#ifdef LIBNBD_HAVE_NBD_SET_TLS + int ret; + + ret = nbd_set_tls (h, tls); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_SET_TLS + missing_function (err, "set_tls"); + return -1; +#endif +} + +int +_nbd_get_tls_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_GET_TLS + int ret; + + ret = nbd_get_tls (h); + return ret; +#else // !LIBNBD_HAVE_NBD_GET_TLS + missing_function (err, "get_tls"); +#endif +} + +int +_nbd_get_tls_negotiated_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_GET_TLS_NEGOTIATED + int ret; + + ret = nbd_get_tls_negotiated (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_GET_TLS_NEGOTIATED + missing_function (err, "get_tls_negotiated"); + return -1; +#endif +} + +int +_nbd_set_tls_certificates_wrapper (struct error *err, + struct nbd_handle *h, const char *dir) +{ +#ifdef LIBNBD_HAVE_NBD_SET_TLS_CERTIFICATES + int ret; + + ret = nbd_set_tls_certificates (h, dir); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_SET_TLS_CERTIFICATES + missing_function (err, "set_tls_certificates"); + return -1; +#endif +} + +int +_nbd_set_tls_verify_peer_wrapper (struct error *err, + struct nbd_handle *h, bool verify) +{ +#ifdef LIBNBD_HAVE_NBD_SET_TLS_VERIFY_PEER + int ret; + + ret = nbd_set_tls_verify_peer (h, verify); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_SET_TLS_VERIFY_PEER + missing_function (err, "set_tls_verify_peer"); + return -1; +#endif +} + +int +_nbd_get_tls_verify_peer_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_GET_TLS_VERIFY_PEER + int ret; + + ret = nbd_get_tls_verify_peer (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_GET_TLS_VERIFY_PEER + missing_function (err, "get_tls_verify_peer"); + return -1; +#endif +} + +int +_nbd_set_tls_username_wrapper (struct error *err, + struct nbd_handle *h, const char *username) +{ +#ifdef LIBNBD_HAVE_NBD_SET_TLS_USERNAME + int ret; + + ret = nbd_set_tls_username (h, username); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_SET_TLS_USERNAME + missing_function (err, "set_tls_username"); + return -1; +#endif +} + +char * +_nbd_get_tls_username_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_GET_TLS_USERNAME + char * ret; + + ret = nbd_get_tls_username (h); + if (ret == NULL) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_GET_TLS_USERNAME + missing_function (err, "get_tls_username"); + return NULL; +#endif +} + +int +_nbd_set_tls_psk_file_wrapper (struct error *err, + struct nbd_handle *h, const char *filename) +{ +#ifdef LIBNBD_HAVE_NBD_SET_TLS_PSK_FILE + int ret; + + ret = nbd_set_tls_psk_file (h, filename); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_SET_TLS_PSK_FILE + missing_function (err, "set_tls_psk_file"); + return -1; +#endif +} + +int +_nbd_set_request_structured_replies_wrapper (struct error *err, + struct nbd_handle *h, bool request) +{ +#ifdef LIBNBD_HAVE_NBD_SET_REQUEST_STRUCTURED_REPLIES + int ret; + + ret = nbd_set_request_structured_replies (h, request); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_SET_REQUEST_STRUCTURED_REPLIES + missing_function (err, "set_request_structured_replies"); + return -1; +#endif +} + +int +_nbd_get_request_structured_replies_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_GET_REQUEST_STRUCTURED_REPLIES + int ret; + + ret = nbd_get_request_structured_replies (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_GET_REQUEST_STRUCTURED_REPLIES + missing_function (err, "get_request_structured_replies"); + return -1; +#endif +} + +int +_nbd_get_structured_replies_negotiated_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_GET_STRUCTURED_REPLIES_NEGOTIATED + int ret; + + ret = nbd_get_structured_replies_negotiated (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_GET_STRUCTURED_REPLIES_NEGOTIATED + missing_function (err, "get_structured_replies_negotiated"); + return -1; +#endif +} + +int +_nbd_set_handshake_flags_wrapper (struct error *err, + struct nbd_handle *h, uint32_t flags) +{ +#ifdef LIBNBD_HAVE_NBD_SET_HANDSHAKE_FLAGS + int ret; + + ret = nbd_set_handshake_flags (h, flags); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_SET_HANDSHAKE_FLAGS + missing_function (err, "set_handshake_flags"); + return -1; +#endif +} + +uint32_t +_nbd_get_handshake_flags_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_GET_HANDSHAKE_FLAGS + uint32_t ret; + + ret = nbd_get_handshake_flags (h); + return ret; +#else // !LIBNBD_HAVE_NBD_GET_HANDSHAKE_FLAGS + missing_function (err, "get_handshake_flags"); +#endif +} + +int +_nbd_set_pread_initialize_wrapper (struct error *err, + struct nbd_handle *h, bool request) +{ +#ifdef LIBNBD_HAVE_NBD_SET_PREAD_INITIALIZE + int ret; + + ret = nbd_set_pread_initialize (h, request); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_SET_PREAD_INITIALIZE + missing_function (err, "set_pread_initialize"); + return -1; +#endif +} + +int +_nbd_get_pread_initialize_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_GET_PREAD_INITIALIZE + int ret; + + ret = nbd_get_pread_initialize (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_GET_PREAD_INITIALIZE + missing_function (err, "get_pread_initialize"); + return -1; +#endif +} + +int +_nbd_set_strict_mode_wrapper (struct error *err, + struct nbd_handle *h, uint32_t flags) +{ +#ifdef LIBNBD_HAVE_NBD_SET_STRICT_MODE + int ret; + + ret = nbd_set_strict_mode (h, flags); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_SET_STRICT_MODE + missing_function (err, "set_strict_mode"); + return -1; +#endif +} + +uint32_t +_nbd_get_strict_mode_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_GET_STRICT_MODE + uint32_t ret; + + ret = nbd_get_strict_mode (h); + return ret; +#else // !LIBNBD_HAVE_NBD_GET_STRICT_MODE + missing_function (err, "get_strict_mode"); +#endif +} + +int +_nbd_set_opt_mode_wrapper (struct error *err, + struct nbd_handle *h, bool enable) +{ +#ifdef LIBNBD_HAVE_NBD_SET_OPT_MODE + int ret; + + ret = nbd_set_opt_mode (h, enable); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_SET_OPT_MODE + missing_function (err, "set_opt_mode"); + return -1; +#endif +} + +int +_nbd_get_opt_mode_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_GET_OPT_MODE + int ret; + + ret = nbd_get_opt_mode (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_GET_OPT_MODE + missing_function (err, "get_opt_mode"); + return -1; +#endif +} + +int +_nbd_opt_go_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_OPT_GO + int ret; + + ret = nbd_opt_go (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_OPT_GO + missing_function (err, "opt_go"); + return -1; +#endif +} + +int +_nbd_opt_abort_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_OPT_ABORT + int ret; + + ret = nbd_opt_abort (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_OPT_ABORT + missing_function (err, "opt_abort"); + return -1; +#endif +} + +int +_nbd_opt_list_wrapper (struct error *err, + struct nbd_handle *h, nbd_list_callback list_callback) +{ +#ifdef LIBNBD_HAVE_NBD_OPT_LIST + int ret; + + ret = nbd_opt_list (h, list_callback); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_OPT_LIST + missing_function (err, "opt_list"); + return -1; +#endif +} + +int +_nbd_opt_info_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_OPT_INFO + int ret; + + ret = nbd_opt_info (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_OPT_INFO + missing_function (err, "opt_info"); + return -1; +#endif +} + +int +_nbd_opt_list_meta_context_wrapper (struct error *err, + struct nbd_handle *h, nbd_context_callback context_callback) +{ +#ifdef LIBNBD_HAVE_NBD_OPT_LIST_META_CONTEXT + int ret; + + ret = nbd_opt_list_meta_context (h, context_callback); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_OPT_LIST_META_CONTEXT + missing_function (err, "opt_list_meta_context"); + return -1; +#endif +} + +int +_nbd_add_meta_context_wrapper (struct error *err, + struct nbd_handle *h, const char *name) +{ +#ifdef LIBNBD_HAVE_NBD_ADD_META_CONTEXT + int ret; + + ret = nbd_add_meta_context (h, name); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_ADD_META_CONTEXT + missing_function (err, "add_meta_context"); + return -1; +#endif +} + +ssize_t +_nbd_get_nr_meta_contexts_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_GET_NR_META_CONTEXTS + ssize_t ret; + + ret = nbd_get_nr_meta_contexts (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_GET_NR_META_CONTEXTS + missing_function (err, "get_nr_meta_contexts"); + return -1; +#endif +} + +char * +_nbd_get_meta_context_wrapper (struct error *err, + struct nbd_handle *h, size_t i) +{ +#ifdef LIBNBD_HAVE_NBD_GET_META_CONTEXT + char * ret; + + ret = nbd_get_meta_context (h, i); + if (ret == NULL) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_GET_META_CONTEXT + missing_function (err, "get_meta_context"); + return NULL; +#endif +} + +int +_nbd_clear_meta_contexts_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_CLEAR_META_CONTEXTS + int ret; + + ret = nbd_clear_meta_contexts (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_CLEAR_META_CONTEXTS + missing_function (err, "clear_meta_contexts"); + return -1; +#endif +} + +int +_nbd_set_uri_allow_transports_wrapper (struct error *err, + struct nbd_handle *h, uint32_t mask) +{ +#ifdef LIBNBD_HAVE_NBD_SET_URI_ALLOW_TRANSPORTS + int ret; + + ret = nbd_set_uri_allow_transports (h, mask); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_SET_URI_ALLOW_TRANSPORTS + missing_function (err, "set_uri_allow_transports"); + return -1; +#endif +} + +int +_nbd_set_uri_allow_tls_wrapper (struct error *err, + struct nbd_handle *h, int tls) +{ +#ifdef LIBNBD_HAVE_NBD_SET_URI_ALLOW_TLS + int ret; + + ret = nbd_set_uri_allow_tls (h, tls); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_SET_URI_ALLOW_TLS + missing_function (err, "set_uri_allow_tls"); + return -1; +#endif +} + +int +_nbd_set_uri_allow_local_file_wrapper (struct error *err, + struct nbd_handle *h, bool allow) +{ +#ifdef LIBNBD_HAVE_NBD_SET_URI_ALLOW_LOCAL_FILE + int ret; + + ret = nbd_set_uri_allow_local_file (h, allow); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_SET_URI_ALLOW_LOCAL_FILE + missing_function (err, "set_uri_allow_local_file"); + return -1; +#endif +} + +int +_nbd_connect_uri_wrapper (struct error *err, + struct nbd_handle *h, const char *uri) +{ +#ifdef LIBNBD_HAVE_NBD_CONNECT_URI + int ret; + + ret = nbd_connect_uri (h, uri); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_CONNECT_URI + missing_function (err, "connect_uri"); + return -1; +#endif +} + +int +_nbd_connect_unix_wrapper (struct error *err, + struct nbd_handle *h, const char *unixsocket) +{ +#ifdef LIBNBD_HAVE_NBD_CONNECT_UNIX + int ret; + + ret = nbd_connect_unix (h, unixsocket); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_CONNECT_UNIX + missing_function (err, "connect_unix"); + return -1; +#endif +} + +int +_nbd_connect_vsock_wrapper (struct error *err, + struct nbd_handle *h, uint32_t cid, uint32_t port) +{ +#ifdef LIBNBD_HAVE_NBD_CONNECT_VSOCK + int ret; + + ret = nbd_connect_vsock (h, cid, port); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_CONNECT_VSOCK + missing_function (err, "connect_vsock"); + return -1; +#endif +} + +int +_nbd_connect_tcp_wrapper (struct error *err, + struct nbd_handle *h, const char *hostname, const char *port) +{ +#ifdef LIBNBD_HAVE_NBD_CONNECT_TCP + int ret; + + ret = nbd_connect_tcp (h, hostname, port); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_CONNECT_TCP + missing_function (err, "connect_tcp"); + return -1; +#endif +} + +int +_nbd_connect_socket_wrapper (struct error *err, + struct nbd_handle *h, int sock) +{ +#ifdef LIBNBD_HAVE_NBD_CONNECT_SOCKET + int ret; + + ret = nbd_connect_socket (h, sock); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_CONNECT_SOCKET + missing_function (err, "connect_socket"); + return -1; +#endif +} + +int +_nbd_connect_command_wrapper (struct error *err, + struct nbd_handle *h, char **argv) +{ +#ifdef LIBNBD_HAVE_NBD_CONNECT_COMMAND + int ret; + + ret = nbd_connect_command (h, argv); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_CONNECT_COMMAND + missing_function (err, "connect_command"); + return -1; +#endif +} + +int +_nbd_connect_systemd_socket_activation_wrapper (struct error *err, + struct nbd_handle *h, char **argv) +{ +#ifdef LIBNBD_HAVE_NBD_CONNECT_SYSTEMD_SOCKET_ACTIVATION + int ret; + + ret = nbd_connect_systemd_socket_activation (h, argv); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_CONNECT_SYSTEMD_SOCKET_ACTIVATION + missing_function (err, "connect_systemd_socket_activation"); + return -1; +#endif +} + +int +_nbd_is_read_only_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_IS_READ_ONLY + int ret; + + ret = nbd_is_read_only (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_IS_READ_ONLY + missing_function (err, "is_read_only"); + return -1; +#endif +} + +int +_nbd_can_flush_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_CAN_FLUSH + int ret; + + ret = nbd_can_flush (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_CAN_FLUSH + missing_function (err, "can_flush"); + return -1; +#endif +} + +int +_nbd_can_fua_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_CAN_FUA + int ret; + + ret = nbd_can_fua (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_CAN_FUA + missing_function (err, "can_fua"); + return -1; +#endif +} + +int +_nbd_is_rotational_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_IS_ROTATIONAL + int ret; + + ret = nbd_is_rotational (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_IS_ROTATIONAL + missing_function (err, "is_rotational"); + return -1; +#endif +} + +int +_nbd_can_trim_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_CAN_TRIM + int ret; + + ret = nbd_can_trim (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_CAN_TRIM + missing_function (err, "can_trim"); + return -1; +#endif +} + +int +_nbd_can_zero_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_CAN_ZERO + int ret; + + ret = nbd_can_zero (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_CAN_ZERO + missing_function (err, "can_zero"); + return -1; +#endif +} + +int +_nbd_can_fast_zero_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_CAN_FAST_ZERO + int ret; + + ret = nbd_can_fast_zero (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_CAN_FAST_ZERO + missing_function (err, "can_fast_zero"); + return -1; +#endif +} + +int +_nbd_can_df_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_CAN_DF + int ret; + + ret = nbd_can_df (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_CAN_DF + missing_function (err, "can_df"); + return -1; +#endif +} + +int +_nbd_can_multi_conn_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_CAN_MULTI_CONN + int ret; + + ret = nbd_can_multi_conn (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_CAN_MULTI_CONN + missing_function (err, "can_multi_conn"); + return -1; +#endif +} + +int +_nbd_can_cache_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_CAN_CACHE + int ret; + + ret = nbd_can_cache (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_CAN_CACHE + missing_function (err, "can_cache"); + return -1; +#endif +} + +int +_nbd_can_meta_context_wrapper (struct error *err, + struct nbd_handle *h, const char *metacontext) +{ +#ifdef LIBNBD_HAVE_NBD_CAN_META_CONTEXT + int ret; + + ret = nbd_can_meta_context (h, metacontext); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_CAN_META_CONTEXT + missing_function (err, "can_meta_context"); + return -1; +#endif +} + +const char * +_nbd_get_protocol_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_GET_PROTOCOL + const char * ret; + + ret = nbd_get_protocol (h); + if (ret == NULL) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_GET_PROTOCOL + missing_function (err, "get_protocol"); + return NULL; +#endif +} + +int64_t +_nbd_get_size_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_GET_SIZE + int64_t ret; + + ret = nbd_get_size (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_GET_SIZE + missing_function (err, "get_size"); + return -1; +#endif +} + +int64_t +_nbd_get_block_size_wrapper (struct error *err, + struct nbd_handle *h, int size_type) +{ +#ifdef LIBNBD_HAVE_NBD_GET_BLOCK_SIZE + int64_t ret; + + ret = nbd_get_block_size (h, size_type); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_GET_BLOCK_SIZE + missing_function (err, "get_block_size"); + return -1; +#endif +} + +int +_nbd_pread_wrapper (struct error *err, + struct nbd_handle *h, void *buf, size_t count, uint64_t offset, + uint32_t flags) +{ +#ifdef LIBNBD_HAVE_NBD_PREAD + int ret; + + ret = nbd_pread (h, buf, count, offset, flags); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_PREAD + missing_function (err, "pread"); + return -1; +#endif +} + +int +_nbd_pread_structured_wrapper (struct error *err, + struct nbd_handle *h, void *buf, size_t count, uint64_t offset, + nbd_chunk_callback chunk_callback, uint32_t flags) +{ +#ifdef LIBNBD_HAVE_NBD_PREAD_STRUCTURED + int ret; + + ret = nbd_pread_structured (h, buf, count, offset, chunk_callback, flags); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_PREAD_STRUCTURED + missing_function (err, "pread_structured"); + return -1; +#endif +} + +int +_nbd_pwrite_wrapper (struct error *err, + struct nbd_handle *h, const void *buf, size_t count, + uint64_t offset, uint32_t flags) +{ +#ifdef LIBNBD_HAVE_NBD_PWRITE + int ret; + + ret = nbd_pwrite (h, buf, count, offset, flags); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_PWRITE + missing_function (err, "pwrite"); + return -1; +#endif +} + +int +_nbd_shutdown_wrapper (struct error *err, + struct nbd_handle *h, uint32_t flags) +{ +#ifdef LIBNBD_HAVE_NBD_SHUTDOWN + int ret; + + ret = nbd_shutdown (h, flags); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_SHUTDOWN + missing_function (err, "shutdown"); + return -1; +#endif +} + +int +_nbd_flush_wrapper (struct error *err, + struct nbd_handle *h, uint32_t flags) +{ +#ifdef LIBNBD_HAVE_NBD_FLUSH + int ret; + + ret = nbd_flush (h, flags); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_FLUSH + missing_function (err, "flush"); + return -1; +#endif +} + +int +_nbd_trim_wrapper (struct error *err, + struct nbd_handle *h, uint64_t count, uint64_t offset, + uint32_t flags) +{ +#ifdef LIBNBD_HAVE_NBD_TRIM + int ret; + + ret = nbd_trim (h, count, offset, flags); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_TRIM + missing_function (err, "trim"); + return -1; +#endif +} + +int +_nbd_cache_wrapper (struct error *err, + struct nbd_handle *h, uint64_t count, uint64_t offset, + uint32_t flags) +{ +#ifdef LIBNBD_HAVE_NBD_CACHE + int ret; + + ret = nbd_cache (h, count, offset, flags); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_CACHE + missing_function (err, "cache"); + return -1; +#endif +} + +int +_nbd_zero_wrapper (struct error *err, + struct nbd_handle *h, uint64_t count, uint64_t offset, + uint32_t flags) +{ +#ifdef LIBNBD_HAVE_NBD_ZERO + int ret; + + ret = nbd_zero (h, count, offset, flags); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_ZERO + missing_function (err, "zero"); + return -1; +#endif +} + +int +_nbd_block_status_wrapper (struct error *err, + struct nbd_handle *h, uint64_t count, uint64_t offset, + nbd_extent_callback extent_callback, uint32_t flags) +{ +#ifdef LIBNBD_HAVE_NBD_BLOCK_STATUS + int ret; + + ret = nbd_block_status (h, count, offset, extent_callback, flags); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_BLOCK_STATUS + missing_function (err, "block_status"); + return -1; +#endif +} + +int +_nbd_poll_wrapper (struct error *err, + struct nbd_handle *h, int timeout) +{ +#ifdef LIBNBD_HAVE_NBD_POLL + int ret; + + ret = nbd_poll (h, timeout); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_POLL + missing_function (err, "poll"); + return -1; +#endif +} + +int +_nbd_aio_connect_wrapper (struct error *err, + struct nbd_handle *h, const struct sockaddr *addr, + socklen_t addrlen) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_CONNECT + int ret; + + ret = nbd_aio_connect (h, addr, addrlen); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_CONNECT + missing_function (err, "aio_connect"); + return -1; +#endif +} + +int +_nbd_aio_connect_uri_wrapper (struct error *err, + struct nbd_handle *h, const char *uri) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_CONNECT_URI + int ret; + + ret = nbd_aio_connect_uri (h, uri); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_CONNECT_URI + missing_function (err, "aio_connect_uri"); + return -1; +#endif +} + +int +_nbd_aio_connect_unix_wrapper (struct error *err, + struct nbd_handle *h, const char *unixsocket) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_CONNECT_UNIX + int ret; + + ret = nbd_aio_connect_unix (h, unixsocket); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_CONNECT_UNIX + missing_function (err, "aio_connect_unix"); + return -1; +#endif +} + +int +_nbd_aio_connect_vsock_wrapper (struct error *err, + struct nbd_handle *h, uint32_t cid, uint32_t port) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_CONNECT_VSOCK + int ret; + + ret = nbd_aio_connect_vsock (h, cid, port); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_CONNECT_VSOCK + missing_function (err, "aio_connect_vsock"); + return -1; +#endif +} + +int +_nbd_aio_connect_tcp_wrapper (struct error *err, + struct nbd_handle *h, const char *hostname, const char *port) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_CONNECT_TCP + int ret; + + ret = nbd_aio_connect_tcp (h, hostname, port); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_CONNECT_TCP + missing_function (err, "aio_connect_tcp"); + return -1; +#endif +} + +int +_nbd_aio_connect_socket_wrapper (struct error *err, + struct nbd_handle *h, int sock) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_CONNECT_SOCKET + int ret; + + ret = nbd_aio_connect_socket (h, sock); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_CONNECT_SOCKET + missing_function (err, "aio_connect_socket"); + return -1; +#endif +} + +int +_nbd_aio_connect_command_wrapper (struct error *err, + struct nbd_handle *h, char **argv) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_CONNECT_COMMAND + int ret; + + ret = nbd_aio_connect_command (h, argv); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_CONNECT_COMMAND + missing_function (err, "aio_connect_command"); + return -1; +#endif +} + +int +_nbd_aio_connect_systemd_socket_activation_wrapper (struct error *err, + struct nbd_handle *h, char **argv) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_CONNECT_SYSTEMD_SOCKET_ACTIVATION + int ret; + + ret = nbd_aio_connect_systemd_socket_activation (h, argv); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_CONNECT_SYSTEMD_SOCKET_ACTIVATION + missing_function (err, "aio_connect_systemd_socket_activation"); + return -1; +#endif +} + +int +_nbd_aio_opt_go_wrapper (struct error *err, + struct nbd_handle *h, nbd_completion_callback completion_callback) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_OPT_GO + int ret; + + ret = nbd_aio_opt_go (h, completion_callback); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_OPT_GO + missing_function (err, "aio_opt_go"); + return -1; +#endif +} + +int +_nbd_aio_opt_abort_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_OPT_ABORT + int ret; + + ret = nbd_aio_opt_abort (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_OPT_ABORT + missing_function (err, "aio_opt_abort"); + return -1; +#endif +} + +int +_nbd_aio_opt_list_wrapper (struct error *err, + struct nbd_handle *h, nbd_list_callback list_callback, + nbd_completion_callback completion_callback) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_OPT_LIST + int ret; + + ret = nbd_aio_opt_list (h, list_callback, completion_callback); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_OPT_LIST + missing_function (err, "aio_opt_list"); + return -1; +#endif +} + +int +_nbd_aio_opt_info_wrapper (struct error *err, + struct nbd_handle *h, nbd_completion_callback completion_callback) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_OPT_INFO + int ret; + + ret = nbd_aio_opt_info (h, completion_callback); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_OPT_INFO + missing_function (err, "aio_opt_info"); + return -1; +#endif +} + +int +_nbd_aio_opt_list_meta_context_wrapper (struct error *err, + struct nbd_handle *h, nbd_context_callback context_callback, + nbd_completion_callback completion_callback) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_OPT_LIST_META_CONTEXT + int ret; + + ret = nbd_aio_opt_list_meta_context (h, context_callback, + completion_callback); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_OPT_LIST_META_CONTEXT + missing_function (err, "aio_opt_list_meta_context"); + return -1; +#endif +} + +int64_t +_nbd_aio_pread_wrapper (struct error *err, + struct nbd_handle *h, void *buf, size_t count, uint64_t offset, + nbd_completion_callback completion_callback, uint32_t flags) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_PREAD + int64_t ret; + + ret = nbd_aio_pread (h, buf, count, offset, completion_callback, flags); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_PREAD + missing_function (err, "aio_pread"); + return -1; +#endif +} + +int64_t +_nbd_aio_pread_structured_wrapper (struct error *err, + struct nbd_handle *h, void *buf, size_t count, uint64_t offset, + nbd_chunk_callback chunk_callback, + nbd_completion_callback completion_callback, uint32_t flags) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_PREAD_STRUCTURED + int64_t ret; + + ret = nbd_aio_pread_structured (h, buf, count, offset, chunk_callback, + completion_callback, flags); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_PREAD_STRUCTURED + missing_function (err, "aio_pread_structured"); + return -1; +#endif +} + +int64_t +_nbd_aio_pwrite_wrapper (struct error *err, + struct nbd_handle *h, const void *buf, size_t count, + uint64_t offset, nbd_completion_callback completion_callback, + uint32_t flags) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_PWRITE + int64_t ret; + + ret = nbd_aio_pwrite (h, buf, count, offset, completion_callback, flags); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_PWRITE + missing_function (err, "aio_pwrite"); + return -1; +#endif +} + +int +_nbd_aio_disconnect_wrapper (struct error *err, + struct nbd_handle *h, uint32_t flags) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_DISCONNECT + int ret; + + ret = nbd_aio_disconnect (h, flags); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_DISCONNECT + missing_function (err, "aio_disconnect"); + return -1; +#endif +} + +int64_t +_nbd_aio_flush_wrapper (struct error *err, + struct nbd_handle *h, nbd_completion_callback completion_callback, + uint32_t flags) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_FLUSH + int64_t ret; + + ret = nbd_aio_flush (h, completion_callback, flags); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_FLUSH + missing_function (err, "aio_flush"); + return -1; +#endif +} + +int64_t +_nbd_aio_trim_wrapper (struct error *err, + struct nbd_handle *h, uint64_t count, uint64_t offset, + nbd_completion_callback completion_callback, uint32_t flags) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_TRIM + int64_t ret; + + ret = nbd_aio_trim (h, count, offset, completion_callback, flags); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_TRIM + missing_function (err, "aio_trim"); + return -1; +#endif +} + +int64_t +_nbd_aio_cache_wrapper (struct error *err, + struct nbd_handle *h, uint64_t count, uint64_t offset, + nbd_completion_callback completion_callback, uint32_t flags) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_CACHE + int64_t ret; + + ret = nbd_aio_cache (h, count, offset, completion_callback, flags); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_CACHE + missing_function (err, "aio_cache"); + return -1; +#endif +} + +int64_t +_nbd_aio_zero_wrapper (struct error *err, + struct nbd_handle *h, uint64_t count, uint64_t offset, + nbd_completion_callback completion_callback, uint32_t flags) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_ZERO + int64_t ret; + + ret = nbd_aio_zero (h, count, offset, completion_callback, flags); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_ZERO + missing_function (err, "aio_zero"); + return -1; +#endif +} + +int64_t +_nbd_aio_block_status_wrapper (struct error *err, + struct nbd_handle *h, uint64_t count, uint64_t offset, + nbd_extent_callback extent_callback, + nbd_completion_callback completion_callback, uint32_t flags) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_BLOCK_STATUS + int64_t ret; + + ret = nbd_aio_block_status (h, count, offset, extent_callback, + completion_callback, flags); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_BLOCK_STATUS + missing_function (err, "aio_block_status"); + return -1; +#endif +} + +int +_nbd_aio_get_fd_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_GET_FD + int ret; + + ret = nbd_aio_get_fd (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_GET_FD + missing_function (err, "aio_get_fd"); + return -1; +#endif +} + +unsigned +_nbd_aio_get_direction_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_GET_DIRECTION + unsigned ret; + + ret = nbd_aio_get_direction (h); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_GET_DIRECTION + missing_function (err, "aio_get_direction"); +#endif +} + +int +_nbd_aio_notify_read_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_NOTIFY_READ + int ret; + + ret = nbd_aio_notify_read (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_NOTIFY_READ + missing_function (err, "aio_notify_read"); + return -1; +#endif +} + +int +_nbd_aio_notify_write_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_NOTIFY_WRITE + int ret; + + ret = nbd_aio_notify_write (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_NOTIFY_WRITE + missing_function (err, "aio_notify_write"); + return -1; +#endif +} + +int +_nbd_aio_is_created_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_IS_CREATED + int ret; + + ret = nbd_aio_is_created (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_IS_CREATED + missing_function (err, "aio_is_created"); + return -1; +#endif +} + +int +_nbd_aio_is_connecting_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_IS_CONNECTING + int ret; + + ret = nbd_aio_is_connecting (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_IS_CONNECTING + missing_function (err, "aio_is_connecting"); + return -1; +#endif +} + +int +_nbd_aio_is_negotiating_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_IS_NEGOTIATING + int ret; + + ret = nbd_aio_is_negotiating (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_IS_NEGOTIATING + missing_function (err, "aio_is_negotiating"); + return -1; +#endif +} + +int +_nbd_aio_is_ready_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_IS_READY + int ret; + + ret = nbd_aio_is_ready (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_IS_READY + missing_function (err, "aio_is_ready"); + return -1; +#endif +} + +int +_nbd_aio_is_processing_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_IS_PROCESSING + int ret; + + ret = nbd_aio_is_processing (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_IS_PROCESSING + missing_function (err, "aio_is_processing"); + return -1; +#endif +} + +int +_nbd_aio_is_dead_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_IS_DEAD + int ret; + + ret = nbd_aio_is_dead (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_IS_DEAD + missing_function (err, "aio_is_dead"); + return -1; +#endif +} + +int +_nbd_aio_is_closed_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_IS_CLOSED + int ret; + + ret = nbd_aio_is_closed (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_IS_CLOSED + missing_function (err, "aio_is_closed"); + return -1; +#endif +} + +int +_nbd_aio_command_completed_wrapper (struct error *err, + struct nbd_handle *h, uint64_t cookie) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_COMMAND_COMPLETED + int ret; + + ret = nbd_aio_command_completed (h, cookie); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_COMMAND_COMPLETED + missing_function (err, "aio_command_completed"); + return -1; +#endif +} + +int64_t +_nbd_aio_peek_command_completed_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_PEEK_COMMAND_COMPLETED + int64_t ret; + + ret = nbd_aio_peek_command_completed (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_PEEK_COMMAND_COMPLETED + missing_function (err, "aio_peek_command_completed"); + return -1; +#endif +} + +int +_nbd_aio_in_flight_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_AIO_IN_FLIGHT + int ret; + + ret = nbd_aio_in_flight (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_AIO_IN_FLIGHT + missing_function (err, "aio_in_flight"); + return -1; +#endif +} + +const char * +_nbd_connection_state_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_CONNECTION_STATE + const char * ret; + + ret = nbd_connection_state (h); + if (ret == NULL) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_CONNECTION_STATE + missing_function (err, "connection_state"); + return NULL; +#endif +} + +const char * +_nbd_get_package_name_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_GET_PACKAGE_NAME + const char * ret; + + ret = nbd_get_package_name (h); + if (ret == NULL) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_GET_PACKAGE_NAME + missing_function (err, "get_package_name"); + return NULL; +#endif +} + +const char * +_nbd_get_version_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_GET_VERSION + const char * ret; + + ret = nbd_get_version (h); + if (ret == NULL) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_GET_VERSION + missing_function (err, "get_version"); + return NULL; +#endif +} + +int +_nbd_kill_subprocess_wrapper (struct error *err, + struct nbd_handle *h, int signum) +{ +#ifdef LIBNBD_HAVE_NBD_KILL_SUBPROCESS + int ret; + + ret = nbd_kill_subprocess (h, signum); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_KILL_SUBPROCESS + missing_function (err, "kill_subprocess"); + return -1; +#endif +} + +int +_nbd_supports_tls_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_SUPPORTS_TLS + int ret; + + ret = nbd_supports_tls (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_SUPPORTS_TLS + missing_function (err, "supports_tls"); + return -1; +#endif +} + +int +_nbd_supports_uri_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_SUPPORTS_URI + int ret; + + ret = nbd_supports_uri (h); + if (ret == -1) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_SUPPORTS_URI + missing_function (err, "supports_uri"); + return -1; +#endif +} + +char * +_nbd_get_uri_wrapper (struct error *err, + struct nbd_handle *h) +{ +#ifdef LIBNBD_HAVE_NBD_GET_URI + char * ret; + + ret = nbd_get_uri (h); + if (ret == NULL) + save_error (err); + return ret; +#else // !LIBNBD_HAVE_NBD_GET_URI + missing_function (err, "get_uri"); + return NULL; +#endif +} + +int +_nbd_chunk_callback_wrapper (void *user_data, const void *subbuf, + size_t count, uint64_t offset, unsigned status, + int *error) +{ + return chunk_callback ((long)user_data, subbuf, count, offset, status, error); +} + +void +_nbd_chunk_callback_free (void *user_data) +{ + long *p = user_data; + extern void freeCallbackId (long); + freeCallbackId (*p); + free (p); +} + +int +_nbd_completion_callback_wrapper (void *user_data, int *error) +{ + return completion_callback ((long)user_data, error); +} + +void +_nbd_completion_callback_free (void *user_data) +{ + long *p = user_data; + extern void freeCallbackId (long); + freeCallbackId (*p); + free (p); +} + +int +_nbd_debug_callback_wrapper (void *user_data, const char *context, + const char *msg) +{ + return debug_callback ((long)user_data, context, msg); +} + +void +_nbd_debug_callback_free (void *user_data) +{ + long *p = user_data; + extern void freeCallbackId (long); + freeCallbackId (*p); + free (p); +} + +int +_nbd_extent_callback_wrapper (void *user_data, const char *metacontext, + uint64_t offset, uint32_t *entries, + size_t nr_entries, int *error) +{ + return extent_callback ((long)user_data, metacontext, offset, entries, nr_entries, error); +} + +void +_nbd_extent_callback_free (void *user_data) +{ + long *p = user_data; + extern void freeCallbackId (long); + freeCallbackId (*p); + free (p); +} + +int +_nbd_list_callback_wrapper (void *user_data, const char *name, + const char *description) +{ + return list_callback ((long)user_data, name, description); +} + +void +_nbd_list_callback_free (void *user_data) +{ + long *p = user_data; + extern void freeCallbackId (long); + freeCallbackId (*p); + free (p); +} + +int +_nbd_context_callback_wrapper (void *user_data, const char *name) +{ + return context_callback ((long)user_data, name); +} + +void +_nbd_context_callback_free (void *user_data) +{ + long *p = user_data; + extern void freeCallbackId (long); + freeCallbackId (*p); + free (p); +} + +// There must be no blank line between end comment and import! +// https://github.com/golang/go/issues/9733 +*/ +import "C" diff --git a/vendor/libguestfs.org/libnbd/wrappers.h b/vendor/libguestfs.org/libnbd/wrappers.h new file mode 100644 index 000000000..32441489e --- /dev/null +++ b/vendor/libguestfs.org/libnbd/wrappers.h @@ -0,0 +1,382 @@ +/* NBD client library in userspace + * WARNING: THIS FILE IS GENERATED FROM + * generator/generator + * ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST. + * + * Copyright (C) 2013-2021 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef LIBNBD_GOLANG_WRAPPERS_H +#define LIBNBD_GOLANG_WRAPPERS_H + +#include +#include +#include +#include + +#include "libnbd.h" + +/* When calling callbacks we pass the callback ID (a golang int / + * C.long) in the void *user_data field. We need to create a block + * to store the callback number. This must be freed by C.free(vp) + */ +static inline void * +alloc_cbid (long i) +{ + long *p = malloc (sizeof (long)); + assert (p != NULL); + *p = i; + return p; +} + +/* save_error is called from the same thread to make a copy + * of the error which can later be retrieve from golang code + * possibly running in a different thread. + */ +struct error { + char *error; + int errnum; +}; + +static inline void +save_error (struct error *err) +{ + err->error = strdup (nbd_get_error ()); + err->errnum = nbd_get_errno (); +} + +static inline void +free_error (struct error *err) +{ + free (err->error); +} + +/* If you mix old C library and new bindings then some C + * functions may not be defined. They return ENOTSUP. + */ +static inline void +missing_function (struct error *err, const char *fn) +{ + asprintf (&err->error, "%s: " + "function missing because golang bindings were compiled " + "against an old version of the C library", fn); + err->errnum = ENOTSUP; +} + +int _nbd_set_debug_wrapper (struct error *err, + struct nbd_handle *h, bool debug); +int _nbd_get_debug_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_set_debug_callback_wrapper (struct error *err, + struct nbd_handle *h, nbd_debug_callback debug_callback); +int _nbd_clear_debug_callback_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_set_handle_name_wrapper (struct error *err, + struct nbd_handle *h, const char *handle_name); +char * _nbd_get_handle_name_wrapper (struct error *err, + struct nbd_handle *h); +uintptr_t _nbd_set_private_data_wrapper (struct error *err, + struct nbd_handle *h, uintptr_t private_data); +uintptr_t _nbd_get_private_data_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_set_export_name_wrapper (struct error *err, + struct nbd_handle *h, const char *export_name); +char * _nbd_get_export_name_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_set_request_block_size_wrapper (struct error *err, + struct nbd_handle *h, bool request); +int _nbd_get_request_block_size_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_set_full_info_wrapper (struct error *err, + struct nbd_handle *h, bool request); +int _nbd_get_full_info_wrapper (struct error *err, + struct nbd_handle *h); +char * _nbd_get_canonical_export_name_wrapper (struct error *err, + struct nbd_handle *h); +char * _nbd_get_export_description_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_set_tls_wrapper (struct error *err, + struct nbd_handle *h, int tls); +int _nbd_get_tls_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_get_tls_negotiated_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_set_tls_certificates_wrapper (struct error *err, + struct nbd_handle *h, const char *dir); +int _nbd_set_tls_verify_peer_wrapper (struct error *err, + struct nbd_handle *h, bool verify); +int _nbd_get_tls_verify_peer_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_set_tls_username_wrapper (struct error *err, + struct nbd_handle *h, const char *username); +char * _nbd_get_tls_username_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_set_tls_psk_file_wrapper (struct error *err, + struct nbd_handle *h, const char *filename); +int _nbd_set_request_structured_replies_wrapper (struct error *err, + struct nbd_handle *h, bool request); +int _nbd_get_request_structured_replies_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_get_structured_replies_negotiated_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_set_handshake_flags_wrapper (struct error *err, + struct nbd_handle *h, uint32_t flags); +uint32_t _nbd_get_handshake_flags_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_set_pread_initialize_wrapper (struct error *err, + struct nbd_handle *h, bool request); +int _nbd_get_pread_initialize_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_set_strict_mode_wrapper (struct error *err, + struct nbd_handle *h, uint32_t flags); +uint32_t _nbd_get_strict_mode_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_set_opt_mode_wrapper (struct error *err, + struct nbd_handle *h, bool enable); +int _nbd_get_opt_mode_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_opt_go_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_opt_abort_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_opt_list_wrapper (struct error *err, + struct nbd_handle *h, nbd_list_callback list_callback); +int _nbd_opt_info_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_opt_list_meta_context_wrapper (struct error *err, + struct nbd_handle *h, nbd_context_callback context_callback); +int _nbd_add_meta_context_wrapper (struct error *err, + struct nbd_handle *h, const char *name); +ssize_t _nbd_get_nr_meta_contexts_wrapper (struct error *err, + struct nbd_handle *h); +char * _nbd_get_meta_context_wrapper (struct error *err, + struct nbd_handle *h, size_t i); +int _nbd_clear_meta_contexts_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_set_uri_allow_transports_wrapper (struct error *err, + struct nbd_handle *h, uint32_t mask); +int _nbd_set_uri_allow_tls_wrapper (struct error *err, + struct nbd_handle *h, int tls); +int _nbd_set_uri_allow_local_file_wrapper (struct error *err, + struct nbd_handle *h, bool allow); +int _nbd_connect_uri_wrapper (struct error *err, + struct nbd_handle *h, const char *uri); +int _nbd_connect_unix_wrapper (struct error *err, + struct nbd_handle *h, const char *unixsocket); +int _nbd_connect_vsock_wrapper (struct error *err, + struct nbd_handle *h, uint32_t cid, uint32_t port); +int _nbd_connect_tcp_wrapper (struct error *err, + struct nbd_handle *h, const char *hostname, const char *port); +int _nbd_connect_socket_wrapper (struct error *err, + struct nbd_handle *h, int sock); +int _nbd_connect_command_wrapper (struct error *err, + struct nbd_handle *h, char **argv); +int _nbd_connect_systemd_socket_activation_wrapper (struct error *err, + struct nbd_handle *h, char **argv); +int _nbd_is_read_only_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_can_flush_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_can_fua_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_is_rotational_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_can_trim_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_can_zero_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_can_fast_zero_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_can_df_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_can_multi_conn_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_can_cache_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_can_meta_context_wrapper (struct error *err, + struct nbd_handle *h, const char *metacontext); +const char * _nbd_get_protocol_wrapper (struct error *err, + struct nbd_handle *h); +int64_t _nbd_get_size_wrapper (struct error *err, + struct nbd_handle *h); +int64_t _nbd_get_block_size_wrapper (struct error *err, + struct nbd_handle *h, int size_type); +int _nbd_pread_wrapper (struct error *err, + struct nbd_handle *h, void *buf, size_t count, uint64_t offset, + uint32_t flags); +int _nbd_pread_structured_wrapper (struct error *err, + struct nbd_handle *h, void *buf, size_t count, uint64_t offset, + nbd_chunk_callback chunk_callback, uint32_t flags); +int _nbd_pwrite_wrapper (struct error *err, + struct nbd_handle *h, const void *buf, size_t count, + uint64_t offset, uint32_t flags); +int _nbd_shutdown_wrapper (struct error *err, + struct nbd_handle *h, uint32_t flags); +int _nbd_flush_wrapper (struct error *err, + struct nbd_handle *h, uint32_t flags); +int _nbd_trim_wrapper (struct error *err, + struct nbd_handle *h, uint64_t count, uint64_t offset, + uint32_t flags); +int _nbd_cache_wrapper (struct error *err, + struct nbd_handle *h, uint64_t count, uint64_t offset, + uint32_t flags); +int _nbd_zero_wrapper (struct error *err, + struct nbd_handle *h, uint64_t count, uint64_t offset, + uint32_t flags); +int _nbd_block_status_wrapper (struct error *err, + struct nbd_handle *h, uint64_t count, uint64_t offset, + nbd_extent_callback extent_callback, uint32_t flags); +int _nbd_poll_wrapper (struct error *err, + struct nbd_handle *h, int timeout); +int _nbd_aio_connect_wrapper (struct error *err, + struct nbd_handle *h, const struct sockaddr *addr, + socklen_t addrlen); +int _nbd_aio_connect_uri_wrapper (struct error *err, + struct nbd_handle *h, const char *uri); +int _nbd_aio_connect_unix_wrapper (struct error *err, + struct nbd_handle *h, const char *unixsocket); +int _nbd_aio_connect_vsock_wrapper (struct error *err, + struct nbd_handle *h, uint32_t cid, uint32_t port); +int _nbd_aio_connect_tcp_wrapper (struct error *err, + struct nbd_handle *h, const char *hostname, const char *port); +int _nbd_aio_connect_socket_wrapper (struct error *err, + struct nbd_handle *h, int sock); +int _nbd_aio_connect_command_wrapper (struct error *err, + struct nbd_handle *h, char **argv); +int _nbd_aio_connect_systemd_socket_activation_wrapper (struct error *err, + struct nbd_handle *h, char **argv); +int _nbd_aio_opt_go_wrapper (struct error *err, + struct nbd_handle *h, nbd_completion_callback completion_callback); +int _nbd_aio_opt_abort_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_aio_opt_list_wrapper (struct error *err, + struct nbd_handle *h, nbd_list_callback list_callback, + nbd_completion_callback completion_callback); +int _nbd_aio_opt_info_wrapper (struct error *err, + struct nbd_handle *h, nbd_completion_callback completion_callback); +int _nbd_aio_opt_list_meta_context_wrapper (struct error *err, + struct nbd_handle *h, nbd_context_callback context_callback, + nbd_completion_callback completion_callback); +int64_t _nbd_aio_pread_wrapper (struct error *err, + struct nbd_handle *h, void *buf, size_t count, uint64_t offset, + nbd_completion_callback completion_callback, uint32_t flags); +int64_t _nbd_aio_pread_structured_wrapper (struct error *err, + struct nbd_handle *h, void *buf, size_t count, uint64_t offset, + nbd_chunk_callback chunk_callback, + nbd_completion_callback completion_callback, uint32_t flags); +int64_t _nbd_aio_pwrite_wrapper (struct error *err, + struct nbd_handle *h, const void *buf, size_t count, + uint64_t offset, nbd_completion_callback completion_callback, + uint32_t flags); +int _nbd_aio_disconnect_wrapper (struct error *err, + struct nbd_handle *h, uint32_t flags); +int64_t _nbd_aio_flush_wrapper (struct error *err, + struct nbd_handle *h, nbd_completion_callback completion_callback, + uint32_t flags); +int64_t _nbd_aio_trim_wrapper (struct error *err, + struct nbd_handle *h, uint64_t count, uint64_t offset, + nbd_completion_callback completion_callback, uint32_t flags); +int64_t _nbd_aio_cache_wrapper (struct error *err, + struct nbd_handle *h, uint64_t count, uint64_t offset, + nbd_completion_callback completion_callback, uint32_t flags); +int64_t _nbd_aio_zero_wrapper (struct error *err, + struct nbd_handle *h, uint64_t count, uint64_t offset, + nbd_completion_callback completion_callback, uint32_t flags); +int64_t _nbd_aio_block_status_wrapper (struct error *err, + struct nbd_handle *h, uint64_t count, uint64_t offset, + nbd_extent_callback extent_callback, + nbd_completion_callback completion_callback, uint32_t flags); +int _nbd_aio_get_fd_wrapper (struct error *err, + struct nbd_handle *h); +unsigned _nbd_aio_get_direction_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_aio_notify_read_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_aio_notify_write_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_aio_is_created_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_aio_is_connecting_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_aio_is_negotiating_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_aio_is_ready_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_aio_is_processing_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_aio_is_dead_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_aio_is_closed_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_aio_command_completed_wrapper (struct error *err, + struct nbd_handle *h, uint64_t cookie); +int64_t _nbd_aio_peek_command_completed_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_aio_in_flight_wrapper (struct error *err, + struct nbd_handle *h); +const char * _nbd_connection_state_wrapper (struct error *err, + struct nbd_handle *h); +const char * _nbd_get_package_name_wrapper (struct error *err, + struct nbd_handle *h); +const char * _nbd_get_version_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_kill_subprocess_wrapper (struct error *err, + struct nbd_handle *h, int signum); +int _nbd_supports_tls_wrapper (struct error *err, + struct nbd_handle *h); +int _nbd_supports_uri_wrapper (struct error *err, + struct nbd_handle *h); +char * _nbd_get_uri_wrapper (struct error *err, + struct nbd_handle *h); + +extern int chunk_callback (); + +int _nbd_chunk_callback_wrapper (void *user_data, const void *subbuf, + size_t count, uint64_t offset, + unsigned status, int *error); +void _nbd_chunk_callback_free (void *user_data); + +extern int completion_callback (); + +int _nbd_completion_callback_wrapper (void *user_data, int *error); +void _nbd_completion_callback_free (void *user_data); + +extern int debug_callback (); + +int _nbd_debug_callback_wrapper (void *user_data, const char *context, + const char *msg); +void _nbd_debug_callback_free (void *user_data); + +extern int extent_callback (); + +int _nbd_extent_callback_wrapper (void *user_data, const char *metacontext, + uint64_t offset, uint32_t *entries, + size_t nr_entries, int *error); +void _nbd_extent_callback_free (void *user_data); + +extern int list_callback (); + +int _nbd_list_callback_wrapper (void *user_data, const char *name, + const char *description); +void _nbd_list_callback_free (void *user_data); + +extern int context_callback (); + +int _nbd_context_callback_wrapper (void *user_data, const char *name); +void _nbd_context_callback_free (void *user_data); + +#endif /* LIBNBD_GOLANG_WRAPPERS_H */ diff --git a/vendor/modules.txt b/vendor/modules.txt index 75a54f9b8..6e8ab16a9 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -388,4 +388,7 @@ k8s.io/utils/clock k8s.io/utils/exec k8s.io/utils/io k8s.io/utils/keymutex +# libguestfs.org/libnbd v1.13.1 +## explicit; go 1.13 +libguestfs.org/libnbd # github.com/pojntfx/go-nbd => github.com/chazapis/go-nbd v0.0.0-20231031233644-40daa63e22c3 From bf4a7043f56412b98e2235522c8209daf6ed6fb4 Mon Sep 17 00:00:00 2001 From: Mike Toutou Date: Thu, 7 Dec 2023 15:25:07 +0200 Subject: [PATCH 04/10] Refactoring for go fmt command --- pkg/backend/remote/remote.go | 2 +- pkg/controller/init_frontend.go | 2 +- pkg/dataconn/nbd_client.go | 16 +++++++------- pkg/dataconn/nbd_server.go | 26 +++++++++++------------ pkg/frontend/nbd/frontend.go | 37 ++++++++++++++++----------------- pkg/replica/rpc/dataserver.go | 2 +- 6 files changed, 42 insertions(+), 43 deletions(-) diff --git a/pkg/backend/remote/remote.go b/pkg/backend/remote/remote.go index eb32293c5..1dab1a8c4 100644 --- a/pkg/backend/remote/remote.go +++ b/pkg/backend/remote/remote.go @@ -362,7 +362,7 @@ func (rf *Factory) Create(volumeName, address string, dataServerProtocol types.D } var dataConnClient *dataconn.Client if nbdEnabled > 0 { - dataConnClientNBD := dataconn.NewNBDClientWrapper(conn, engineToReplicaTimeout, nbdEnabled) + dataConnClientNBD := dataconn.NewNbdClientWrapper(conn, engineToReplicaTimeout, nbdEnabled) r.ReaderWriterUnmapperAt = dataConnClientNBD } else { dataConnClient = dataconn.NewClient(conn, engineToReplicaTimeout) diff --git a/pkg/controller/init_frontend.go b/pkg/controller/init_frontend.go index 33e9b2b7d..d11136da5 100644 --- a/pkg/controller/init_frontend.go +++ b/pkg/controller/init_frontend.go @@ -5,10 +5,10 @@ import ( "time" devtypes "github.com/longhorn/go-iscsi-helper/types" + "github.com/longhorn/longhorn-engine/pkg/frontend/nbd" "github.com/longhorn/longhorn-engine/pkg/frontend/rest" "github.com/longhorn/longhorn-engine/pkg/frontend/socket" "github.com/longhorn/longhorn-engine/pkg/frontend/tgt" - "github.com/longhorn/longhorn-engine/pkg/frontend/nbd" "github.com/longhorn/longhorn-engine/pkg/types" "github.com/sirupsen/logrus" ) diff --git a/pkg/dataconn/nbd_client.go b/pkg/dataconn/nbd_client.go index 16a81b736..36404720c 100644 --- a/pkg/dataconn/nbd_client.go +++ b/pkg/dataconn/nbd_client.go @@ -8,7 +8,7 @@ import ( "libguestfs.org/libnbd" ) -type nbdClientWrapper struct { +type NbdClientWrapper struct { handles []*libnbd.Libnbd conn net.Conn maxConnections int @@ -17,8 +17,8 @@ type nbdClientWrapper struct { end chan struct{} } -func NewNBDClientWrapper(conn net.Conn, engineToReplicaTimeout time.Duration, nbdEnabled int) *nbdClientWrapper { - wrapper := &nbdClientWrapper{ +func NewNbdClientWrapper(conn net.Conn, engineToReplicaTimeout time.Duration, nbdEnabled int) *NbdClientWrapper { + wrapper := &NbdClientWrapper{ handles: make([]*libnbd.Libnbd, nbdEnabled), conn: conn, maxConnections: nbdEnabled, @@ -30,7 +30,7 @@ func NewNBDClientWrapper(conn net.Conn, engineToReplicaTimeout time.Duration, nb return wrapper } -func (w *nbdClientWrapper) handle() { +func (w *NbdClientWrapper) handle() { for i := 0; i < w.maxConnections; i++ { h, err := libnbd.Create() if err != nil { @@ -51,7 +51,7 @@ func (w *nbdClientWrapper) handle() { } } -func (w *nbdClientWrapper) ReadAt(buf []byte, offset int64) (int, error) { +func (w *NbdClientWrapper) ReadAt(buf []byte, offset int64) (int, error) { w.indexLock.Lock() w.next = (w.next + 1) % w.maxConnections index := w.next @@ -64,7 +64,7 @@ func (w *nbdClientWrapper) ReadAt(buf []byte, offset int64) (int, error) { return len(buf), nil } -func (w *nbdClientWrapper) WriteAt(buf []byte, offset int64) (int, error) { +func (w *NbdClientWrapper) WriteAt(buf []byte, offset int64) (int, error) { w.indexLock.Lock() w.next = (w.next + 1) % w.maxConnections index := w.next @@ -77,12 +77,12 @@ func (w *nbdClientWrapper) WriteAt(buf []byte, offset int64) (int, error) { return len(buf), nil } -func (w *nbdClientWrapper) UnmapAt(length uint32, offset int64) (int, error) { +func (w *NbdClientWrapper) UnmapAt(length uint32, offset int64) (int, error) { return int(length), nil } -func (w *nbdClientWrapper) Close() { +func (w *NbdClientWrapper) Close() { for i := 0; i < w.maxConnections; i++ { w.handles[i].Close() } diff --git a/pkg/dataconn/nbd_server.go b/pkg/dataconn/nbd_server.go index 97f568b41..bc3d873cd 100644 --- a/pkg/dataconn/nbd_server.go +++ b/pkg/dataconn/nbd_server.go @@ -9,19 +9,19 @@ import ( "github.com/pojntfx/go-nbd/pkg/server" ) -type nbdServer struct { +type NbdServer struct { conn net.Conn s *replica.Server } -func NewNBDServer(conn net.Conn, s *replica.Server) *nbdServer { - return &nbdServer{ +func NewNbdServer(conn net.Conn, s *replica.Server) *NbdServer { + return &NbdServer{ conn: conn, s: s, } } -func (s *nbdServer) Handle() { +func (s *NbdServer) Handle() { if err := server.Handle( s.conn, []*server.Export{ @@ -41,27 +41,27 @@ func (s *nbdServer) Handle() { } } -func (b *nbdServer) ReadAt(p []byte, off int64) (n int, err error) { - n, err = b.s.ReadAt(p, off) +func (s *NbdServer) ReadAt(p []byte, off int64) (n int, err error) { + n, err = s.s.ReadAt(p, off) return } -func (b *nbdServer) WriteAt(p []byte, off int64) (n int, err error) { - n, err = b.s.WriteAt(p, off) +func (s *NbdServer) WriteAt(p []byte, off int64) (n int, err error) { + n, err = s.s.WriteAt(p, off) return } -func (b *nbdServer) Size() (int64, error) { - _, info := b.s.Status() +func (s *NbdServer) Size() (int64, error) { + _, info := s.s.Status() return info.Size, nil } -func (b *nbdServer) Sync() error { +func (s *NbdServer) Sync() error { return nil } -func (b *nbdServer) Ping() error { - state, info := b.s.Status() +func (s *NbdServer) Ping() error { + state, info := s.s.Status() if state == types.ReplicaStateError { return fmt.Errorf("ping failure due to %v", info.Error) } diff --git a/pkg/frontend/nbd/frontend.go b/pkg/frontend/nbd/frontend.go index 276d5765e..1c025f5f0 100644 --- a/pkg/frontend/nbd/frontend.go +++ b/pkg/frontend/nbd/frontend.go @@ -9,9 +9,9 @@ import ( "strings" "github.com/pkg/errors" - "github.com/sirupsen/logrus" - nbd "github.com/pojntfx/go-nbd/pkg/server" "github.com/pmorjan/kmod" + nbd "github.com/pojntfx/go-nbd/pkg/server" + "github.com/sirupsen/logrus" "github.com/longhorn/longhorn-engine/pkg/types" ) @@ -24,15 +24,15 @@ const ( ) type Nbd struct { - Volume string - Size int64 - SectorSize int - - isUp bool - socketPath string - nbdDevicePath string - connections int - clients int + Volume string + Size int64 + SectorSize int + + isUp bool + socketPath string + nbdDevicePath string + connections int + clients int } func New(frontendStreams int) types.Frontend { @@ -106,7 +106,6 @@ func (n *Nbd) getNextFreeNbdDevice() (string, error) { return "", fmt.Errorf("no more nbd devices") } - func (n *Nbd) Shutdown() error { if n.Volume == "" || !n.isUp { return nil @@ -234,31 +233,31 @@ func (n *Nbd) handleServerConnection(conn net.Conn, rwu types.ReaderWriterUnmapp } } -type NbdBackend struct { +type Backend struct { rwu types.ReaderWriterUnmapperAt size int64 } -func NewNbdBackend(rwu types.ReaderWriterUnmapperAt, size int64) *NbdBackend { - return &NbdBackend{ +func NewNbdBackend(rwu types.ReaderWriterUnmapperAt, size int64) *Backend { + return &Backend{ rwu: rwu, size: size, } } -func (b *NbdBackend) ReadAt(p []byte, off int64) (n int, err error) { +func (b *Backend) ReadAt(p []byte, off int64) (n int, err error) { return b.rwu.ReadAt(p, off) } -func (b *NbdBackend) WriteAt(p []byte, off int64) (n int, err error) { +func (b *Backend) WriteAt(p []byte, off int64) (n int, err error) { return b.rwu.WriteAt(p, off) } -func (b *NbdBackend) Size() (int64, error) { +func (b *Backend) Size() (int64, error) { return b.size, nil } -func (b *NbdBackend) Sync() error { +func (b *Backend) Sync() error { return nil } diff --git a/pkg/replica/rpc/dataserver.go b/pkg/replica/rpc/dataserver.go index 7f5e1e95e..054c24d68 100644 --- a/pkg/replica/rpc/dataserver.go +++ b/pkg/replica/rpc/dataserver.go @@ -60,7 +60,7 @@ func (s *DataServer) listenAndServeTCP() error { if s.nbdEnabled > 0 { go func() { - nbdServer := dataconn.NewNBDServer(conn, s.s) + nbdServer := dataconn.NewNbdServer(conn, s.s) nbdServer.Handle() }() } else { From 7708e070cef9ca4002eba70582ca119016ecca6a Mon Sep 17 00:00:00 2001 From: Antony Chazapis Date: Fri, 15 Dec 2023 18:15:06 +0200 Subject: [PATCH 05/10] Fix build --- Dockerfile.dapper | 9 +++++++++ scripts/build | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Dockerfile.dapper b/Dockerfile.dapper index 4d2025b60..1e3f66575 100644 --- a/Dockerfile.dapper +++ b/Dockerfile.dapper @@ -139,6 +139,15 @@ RUN cd /go/src/github.com/longhorn && \ cp -r integration/rpc/ ${DAPPER_SOURCE}/integration/rpc/ && \ cp longhorn-instance-manager /usr/local/bin +# Build libnbd +RUN zypper -n install libxml2-devel +RUN cd /usr/src && \ + wget -O - https://download.libguestfs.org/libnbd/1.13-development/libnbd-1.13.1.tar.gz | tar -xzf - && \ + cd libnbd-1.13.1 && \ + ./configure --disable-ocaml --disable-python --disable-golang; \ + make; \ + make install + VOLUME /tmp ENV TMPDIR /tmp ENTRYPOINT ["./scripts/entry"] diff --git a/scripts/build b/scripts/build index 21106ffd4..cbfe4735c 100755 --- a/scripts/build +++ b/scripts/build @@ -6,7 +6,7 @@ source $(dirname $0)/version LINKFLAGS="-X main.Version=$VERSION -X main.GitCommit=$GITCOMMIT -X main.BuildDate=$BUILDDATE - -linkmode external -extldflags -static" + -linkmode external" # add coverage flags if there is no tag and it's on master or a version branch like v1.6.x COMMIT_BRANCH=$(git rev-parse --abbrev-ref HEAD) From 7ad1a3d16f45f52bdea52d71ea6ff8326191db32 Mon Sep 17 00:00:00 2001 From: Mike Toutou Date: Thu, 21 Dec 2023 16:14:24 +0200 Subject: [PATCH 06/10] Build: libqcow, libnbd and nbd-client added to release container --- package/Dockerfile | 23 ++++++++++++++++++++++- pkg/frontend/nbd/frontend.go | 2 +- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/package/Dockerfile b/package/Dockerfile index 1150dc0d4..c0d2752b4 100644 --- a/package/Dockerfile +++ b/package/Dockerfile @@ -27,6 +27,23 @@ RUN cd /usr/src && \ make; \ make install +RUN wget -O - https://s3-us-west-1.amazonaws.com/rancher-longhorn/libqcow-alpha-20181117.tar.gz | tar xvzf - -C /usr/src +RUN cd /usr/src/libqcow-20181117 && \ + ./configure +RUN cd /usr/src/libqcow-20181117 && \ + make -j$(nproc) && \ + make install + +RUN zypper -n install libxml2-devel nbd +RUN cd /usr/src && \ + wget -O - https://download.libguestfs.org/libnbd/1.13-development/libnbd-1.13.1.tar.gz | tar -xzf - && \ + cd libnbd-1.13.1 && \ + ./configure --disable-ocaml --disable-python --disable-golang; \ + make; \ + make install + +RUN ldconfig + # Install grpc_health_probe RUN wget https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/v0.4.21/grpc_health_probe-linux-${ARCH} -O /usr/local/bin/grpc_health_probe && \ chmod +x /usr/local/bin/grpc_health_probe @@ -39,7 +56,7 @@ RUN zypper -n addrepo --refresh https://download.opensuse.org/repositories/syste zypper -n addrepo --refresh https://download.opensuse.org/repositories/network:/utilities/SLE_15_SP5/network:utilities.repo && \ zypper --gpg-auto-import-keys ref -RUN zypper -n install nfs-client nfs4-acl-tools cifs-utils libaio1 sg3_utils \ +RUN zypper -n install nfs-client nfs4-acl-tools cifs-utils libaio1 sg3_utils nbd \ iputils iproute2 qemu-tools e2fsprogs && \ rm -rf /var/cache/zypp/* @@ -57,6 +74,10 @@ COPY bin/longhorn bin/longhorn-instance-manager /usr/local/bin/ COPY package/launch-simple-longhorn package/engine-manager package/launch-simple-file /usr/local/bin/ +COPY --from=builder /usr/sbin/nbd-client /usr/sbin/nbd-client +COPY --from=builder /usr/local/lib /usr/local/lib +ENV LD_LIBRARY_PATH=/usr/local/lib + VOLUME /usr/local/bin # Add Tini diff --git a/pkg/frontend/nbd/frontend.go b/pkg/frontend/nbd/frontend.go index 1c025f5f0..2f5a1f8aa 100644 --- a/pkg/frontend/nbd/frontend.go +++ b/pkg/frontend/nbd/frontend.go @@ -218,7 +218,7 @@ func (n *Nbd) handleServerConnection(conn net.Conn, rwu types.ReaderWriterUnmapp conn, []*nbd.Export{ { - Name: "", + Name: n.Volume, Description: "Longhorn volume", Backend: b, }, From 21b354b30964e981957429b6916fcd5a02b933a1 Mon Sep 17 00:00:00 2001 From: Mike Toutou Date: Sat, 13 Jan 2024 13:52:06 +0200 Subject: [PATCH 07/10] Add frontend streams and nbd dataserver parameters to launch-simple-longhorn script --- package/launch-simple-longhorn | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/package/launch-simple-longhorn b/package/launch-simple-longhorn index 3464d4b05..9e5cb6dcc 100755 --- a/package/launch-simple-longhorn +++ b/package/launch-simple-longhorn @@ -7,6 +7,8 @@ mount --rbind /host/dev /dev volume=$1 size=$2 frontend=$3 +frontendStreams=$4 +nbdEnabled=$5 if [ -z $volume ] then @@ -28,6 +30,23 @@ then frontend="tgt-blockdev" fi +if [ -z $frontendStreams ] +then + echo Use default frontend streams. No frontend nbd streams + frontendStreams="" +else + frontendStreams="--frontend-streams "$frontendStreams +fi + +if [ -z $nbdEnabled ] +then + echo Use default dataserver. Dataconn dataserver + nbdEnabled="" +else + nbdEnabled="--nbd-enabled "$nbdEnabled +fi + + function start() { set +e while true; @@ -44,12 +63,12 @@ function start() { tgtd -f 2>&1 | tee /var/log/tgtd.log & - longhorn-instance-manager process create --name "$volume-r" --binary /usr/local/bin/longhorn --port-count 15 --port-args "--listen,localhost:" -- replica /volume/ "--size" $size + longhorn-instance-manager process create --name "$volume-r" --binary /usr/local/bin/longhorn --port-count 15 --port-args "--listen,localhost:" -- replica /volume/ "--size" $size $nbdEnabled # wait for the replica to be started sleep 5 - longhorn-instance-manager process create --name "$volume-e" --binary /usr/local/bin/longhorn --port-count 1 --port-args "--listen,localhost:" -- controller $volume --frontend $frontend "--size" $size "--current-size" $size --replica tcp://localhost:10000 + longhorn-instance-manager process create --name "$volume-e" --binary /usr/local/bin/longhorn --port-count 1 --port-args "--listen,localhost:" -- controller $volume --frontend $frontend "--size" $size "--current-size" $size --replica tcp://localhost:10000 $nbdEnabled $frontendStreams } start & From d8827534c97cfff2490752029cbe253226a2a8ab Mon Sep 17 00:00:00 2001 From: Mike Toutou Date: Fri, 9 Feb 2024 14:22:23 +0200 Subject: [PATCH 08/10] nbd client and server fix --- pkg/dataconn/nbd_client.go | 6 ++++-- pkg/dataconn/nbd_server.go | 9 ++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/pkg/dataconn/nbd_client.go b/pkg/dataconn/nbd_client.go index 36404720c..f3722dbb4 100644 --- a/pkg/dataconn/nbd_client.go +++ b/pkg/dataconn/nbd_client.go @@ -15,6 +15,7 @@ type NbdClientWrapper struct { next int indexLock sync.Mutex end chan struct{} + handlesAlive chan struct{} } func NewNbdClientWrapper(conn net.Conn, engineToReplicaTimeout time.Duration, nbdEnabled int) *NbdClientWrapper { @@ -24,9 +25,10 @@ func NewNbdClientWrapper(conn net.Conn, engineToReplicaTimeout time.Duration, nb maxConnections: nbdEnabled, next: 0, end: make(chan struct{}), + handlesAlive: make(chan struct{}), } go wrapper.handle() - + <-wrapper.handlesAlive return wrapper } @@ -44,7 +46,7 @@ func (w *NbdClientWrapper) handle() { panic(err) } } - + w.handlesAlive <- struct{}{} for { <-w.end return diff --git a/pkg/dataconn/nbd_server.go b/pkg/dataconn/nbd_server.go index bc3d873cd..a5223abc0 100644 --- a/pkg/dataconn/nbd_server.go +++ b/pkg/dataconn/nbd_server.go @@ -7,6 +7,7 @@ import ( "github.com/longhorn/longhorn-engine/pkg/replica" "github.com/longhorn/longhorn-engine/pkg/types" "github.com/pojntfx/go-nbd/pkg/server" + "github.com/sirupsen/logrus" ) type NbdServer struct { @@ -37,18 +38,16 @@ func (s *NbdServer) Handle() { PreferredBlockSize: uint32(512), MaximumBlockSize: uint32(512), }); err != nil { - panic(err) + logrus.WithError(err).Errorf("Failed to handle dataconn nbd connection") } } func (s *NbdServer) ReadAt(p []byte, off int64) (n int, err error) { - n, err = s.s.ReadAt(p, off) - return + return s.s.ReadAt(p, off) } func (s *NbdServer) WriteAt(p []byte, off int64) (n int, err error) { - n, err = s.s.WriteAt(p, off) - return + return s.s.WriteAt(p, off) } func (s *NbdServer) Size() (int64, error) { From 2be76929ae8c533d144513645020d13ef5af8b0b Mon Sep 17 00:00:00 2001 From: Toutou98 Date: Tue, 26 Mar 2024 21:38:23 +0200 Subject: [PATCH 09/10] Replaced locks with chans. Added error messages on ReadAt/WriteAt --- pkg/dataconn/nbd_client.go | 123 +++++++++++++++++++++++++++++-------- 1 file changed, 97 insertions(+), 26 deletions(-) diff --git a/pkg/dataconn/nbd_client.go b/pkg/dataconn/nbd_client.go index f3722dbb4..46cce15e9 100644 --- a/pkg/dataconn/nbd_client.go +++ b/pkg/dataconn/nbd_client.go @@ -2,28 +2,27 @@ package dataconn import ( "net" - "sync" "time" + "github.com/sirupsen/logrus" "libguestfs.org/libnbd" ) -type NbdClientWrapper struct { +type NbdClientController struct { handles []*libnbd.Libnbd conn net.Conn maxConnections int - next int - indexLock sync.Mutex + handleCh chan *libnbd.Libnbd end chan struct{} handlesAlive chan struct{} } -func NewNbdClientWrapper(conn net.Conn, engineToReplicaTimeout time.Duration, nbdEnabled int) *NbdClientWrapper { - wrapper := &NbdClientWrapper{ +func NewNbdClientWrapper(conn net.Conn, engineToReplicaTimeout time.Duration, nbdEnabled int) *NbdClientController { + wrapper := &NbdClientController{ handles: make([]*libnbd.Libnbd, nbdEnabled), conn: conn, maxConnections: nbdEnabled, - next: 0, + handleCh: make(chan *libnbd.Libnbd, nbdEnabled), end: make(chan struct{}), handlesAlive: make(chan struct{}), } @@ -32,7 +31,7 @@ func NewNbdClientWrapper(conn net.Conn, engineToReplicaTimeout time.Duration, nb return wrapper } -func (w *NbdClientWrapper) handle() { +func (w *NbdClientController) handle() { for i := 0; i < w.maxConnections; i++ { h, err := libnbd.Create() if err != nil { @@ -45,48 +44,120 @@ func (w *NbdClientWrapper) handle() { if err != nil { panic(err) } + w.handleCh <- h } w.handlesAlive <- struct{}{} - for { - <-w.end - return - } + <-w.end } -func (w *NbdClientWrapper) ReadAt(buf []byte, offset int64) (int, error) { - w.indexLock.Lock() - w.next = (w.next + 1) % w.maxConnections - index := w.next - w.indexLock.Unlock() - err := w.handles[index].Pread(buf, uint64(offset), nil) +func (w *NbdClientController) ReadAt(buf []byte, offset int64) (int, error) { + h := <-w.handleCh + err := h.Pread(buf, uint64(offset), nil) + w.handleCh <- h if err != nil { + logrus.WithError(err).Error("Failed to read from NBD server: ", w.conn.RemoteAddr().String()) return 0, err } return len(buf), nil } -func (w *NbdClientWrapper) WriteAt(buf []byte, offset int64) (int, error) { - w.indexLock.Lock() - w.next = (w.next + 1) % w.maxConnections - index := w.next - w.indexLock.Unlock() - err := w.handles[index].Pwrite(buf, uint64(offset), nil) +func (w *NbdClientController) WriteAt(buf []byte, offset int64) (int, error) { + h := <-w.handleCh + err := h.Pwrite(buf, uint64(offset), nil) + w.handleCh <- h if err != nil { + logrus.WithError(err).Error("Failed to write to NBD server: ", w.conn.RemoteAddr().String()) return 0, err } return len(buf), nil } -func (w *NbdClientWrapper) UnmapAt(length uint32, offset int64) (int, error) { +func (w *NbdClientController) UnmapAt(length uint32, offset int64) (int, error) { return int(length), nil } -func (w *NbdClientWrapper) Close() { +func (w *NbdClientController) Close() { for i := 0; i < w.maxConnections; i++ { w.handles[i].Close() } w.end <- struct{}{} } + +// type NbdClientWrapper struct { +// handles []*libnbd.Libnbd +// conn net.Conn +// maxConnections int +// next int32 +// end chan struct{} +// handlesAlive chan struct{} +// } + +// func NewNbdClientWrapper(conn net.Conn, engineToReplicaTimeout time.Duration, nbdEnabled int) *NbdClientWrapper { +// wrapper := &NbdClientWrapper{ +// handles: make([]*libnbd.Libnbd, nbdEnabled), +// conn: conn, +// maxConnections: nbdEnabled, +// next: 0, +// end: make(chan struct{}), +// handlesAlive: make(chan struct{}), +// } +// go wrapper.handle() +// <-wrapper.handlesAlive +// return wrapper +// } + +// func (w *NbdClientWrapper) handle() { +// for i := 0; i < w.maxConnections; i++ { +// h, err := libnbd.Create() +// if err != nil { +// panic(err) +// } + +// w.handles[i] = h +// uri := "nbd://" + w.conn.RemoteAddr().String() +// err = w.handles[i].ConnectUri(uri) +// if err != nil { +// panic(err) +// } +// } +// w.handlesAlive <- struct{}{} +// for { +// <-w.end +// return +// } +// } + +// func (w *NbdClientWrapper) ReadAt(buf []byte, offset int64) (int, error) { +// index := atomic.AddInt32(&w.next, 1) % int32(w.maxConnections) +// err := w.handles[index].Pread(buf, uint64(offset), nil) +// if err != nil { +// return 0, err +// } + +// return len(buf), nil +// } + +// func (w *NbdClientWrapper) WriteAt(buf []byte, offset int64) (int, error) { +// index := atomic.AddInt32(&w.next, 1) % int32(w.maxConnections) +// err := w.handles[index].Pwrite(buf, uint64(offset), nil) +// if err != nil { +// return 0, err +// } + +// return len(buf), nil +// } + +// func (w *NbdClientWrapper) UnmapAt(length uint32, offset int64) (int, error) { +// return int(length), nil + +// } + +// func (w *NbdClientWrapper) Close() { +// for i := 0; i < w.maxConnections; i++ { +// w.handles[i].Close() +// } +// w.end <- struct{}{} +// } From 7206bc18303705438df28fedcff6d60215faecde Mon Sep 17 00:00:00 2001 From: Toutou98 Date: Tue, 26 Mar 2024 23:06:53 +0200 Subject: [PATCH 10/10] remove comments --- pkg/dataconn/nbd_client.go | 76 -------------------------------------- 1 file changed, 76 deletions(-) diff --git a/pkg/dataconn/nbd_client.go b/pkg/dataconn/nbd_client.go index 46cce15e9..c028a4cac 100644 --- a/pkg/dataconn/nbd_client.go +++ b/pkg/dataconn/nbd_client.go @@ -85,79 +85,3 @@ func (w *NbdClientController) Close() { } w.end <- struct{}{} } - -// type NbdClientWrapper struct { -// handles []*libnbd.Libnbd -// conn net.Conn -// maxConnections int -// next int32 -// end chan struct{} -// handlesAlive chan struct{} -// } - -// func NewNbdClientWrapper(conn net.Conn, engineToReplicaTimeout time.Duration, nbdEnabled int) *NbdClientWrapper { -// wrapper := &NbdClientWrapper{ -// handles: make([]*libnbd.Libnbd, nbdEnabled), -// conn: conn, -// maxConnections: nbdEnabled, -// next: 0, -// end: make(chan struct{}), -// handlesAlive: make(chan struct{}), -// } -// go wrapper.handle() -// <-wrapper.handlesAlive -// return wrapper -// } - -// func (w *NbdClientWrapper) handle() { -// for i := 0; i < w.maxConnections; i++ { -// h, err := libnbd.Create() -// if err != nil { -// panic(err) -// } - -// w.handles[i] = h -// uri := "nbd://" + w.conn.RemoteAddr().String() -// err = w.handles[i].ConnectUri(uri) -// if err != nil { -// panic(err) -// } -// } -// w.handlesAlive <- struct{}{} -// for { -// <-w.end -// return -// } -// } - -// func (w *NbdClientWrapper) ReadAt(buf []byte, offset int64) (int, error) { -// index := atomic.AddInt32(&w.next, 1) % int32(w.maxConnections) -// err := w.handles[index].Pread(buf, uint64(offset), nil) -// if err != nil { -// return 0, err -// } - -// return len(buf), nil -// } - -// func (w *NbdClientWrapper) WriteAt(buf []byte, offset int64) (int, error) { -// index := atomic.AddInt32(&w.next, 1) % int32(w.maxConnections) -// err := w.handles[index].Pwrite(buf, uint64(offset), nil) -// if err != nil { -// return 0, err -// } - -// return len(buf), nil -// } - -// func (w *NbdClientWrapper) UnmapAt(length uint32, offset int64) (int, error) { -// return int(length), nil - -// } - -// func (w *NbdClientWrapper) Close() { -// for i := 0; i < w.maxConnections; i++ { -// w.handles[i].Close() -// } -// w.end <- struct{}{} -// }