util: use ClusterConnection.Copy() for re-using connections

Connections are reference counted, so just assigning the connection to
an other object for re-use is not correct. This can cause connections to
be garbage collected while something else is still using it.

Signed-off-by: Niels de Vos <ndevos@redhat.com>
This commit is contained in:
Niels de Vos 2021-03-15 10:50:09 +01:00 committed by mergify[bot]
parent 6e941539b5
commit 5c26fbb0d7
4 changed files with 35 additions and 3 deletions

View File

@ -127,7 +127,7 @@ func (rv *rbdVolume) checkCloneImage(ctx context.Context, parentVol *rbdVolume)
func (rv *rbdVolume) generateTempClone() *rbdVolume {
tempClone := rbdVolume{}
tempClone.conn = rv.conn
tempClone.conn = rv.conn.Copy()
// The temp clone image need to have deep flatten feature
f := []string{librbd.FeatureNameLayering, librbd.FeatureNameDeepFlatten}
tempClone.imageFeatureSet = librbd.FeatureSetFromNames(f)

View File

@ -496,7 +496,7 @@ func (rv *rbdVolume) getCloneDepth(ctx context.Context) (uint, error) {
vol.Pool = rv.Pool
vol.Monitors = rv.Monitors
vol.RbdImageName = rv.RbdImageName
vol.conn = rv.conn
vol.conn = rv.conn.Copy()
err := vol.openIoctx()
if err != nil {
@ -666,7 +666,7 @@ func (rv *rbdVolume) checkImageChainHasFeature(ctx context.Context, feature uint
vol.RadosNamespace = rv.RadosNamespace
vol.Monitors = rv.Monitors
vol.RbdImageName = rv.RbdImageName
vol.conn = rv.conn
vol.conn = rv.conn.Copy()
err := vol.openIoctx()
if err != nil {

View File

@ -168,6 +168,22 @@ func (cp *ConnPool) Get(monitors, user, keyfile string) (*rados.Conn, error) {
return conn, nil
}
// Copy adds an extra reference count to the used ConnEntry and returns the
// *rados.Conn if it was found.
func (cp *ConnPool) Copy(conn *rados.Conn) *rados.Conn {
cp.lock.Lock()
defer cp.lock.Unlock()
for _, ce := range cp.conns {
if ce.conn == conn {
ce.get()
return ce.conn
}
}
return nil
}
// Put reduces the reference count of the rados.Conn object that was returned with
// ConnPool.Get().
func (cp *ConnPool) Put(conn *rados.Conn) {

View File

@ -68,6 +68,22 @@ func (cc *ClusterConnection) Destroy() {
}
}
// Copy creates a copy of the ClusterConnection. This is needed when an other
// object needs to use the existing connection.
// It is required to call Destroy() once the (copied) connection is not used
// anymore.
func (cc *ClusterConnection) Copy() *ClusterConnection {
if cc.conn == nil {
return nil
}
c := ClusterConnection{}
c.discardOnZeroedWriteSameDisabled = cc.discardOnZeroedWriteSameDisabled
c.conn = connPool.Copy(cc.conn)
return &c
}
func (cc *ClusterConnection) GetIoctx(pool string) (*rados.IOContext, error) {
if cc.conn == nil {
return nil, errors.New("cluster is not connected yet")