rbd: keep rados.IOContext for re-use

This prevents the need to open the IOContext for additional operations
on the image.

It also addresses a leak of the IOContext in case `rbdVolume.open()` was
called. The method only returned the `rbd.Image` without the possibility
to close the related IOContext.

Signed-off-by: Niels de Vos <ndevos@redhat.com>
This commit is contained in:
Niels de Vos 2020-06-03 09:37:44 +02:00 committed by mergify[bot]
parent 81b17c5157
commit 926f1e813c

View File

@ -104,6 +104,8 @@ type rbdVolume struct {
// conn is a connection to the Ceph cluster obtained from a ConnPool // conn is a connection to the Ceph cluster obtained from a ConnPool
conn *util.ClusterConnection conn *util.ClusterConnection
// an opened IOContext, call .openIoctx() before using
ioctx *rados.IOContext
} }
// rbdSnapshot represents a CSI snapshot and its RBD snapshot specifics // rbdSnapshot represents a CSI snapshot and its RBD snapshot specifics
@ -151,6 +153,9 @@ func (rv *rbdVolume) Connect(cr *util.Credentials) error {
// Destroy cleans up the rbdVolume and closes the connection to the Ceph // Destroy cleans up the rbdVolume and closes the connection to the Ceph
// cluster in case one was setup. // cluster in case one was setup.
func (rv *rbdVolume) Destroy() { func (rv *rbdVolume) Destroy() {
if rv.ioctx != nil {
rv.ioctx.Destroy()
}
if rv.conn != nil { if rv.conn != nil {
rv.conn.Destroy() rv.conn.Destroy()
} }
@ -200,13 +205,12 @@ func createImage(ctx context.Context, pOpts *rbdVolume, cr *util.Credentials) er
return err return err
} }
ioctx, err := pOpts.conn.GetIoctx(pOpts.Pool) err = pOpts.openIoctx()
if err != nil { if err != nil {
return errors.Wrapf(err, "failed to get IOContext") return errors.Wrapf(err, "failed to get IOContext")
} }
defer ioctx.Destroy()
err = librbd.CreateImage(ioctx, pOpts.RbdImageName, err = librbd.CreateImage(pOpts.ioctx, pOpts.RbdImageName,
uint64(util.RoundOffVolSize(pOpts.VolSize)*helpers.MiB), options) uint64(util.RoundOffVolSize(pOpts.VolSize)*helpers.MiB), options)
if err != nil { if err != nil {
return errors.Wrapf(err, "failed to create rbd image") return errors.Wrapf(err, "failed to create rbd image")
@ -215,18 +219,33 @@ func createImage(ctx context.Context, pOpts *rbdVolume, cr *util.Credentials) er
return nil return nil
} }
func (rv *rbdVolume) openIoctx() error {
if rv.ioctx != nil {
return nil
}
ioctx, err := rv.conn.GetIoctx(rv.Pool)
if err != nil {
// GetIoctx() can return util.ErrPoolNotFound
return err
}
rv.ioctx = ioctx
return nil
}
// open the rbdVolume after it has been connected. // open the rbdVolume after it has been connected.
// ErrPoolNotFound or ErrImageNotFound are returned in case the pool or image // ErrPoolNotFound or ErrImageNotFound are returned in case the pool or image
// can not be found, other errors will contain more details about other issues // can not be found, other errors will contain more details about other issues
// (permission denied, ...) and are expected to relate to configuration issues. // (permission denied, ...) and are expected to relate to configuration issues.
func (rv *rbdVolume) open() (*librbd.Image, error) { func (rv *rbdVolume) open() (*librbd.Image, error) {
ioctx, err := rv.conn.GetIoctx(rv.Pool) err := rv.openIoctx()
if err != nil { if err != nil {
// GetIoctx() can return util.ErrPoolNotFound
return nil, err return nil, err
} }
image, err := librbd.OpenImage(ioctx, rv.RbdImageName, librbd.NoSnapshot) image, err := librbd.OpenImage(rv.ioctx, rv.RbdImageName, librbd.NoSnapshot)
if err != nil { if err != nil {
if err == librbd.ErrNotFound { if err == librbd.ErrNotFound {
err = ErrImageNotFound{rv.RbdImageName, err} err = ErrImageNotFound{rv.RbdImageName, err}