Add rbd_writesame()

In order to provide the ability to do thick provisioning of RBD images,
Image.WriteSame() can be used. The `rbd` commandline utility calls the
rbd_writesame() function when an image is created with the
`--thick-provision` option.

See-also: ceph/ceph-csi#1675
Signed-off-by: Niels de Vos <ndevos@redhat.com>
This commit is contained in:
Niels de Vos 2020-11-11 09:06:16 +01:00 committed by mergify[bot]
parent 460837e900
commit 0afcf98b34
2 changed files with 113 additions and 0 deletions

View File

@ -808,6 +808,36 @@ func (image *Image) WriteAt(data []byte, off int64) (n int, err error) {
return ret, err
}
// WriteSame repeats writing data from starting point ofs until n bytes have
// been written.
//
// Implements:
// ssize_t rbd_writesame(rbd_image_t image, uint64_t ofs, size_t len,
// const char *buf, size_t data_len, int op_flags);
func (image *Image) WriteSame(ofs, n uint64, data []byte, flags rados.OpFlags) (int64, error) {
var err error
if err = image.validate(imageIsOpen); err != nil {
return 0, err
}
if len(data) == 0 {
return 0, nil
}
ret := C.rbd_writesame(image.image,
C.uint64_t(ofs),
C.uint64_t(n),
(*C.char)(unsafe.Pointer(&data[0])),
C.size_t(len(data)),
C.int(flags))
if ret < 0 {
err = getError(C.int(ret))
}
return int64(ret), err
}
// Flush all cached writes to storage.
//
// Implements:

View File

@ -521,6 +521,86 @@ func TestImageDiscard(t *testing.T) {
conn.Shutdown()
}
func TestWriteSame(t *testing.T) {
conn := radosConnect(t)
poolname := GetUUID()
err := conn.MakePool(poolname)
assert.NoError(t, err)
ioctx, err := conn.OpenIOContext(poolname)
require.NoError(t, err)
name := GetUUID()
options := NewRbdImageOptions()
defer options.Destroy()
err = options.SetUint64(ImageOptionOrder, uint64(testImageOrder))
assert.NoError(t, err)
err = CreateImage(ioctx, name, testImageSize, options)
require.NoError(t, err)
img, err := OpenImage(ioctx, name, NoSnapshot)
assert.NoError(t, err)
data_out := []byte("this is a string of 28 bytes")
t.Run("writeAndRead", func(t *testing.T) {
// write some bytes at the start of the image
n_out, err := img.WriteSame(0, uint64(4*len(data_out)), data_out, rados.OpFlagNone)
assert.Equal(t, int64(4*len(data_out)), n_out)
assert.NoError(t, err)
// the same string should be read from byte 0
data_in := make([]byte, len(data_out))
n_in, err := img.ReadAt(data_in, 0)
assert.Equal(t, len(data_out), n_in)
assert.Equal(t, data_out, data_in)
assert.NoError(t, err)
// the same string should be read from byte 28
data_in = make([]byte, len(data_out))
n_in, err = img.ReadAt(data_in, 28)
assert.Equal(t, len(data_out), n_in)
assert.Equal(t, data_out, data_in)
assert.NoError(t, err)
})
t.Run("writePartialData", func(t *testing.T) {
// writing a non-multiple of data_out len will fail
_, err = img.WriteSame(0, 64, data_out, rados.OpFlagNone)
assert.Error(t, err)
})
t.Run("writeNoData", func(t *testing.T) {
// writing empty data should succeed
n_in, err := img.WriteSame(0, 64, []byte(""), rados.OpFlagNone)
assert.NoError(t, err)
assert.Equal(t, int64(0), n_in)
})
err = img.Close()
assert.NoError(t, err)
t.Run("writeSameReadOnly", func(t *testing.T) {
// writing to a read-only image should fail
img, err = OpenImageReadOnly(ioctx, name, NoSnapshot)
assert.NoError(t, err)
_, err = img.WriteSame(96, 32, data_out, rados.OpFlagNone)
assert.Error(t, err)
err = img.Close()
assert.NoError(t, err)
})
err = img.Remove()
assert.NoError(t, err)
ioctx.Destroy()
conn.DeletePool(poolname)
conn.Shutdown()
}
func TestIOReaderWriter(t *testing.T) {
conn := radosConnect(t)
@ -1016,6 +1096,9 @@ func TestErrorImageNotOpen(t *testing.T) {
_, err = image.WriteAt(nil, 0)
assert.Equal(t, err, ErrImageNotOpen)
_, err = image.WriteSame(64, 128, []byte("not opened"), rados.OpFlagNone)
assert.Equal(t, err, ErrImageNotOpen)
err = image.Flush()
assert.Equal(t, err, ErrImageNotOpen)
}