mirror of https://github.com/ceph/go-ceph
cutil: use SyncBuffer for iovec type
The main motivation for PtrGuard was read and write buffers as they are used in iovec. This change uses SyncBuffer for the iovec implementation, so that the no-copy PtrGuard implementation can be enabled with the with_ptrguard build tag. Signed-off-by: Sven Anderson <sven@redhat.com>
This commit is contained in:
parent
430dea5b7f
commit
b8a803ccbb
|
@ -158,6 +158,7 @@ func (f *File) Preadv(data [][]byte, offset int64) (int, error) {
|
||||||
case ret == 0:
|
case ret == 0:
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
}
|
}
|
||||||
|
iov.Sync()
|
||||||
return int(ret), nil
|
return int(ret), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,74 +5,56 @@ package cutil
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
var iovecSize uintptr
|
// Iovec is a slice of iovec structs. Might have allocated C memory, so it must
|
||||||
|
// be freed with the Free() method.
|
||||||
// StructIovecPtr is an unsafe pointer wrapping C's `*struct iovec`.
|
|
||||||
type StructIovecPtr unsafe.Pointer
|
|
||||||
|
|
||||||
// Iovec helps manage struct iovec arrays needed by some C functions.
|
|
||||||
type Iovec struct {
|
type Iovec struct {
|
||||||
// cvec represents an array of struct iovec C memory
|
iovec []C.struct_iovec
|
||||||
cvec unsafe.Pointer
|
sbs []*SyncBuffer
|
||||||
// length of the array (in elements)
|
|
||||||
length int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewIovec creates an Iovec, and underlying C memory, of the specified size.
|
const iovecSize = C.sizeof_struct_iovec
|
||||||
func NewIovec(l int) *Iovec {
|
|
||||||
r := &Iovec{
|
// ByteSlicesToIovec creates an Iovec and links it to Go buffers in data.
|
||||||
cvec: C.malloc(C.size_t(l) * C.size_t(iovecSize)),
|
func ByteSlicesToIovec(data [][]byte) (v Iovec) {
|
||||||
length: l,
|
n := len(data)
|
||||||
|
iovecMem := C.malloc(iovecSize * C.size_t(n))
|
||||||
|
v.iovec = (*[MaxIdx]C.struct_iovec)(iovecMem)[:n:n]
|
||||||
|
for i, b := range data {
|
||||||
|
sb := NewSyncBuffer(CPtr(&v.iovec[i].iov_base), b)
|
||||||
|
v.sbs = append(v.sbs, sb)
|
||||||
|
v.iovec[i].iov_len = C.size_t(len(b))
|
||||||
}
|
}
|
||||||
return r
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// ByteSlicesToIovec takes a slice of byte slices and returns a new iovec that
|
// Sync makes sure the slices contain the same as the C buffers
|
||||||
// maps the slice data to struct iovec entries.
|
func (v *Iovec) Sync() {
|
||||||
func ByteSlicesToIovec(data [][]byte) *Iovec {
|
for _, sb := range v.sbs {
|
||||||
iov := NewIovec(len(data))
|
sb.Sync()
|
||||||
for i := range data {
|
|
||||||
iov.Set(i, data[i])
|
|
||||||
}
|
}
|
||||||
return iov
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pointer returns a StructIovecPtr that represents the C memory of the
|
// Pointer returns a pointer to the iovec
|
||||||
// underlying array.
|
func (v *Iovec) Pointer() unsafe.Pointer {
|
||||||
func (v *Iovec) Pointer() StructIovecPtr {
|
return unsafe.Pointer(&v.iovec[0])
|
||||||
return StructIovecPtr(unsafe.Pointer(v.cvec))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Len returns the number of entries in the Iovec.
|
// Len returns a pointer to the iovec
|
||||||
func (v *Iovec) Len() int {
|
func (v *Iovec) Len() int {
|
||||||
return v.length
|
return len(v.iovec)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free the C memory in the Iovec.
|
// Free the C memory in the Iovec.
|
||||||
func (v *Iovec) Free() {
|
func (v *Iovec) Free() {
|
||||||
if v.cvec != nil {
|
for _, sb := range v.sbs {
|
||||||
C.free(v.cvec)
|
sb.Release()
|
||||||
v.cvec = nil
|
|
||||||
v.length = 0
|
|
||||||
}
|
}
|
||||||
|
if len(v.iovec) != 0 {
|
||||||
|
C.free(unsafe.Pointer(&v.iovec[0]))
|
||||||
}
|
}
|
||||||
|
v.iovec = nil
|
||||||
// Set will map the memory of the given byte slice to the iovec at the
|
|
||||||
// specified position.
|
|
||||||
func (v *Iovec) Set(i int, buf []byte) {
|
|
||||||
offset := uintptr(i) * iovecSize
|
|
||||||
iov := (*C.struct_iovec)(unsafe.Pointer(
|
|
||||||
uintptr(unsafe.Pointer(v.cvec)) + offset))
|
|
||||||
iov.iov_base = unsafe.Pointer(&buf[0])
|
|
||||||
iov.iov_len = C.size_t(len(buf))
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
var iovec C.struct_iovec
|
|
||||||
iovecSize = unsafe.Sizeof(iovec)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,53 +5,54 @@ import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestIovec(t *testing.T) {
|
func TestIovec(t *testing.T) {
|
||||||
t.Run("newAndFree", func(t *testing.T) {
|
strs := []string{
|
||||||
iov := NewIovec(3)
|
"foo",
|
||||||
iov.Free()
|
"barbar",
|
||||||
})
|
"bazbazbaz",
|
||||||
t.Run("setBufs", func(t *testing.T) {
|
|
||||||
b1 := []byte("foo")
|
|
||||||
b2 := []byte("barbar")
|
|
||||||
b3 := []byte("bazbazbaz")
|
|
||||||
iov := NewIovec(3)
|
|
||||||
iov.Set(0, b1)
|
|
||||||
iov.Set(1, b2)
|
|
||||||
iov.Set(2, b3)
|
|
||||||
iov.Free()
|
|
||||||
// free also unsets internal values
|
|
||||||
assert.Equal(t, unsafe.Pointer(nil), iov.cvec)
|
|
||||||
assert.Equal(t, 0, iov.length)
|
|
||||||
})
|
|
||||||
t.Run("testGetters", func(t *testing.T) {
|
|
||||||
b1 := []byte("foo")
|
|
||||||
b2 := []byte("barbar")
|
|
||||||
b3 := []byte("bazbazbaz")
|
|
||||||
b4 := []byte("zonk")
|
|
||||||
iov := NewIovec(4)
|
|
||||||
defer iov.Free()
|
|
||||||
iov.Set(0, b1)
|
|
||||||
iov.Set(1, b2)
|
|
||||||
iov.Set(2, b3)
|
|
||||||
iov.Set(3, b4)
|
|
||||||
|
|
||||||
assert.NotNil(t, iov.Pointer())
|
|
||||||
assert.Equal(t, 4, iov.Len())
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
var data [][]byte
|
||||||
func TestByteSlicesToIovec(t *testing.T) {
|
for _, s := range strs {
|
||||||
d := [][]byte{
|
data = append(data, []byte(s))
|
||||||
[]byte("ramekin"),
|
|
||||||
[]byte("shuffleboard"),
|
|
||||||
[]byte("tranche"),
|
|
||||||
[]byte("phycobilisomes"),
|
|
||||||
}
|
}
|
||||||
iov := ByteSlicesToIovec(d)
|
iovec := ByteSlicesToIovec(data)
|
||||||
defer iov.Free()
|
p := iovec.Pointer()
|
||||||
|
assert.NotNil(t, p)
|
||||||
assert.NotNil(t, iov.Pointer())
|
assert.Equal(t, iovec.Len(), len(data))
|
||||||
assert.Equal(t, 4, iov.Len())
|
assert.Equal(t, p, unsafe.Pointer(&iovec.iovec[0]))
|
||||||
|
for i, iov := range iovec.iovec {
|
||||||
|
require.NotNil(t, iov.iov_base)
|
||||||
|
assert.Equal(t, int(iov.iov_len), len(data[i]))
|
||||||
|
assert.Equal(t, data[i], (*[MaxIdx]byte)(iov.iov_base)[:iov.iov_len:iov.iov_len])
|
||||||
|
}
|
||||||
|
// data didn't change
|
||||||
|
for i, b := range data {
|
||||||
|
assert.Equal(t, string(b), strs[i])
|
||||||
|
}
|
||||||
|
// clear iovec buffers
|
||||||
|
for _, iov := range iovec.iovec {
|
||||||
|
b := (*[MaxIdx]byte)(iov.iov_base)[:iov.iov_len:iov.iov_len]
|
||||||
|
for i := range b {
|
||||||
|
b[i] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iovec.Sync()
|
||||||
|
// data must be cleared
|
||||||
|
for _, b := range data {
|
||||||
|
for i := range b {
|
||||||
|
assert.Zero(t, b[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iovec.Free()
|
||||||
|
for _, iov := range iovec.iovec {
|
||||||
|
assert.Equal(t, iov.iov_base, unsafe.Pointer(nil))
|
||||||
|
assert.Zero(t, iov.iov_len)
|
||||||
|
}
|
||||||
|
iovec.Free()
|
||||||
|
iovec.Sync()
|
||||||
|
iovec.Sync()
|
||||||
|
iovec.Free()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue