mirror of
https://github.com/restic/restic.git
synced 2024-12-23 08:16:36 +00:00
Fix data race in blob_saver
After the `BlobSaver` job is submitted, the buffer can be released and reused by another `FileSaver` even before `BlobSaver.Save` returns. That FileSaver will the change `buf.Data` leading to wrong backup statistics. Found by `go test -race ./...`: WARNING: DATA RACE Write at 0x00c0000784a0 by goroutine 41: github.com/restic/restic/internal/archiver.(*FileSaver).saveFile() /home/michael/Projekte/restic/restic/internal/archiver/file_saver.go:176 +0x789 github.com/restic/restic/internal/archiver.(*FileSaver).worker() /home/michael/Projekte/restic/restic/internal/archiver/file_saver.go:242 +0x2af github.com/restic/restic/internal/archiver.NewFileSaver.func2() /home/michael/Projekte/restic/restic/internal/archiver/file_saver.go:88 +0x5d golang.org/x/sync/errgroup.(*Group).Go.func1() /home/michael/go/pkg/mod/golang.org/x/sync@v0.0.0-20210220032951-036812b2e83c/errgroup/errgroup.go:57 +0x91 Previous read at 0x00c0000784a0 by goroutine 29: github.com/restic/restic/internal/archiver.(*BlobSaver).Save() /home/michael/Projekte/restic/restic/internal/archiver/blob_saver.go:57 +0x1dd github.com/restic/restic/internal/archiver.(*BlobSaver).Save-fm() <autogenerated>:1 +0xac github.com/restic/restic/internal/archiver.(*FileSaver).saveFile() /home/michael/Projekte/restic/restic/internal/archiver/file_saver.go:191 +0x855 github.com/restic/restic/internal/archiver.(*FileSaver).worker() /home/michael/Projekte/restic/restic/internal/archiver/file_saver.go:242 +0x2af github.com/restic/restic/internal/archiver.NewFileSaver.func2() /home/michael/Projekte/restic/restic/internal/archiver/file_saver.go:88 +0x5d golang.org/x/sync/errgroup.(*Group).Go.func1() /home/michael/go/pkg/mod/golang.org/x/sync@v0.0.0-20210220032951-036812b2e83c/errgroup/errgroup.go:57 +0x91
This commit is contained in:
parent
b6a38d43b3
commit
ce89018902
1 changed files with 3 additions and 1 deletions
|
@ -45,6 +45,8 @@ func (s *BlobSaver) TriggerShutdown() {
|
||||||
// Save stores a blob in the repo. It checks the index and the known blobs
|
// Save stores a blob in the repo. It checks the index and the known blobs
|
||||||
// before saving anything. It takes ownership of the buffer passed in.
|
// before saving anything. It takes ownership of the buffer passed in.
|
||||||
func (s *BlobSaver) Save(ctx context.Context, t restic.BlobType, buf *Buffer) FutureBlob {
|
func (s *BlobSaver) Save(ctx context.Context, t restic.BlobType, buf *Buffer) FutureBlob {
|
||||||
|
// buf might be freed once the job was submitted, thus calculate the length now
|
||||||
|
length := len(buf.Data)
|
||||||
ch := make(chan saveBlobResponse, 1)
|
ch := make(chan saveBlobResponse, 1)
|
||||||
select {
|
select {
|
||||||
case s.ch <- saveBlobJob{BlobType: t, buf: buf, ch: ch}:
|
case s.ch <- saveBlobJob{BlobType: t, buf: buf, ch: ch}:
|
||||||
|
@ -54,7 +56,7 @@ func (s *BlobSaver) Save(ctx context.Context, t restic.BlobType, buf *Buffer) Fu
|
||||||
return FutureBlob{ch: ch}
|
return FutureBlob{ch: ch}
|
||||||
}
|
}
|
||||||
|
|
||||||
return FutureBlob{ch: ch, length: len(buf.Data)}
|
return FutureBlob{ch: ch, length: length}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FutureBlob is returned by SaveBlob and will return the data once it has been processed.
|
// FutureBlob is returned by SaveBlob and will return the data once it has been processed.
|
||||||
|
|
Loading…
Reference in a new issue