mirror of
https://github.com/minio/minio.git
synced 2025-11-06 20:33:07 -05:00
lock: Always cancel the returned Get(R)Lock context (#12162)
* lock: Always cancel the returned Get(R)Lock context There is a leak with cancel created inside the locking mechanism. The cancel purpose was to cancel operations such erasure get/put that are holding non-refreshable locks. This PR will ensure the created context.Cancel is passed to the unlock API so it will cleanup and avoid leaks. * locks: Avoid returning nil cancel in local lockers Since there is no Refresh mechanism in the local locking mechanism, we do not generate a new context or cancel. Currently, a nil cancel function is returned but this can cause a crash. Return a dummy function instead.
This commit is contained in:
@@ -65,12 +65,13 @@ func (er erasureObjects) CopyObject(ctx context.Context, srcBucket, srcObject, d
|
||||
|
||||
defer ObjectPathUpdated(pathJoin(dstBucket, dstObject))
|
||||
if !dstOpts.NoLock {
|
||||
var cancel context.CancelFunc
|
||||
lk := er.NewNSLock(dstBucket, dstObject)
|
||||
ctx, err = lk.GetLock(ctx, globalOperationTimeout)
|
||||
ctx, cancel, err = lk.GetLock(ctx, globalOperationTimeout)
|
||||
if err != nil {
|
||||
return oi, err
|
||||
}
|
||||
defer lk.Unlock()
|
||||
defer lk.Unlock(cancel)
|
||||
}
|
||||
// Read metadata associated with the object from all disks.
|
||||
storageDisks := er.getDisks()
|
||||
@@ -145,20 +146,21 @@ func (er erasureObjects) GetObjectNInfo(ctx context.Context, bucket, object stri
|
||||
|
||||
// Acquire lock
|
||||
if lockType != noLock {
|
||||
var cancel context.CancelFunc
|
||||
lock := er.NewNSLock(bucket, object)
|
||||
switch lockType {
|
||||
case writeLock:
|
||||
ctx, err = lock.GetLock(ctx, globalOperationTimeout)
|
||||
ctx, cancel, err = lock.GetLock(ctx, globalOperationTimeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nsUnlocker = lock.Unlock
|
||||
nsUnlocker = func() { lock.Unlock(cancel) }
|
||||
case readLock:
|
||||
ctx, err = lock.GetRLock(ctx, globalOperationTimeout)
|
||||
ctx, cancel, err = lock.GetRLock(ctx, globalOperationTimeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nsUnlocker = lock.RUnlock
|
||||
nsUnlocker = func() { lock.RUnlock(cancel) }
|
||||
}
|
||||
unlockOnDefer = true
|
||||
}
|
||||
@@ -213,11 +215,11 @@ func (er erasureObjects) GetObjectNInfo(ctx context.Context, bucket, object stri
|
||||
func (er erasureObjects) GetObject(ctx context.Context, bucket, object string, startOffset int64, length int64, writer io.Writer, etag string, opts ObjectOptions) (err error) {
|
||||
// Lock the object before reading.
|
||||
lk := er.NewNSLock(bucket, object)
|
||||
ctx, err = lk.GetRLock(ctx, globalOperationTimeout)
|
||||
ctx, cancel, err := lk.GetRLock(ctx, globalOperationTimeout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer lk.RUnlock()
|
||||
defer lk.RUnlock(cancel)
|
||||
|
||||
// Start offset cannot be negative.
|
||||
if startOffset < 0 {
|
||||
@@ -376,13 +378,14 @@ func (er erasureObjects) getObject(ctx context.Context, bucket, object string, s
|
||||
// GetObjectInfo - reads object metadata and replies back ObjectInfo.
|
||||
func (er erasureObjects) GetObjectInfo(ctx context.Context, bucket, object string, opts ObjectOptions) (info ObjectInfo, err error) {
|
||||
if !opts.NoLock {
|
||||
var cancel context.CancelFunc
|
||||
// Lock the object before reading.
|
||||
lk := er.NewNSLock(bucket, object)
|
||||
ctx, err = lk.GetRLock(ctx, globalOperationTimeout)
|
||||
ctx, cancel, err = lk.GetRLock(ctx, globalOperationTimeout)
|
||||
if err != nil {
|
||||
return ObjectInfo{}, err
|
||||
}
|
||||
defer lk.RUnlock()
|
||||
defer lk.RUnlock(cancel)
|
||||
}
|
||||
|
||||
return er.getObjectInfo(ctx, bucket, object, opts)
|
||||
@@ -732,12 +735,13 @@ func (er erasureObjects) putObject(ctx context.Context, bucket string, object st
|
||||
|
||||
if !opts.NoLock {
|
||||
var err error
|
||||
var cancel context.CancelFunc
|
||||
lk := er.NewNSLock(bucket, object)
|
||||
ctx, err = lk.GetLock(ctx, globalOperationTimeout)
|
||||
ctx, cancel, err = lk.GetLock(ctx, globalOperationTimeout)
|
||||
if err != nil {
|
||||
return ObjectInfo{}, err
|
||||
}
|
||||
defer lk.Unlock()
|
||||
defer lk.Unlock(cancel)
|
||||
}
|
||||
|
||||
for i, w := range writers {
|
||||
@@ -1043,11 +1047,11 @@ func (er erasureObjects) DeleteObject(ctx context.Context, bucket, object string
|
||||
}
|
||||
// Acquire a write lock before deleting the object.
|
||||
lk := er.NewNSLock(bucket, object)
|
||||
ctx, err = lk.GetLock(ctx, globalDeleteOperationTimeout)
|
||||
ctx, cancel, err := lk.GetLock(ctx, globalDeleteOperationTimeout)
|
||||
if err != nil {
|
||||
return ObjectInfo{}, err
|
||||
}
|
||||
defer lk.Unlock()
|
||||
defer lk.Unlock(cancel)
|
||||
|
||||
storageDisks := er.getDisks()
|
||||
writeQuorum := len(storageDisks)/2 + 1
|
||||
@@ -1154,14 +1158,13 @@ func (er erasureObjects) addPartial(bucket, object, versionID string) {
|
||||
}
|
||||
|
||||
func (er erasureObjects) PutObjectMetadata(ctx context.Context, bucket, object string, opts ObjectOptions) (ObjectInfo, error) {
|
||||
var err error
|
||||
// Lock the object before updating tags.
|
||||
lk := er.NewNSLock(bucket, object)
|
||||
ctx, err = lk.GetLock(ctx, globalOperationTimeout)
|
||||
ctx, cancel, err := lk.GetLock(ctx, globalOperationTimeout)
|
||||
if err != nil {
|
||||
return ObjectInfo{}, err
|
||||
}
|
||||
defer lk.Unlock()
|
||||
defer lk.Unlock(cancel)
|
||||
|
||||
disks := er.getDisks()
|
||||
|
||||
@@ -1205,14 +1208,13 @@ func (er erasureObjects) PutObjectMetadata(ctx context.Context, bucket, object s
|
||||
|
||||
// PutObjectTags - replace or add tags to an existing object
|
||||
func (er erasureObjects) PutObjectTags(ctx context.Context, bucket, object string, tags string, opts ObjectOptions) (ObjectInfo, error) {
|
||||
var err error
|
||||
// Lock the object before updating tags.
|
||||
lk := er.NewNSLock(bucket, object)
|
||||
ctx, err = lk.GetLock(ctx, globalOperationTimeout)
|
||||
ctx, cancel, err := lk.GetLock(ctx, globalOperationTimeout)
|
||||
if err != nil {
|
||||
return ObjectInfo{}, err
|
||||
}
|
||||
defer lk.Unlock()
|
||||
defer lk.Unlock(cancel)
|
||||
|
||||
disks := er.getDisks()
|
||||
|
||||
@@ -1302,11 +1304,11 @@ func (er erasureObjects) TransitionObject(ctx context.Context, bucket, object st
|
||||
}
|
||||
// Acquire write lock before starting to transition the object.
|
||||
lk := er.NewNSLock(bucket, object)
|
||||
ctx, err = lk.GetLock(ctx, globalDeleteOperationTimeout)
|
||||
ctx, cancel, err := lk.GetLock(ctx, globalDeleteOperationTimeout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer lk.Unlock()
|
||||
defer lk.Unlock(cancel)
|
||||
|
||||
fi, metaArr, onlineDisks, err := er.getObjectFileInfo(ctx, bucket, object, opts, true)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user