mirror of
https://github.com/minio/minio.git
synced 2025-04-06 12:50:34 -04:00
Fix deadlock in in-place CopyObject decryption/encryption (#5637)
In-place decryption/encryption already holds write locks on them, attempting to acquire a read lock would fail.
This commit is contained in:
parent
574b667c56
commit
29ef7d29e4
@ -12,7 +12,7 @@ clone_folder: c:\gopath\src\github.com\minio\minio
|
|||||||
# Environment variables
|
# Environment variables
|
||||||
environment:
|
environment:
|
||||||
GOPATH: c:\gopath
|
GOPATH: c:\gopath
|
||||||
GOROOT: c:\go
|
GOROOT: c:\go19
|
||||||
|
|
||||||
# scripts that run after cloning repository
|
# scripts that run after cloning repository
|
||||||
install:
|
install:
|
||||||
|
63
cmd/fs-v1.go
63
cmd/fs-v1.go
@ -388,6 +388,9 @@ func (fs *FSObjects) CopyObject(srcBucket, srcObject, dstBucket, dstObject strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
if cpSrcDstSame && srcInfo.metadataOnly {
|
if cpSrcDstSame && srcInfo.metadataOnly {
|
||||||
|
// Close any writer which was initialized.
|
||||||
|
defer srcInfo.Writer.Close()
|
||||||
|
|
||||||
fsMetaPath := pathJoin(fs.fsPath, minioMetaBucket, bucketMetaPrefix, srcBucket, srcObject, fsMetaJSONFile)
|
fsMetaPath := pathJoin(fs.fsPath, minioMetaBucket, bucketMetaPrefix, srcBucket, srcObject, fsMetaJSONFile)
|
||||||
wlk, err := fs.rwPool.Write(fsMetaPath)
|
wlk, err := fs.rwPool.Write(fsMetaPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -494,7 +497,7 @@ func (fs *FSObjects) getObject(bucket, object string, offset int64, length int64
|
|||||||
}
|
}
|
||||||
|
|
||||||
if etag != "" {
|
if etag != "" {
|
||||||
objEtag, perr := fs.getObjectETag(bucket, object)
|
objEtag, perr := fs.getObjectETag(bucket, object, lock)
|
||||||
if perr != nil {
|
if perr != nil {
|
||||||
return toObjectErr(errors.Trace(perr), bucket, object)
|
return toObjectErr(errors.Trace(perr), bucket, object)
|
||||||
}
|
}
|
||||||
@ -828,43 +831,55 @@ func (fs *FSObjects) listDirFactory(isLeaf isLeafFunc) listDirFunc {
|
|||||||
|
|
||||||
// getObjectETag is a helper function, which returns only the md5sum
|
// getObjectETag is a helper function, which returns only the md5sum
|
||||||
// of the file on the disk.
|
// of the file on the disk.
|
||||||
func (fs *FSObjects) getObjectETag(bucket, entry string) (string, error) {
|
func (fs *FSObjects) getObjectETag(bucket, entry string, lock bool) (string, error) {
|
||||||
fsMetaPath := pathJoin(fs.fsPath, minioMetaBucket, bucketMetaPrefix, bucket, entry, fsMetaJSONFile)
|
fsMetaPath := pathJoin(fs.fsPath, minioMetaBucket, bucketMetaPrefix, bucket, entry, fsMetaJSONFile)
|
||||||
|
|
||||||
// Read `fs.json` to perhaps contend with
|
var reader io.Reader
|
||||||
// parallel Put() operations.
|
var fi os.FileInfo
|
||||||
rlk, err := fs.rwPool.Open(fsMetaPath)
|
var size int64
|
||||||
// Ignore if `fs.json` is not available, this is true for pre-existing data.
|
if lock {
|
||||||
if err != nil && err != errFileNotFound {
|
// Read `fs.json` to perhaps contend with
|
||||||
return "", toObjectErr(errors.Trace(err), bucket, entry)
|
// parallel Put() operations.
|
||||||
}
|
rlk, err := fs.rwPool.Open(fsMetaPath)
|
||||||
|
// Ignore if `fs.json` is not available, this is true for pre-existing data.
|
||||||
|
if err != nil && err != errFileNotFound {
|
||||||
|
return "", toObjectErr(errors.Trace(err), bucket, entry)
|
||||||
|
}
|
||||||
|
|
||||||
// If file is not found, we don't need to proceed forward.
|
// If file is not found, we don't need to proceed forward.
|
||||||
if err == errFileNotFound {
|
if err == errFileNotFound {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read from fs metadata only if it exists.
|
// Read from fs metadata only if it exists.
|
||||||
defer fs.rwPool.Close(fsMetaPath)
|
defer fs.rwPool.Close(fsMetaPath)
|
||||||
|
|
||||||
// Fetch the size of the underlying file.
|
// Fetch the size of the underlying file.
|
||||||
fi, err := rlk.LockedFile.Stat()
|
fi, err = rlk.LockedFile.Stat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", toObjectErr(errors.Trace(err), bucket, entry)
|
return "", toObjectErr(errors.Trace(err), bucket, entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
size = fi.Size()
|
||||||
|
reader = io.NewSectionReader(rlk.LockedFile, 0, fi.Size())
|
||||||
|
} else {
|
||||||
|
var err error
|
||||||
|
reader, size, err = fsOpenFile(fsMetaPath, 0)
|
||||||
|
if err != nil {
|
||||||
|
return "", toObjectErr(errors.Trace(err), bucket, entry)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// `fs.json` can be empty due to previously failed
|
// `fs.json` can be empty due to previously failed
|
||||||
// PutObject() transaction, if we arrive at such
|
// PutObject() transaction, if we arrive at such
|
||||||
// a situation we just ignore and continue.
|
// a situation we just ignore and continue.
|
||||||
if fi.Size() == 0 {
|
if size == 0 {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrap the locked file in a ReadAt() backend section reader to
|
fsMetaBuf, err := ioutil.ReadAll(reader)
|
||||||
// make sure the underlying offsets don't move.
|
|
||||||
fsMetaBuf, err := ioutil.ReadAll(io.NewSectionReader(rlk.LockedFile, 0, fi.Size()))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.Trace(err)
|
return "", toObjectErr(errors.Trace(err), bucket, entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if FS metadata is valid, if not return error.
|
// Check if FS metadata is valid, if not return error.
|
||||||
|
@ -402,7 +402,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
|
|||||||
if sseC {
|
if sseC {
|
||||||
newKey, err = ParseSSECustomerRequest(r)
|
newKey, err = ParseSSECustomerRequest(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pipeReader.CloseWithError(err)
|
pipeWriter.CloseWithError(err)
|
||||||
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -426,6 +426,9 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
|
|||||||
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Since we are rotating the keys, make sure to update the metadata.
|
||||||
|
srcInfo.metadataOnly = true
|
||||||
} else {
|
} else {
|
||||||
if sseCopyC {
|
if sseCopyC {
|
||||||
// Source is encrypted make sure to save the encrypted size.
|
// Source is encrypted make sure to save the encrypted size.
|
||||||
@ -500,6 +503,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
|
|||||||
// object is same then only metadata is updated.
|
// object is same then only metadata is updated.
|
||||||
objInfo, err := objectAPI.CopyObject(srcBucket, srcObject, dstBucket, dstObject, srcInfo)
|
objInfo, err := objectAPI.CopyObject(srcBucket, srcObject, dstBucket, dstObject, srcInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
pipeWriter.CloseWithError(err)
|
||||||
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user