-
Notifications
You must be signed in to change notification settings - Fork 2
/
buse.go
117 lines (98 loc) · 2.49 KB
/
buse.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//go:build linux
// +build linux
package buse
import (
"net"
"os"
"syscall"
"github.com/dop251/nbd"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
type Device struct {
size int64
blockSize int
device string
driver nbd.Driver
deviceFp *os.File
sock int
client *nbd.Client
srvConn *nbd.ServerConn
disconnect chan struct{}
log *logrus.Logger
readOnly bool
}
func (bd *Device) startNBDClient() {
bd.client = nbd.NewClient(bd.device, bd.sock, bd.size)
if bd.log != nil {
bd.client.SetLogger(bd.log)
}
if bd.blockSize > 0 {
bd.client.SetBlockSize(bd.blockSize)
} else {
bd.client.SetBlockSize(512)
}
if _, ok := bd.driver.(nbd.Syncer); ok {
bd.client.SetSendFlush(true)
}
if _, ok := bd.driver.(nbd.Trimmer); ok {
bd.client.SetSendTrim(true)
}
bd.client.SetReadOnly(bd.readOnly)
err := bd.client.Run()
if err != nil && bd.log != nil {
bd.log.Errorf("Client has failed: %v", err)
}
bd.srvConn.Close()
bd.disconnect <- struct{}{}
}
// Disconnect disconnects the Device and interrupts the Run()
func (bd *Device) Disconnect() {
if err := bd.client.Close(); err == nil {
<-bd.disconnect
}
}
func (bd *Device) SetMaxProc(p int) {
bd.srvConn.SetMaxProc(p)
}
func (bd *Device) SetPool(pool nbd.ProcPool) {
bd.srvConn.SetPool(pool)
}
func (bd *Device) SetLogger(log *logrus.Logger) {
bd.log = log
bd.srvConn.SetLogger(log)
}
func (bd *Device) SetBlockSize(size int) {
bd.blockSize = size
}
func (bd *Device) SetReadOnly(flag bool) {
bd.readOnly = flag
}
// Run connects a Device to an actual device file
// and starts handling requests. It does not return until it's done serving requests.
func (bd *Device) Run() error {
go bd.startNBDClient()
defer bd.srvConn.Close()
return bd.srvConn.Serve()
}
func NewDevice(device string, size int64, driver nbd.Driver) (*Device, error) {
buseDevice := &Device{size: size, device: device, driver: driver}
sockPair, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
if err != nil {
return nil, errors.Wrap(err, "socketpair() failed")
}
buseDevice.deviceFp, err = os.OpenFile(device, os.O_RDWR, 0600)
if err != nil {
return nil, errors.Wrapf(err, "Cannot open '%s'", device)
}
fp := os.NewFile(uintptr(sockPair[0]), "unix")
conn, err := net.FileConn(fp)
if err != nil {
return nil, err
}
fp.Close() // duplicate
buseDevice.srvConn = nbd.NewServerConn(conn, driver)
buseDevice.sock = sockPair[1]
buseDevice.disconnect = make(chan struct{}, 1)
return buseDevice, nil
}