endpoint: fix incorrect early release of maxConcurrentZFSSendSemaphore

fixes #274
This commit is contained in:
Christian Schwarz 2020-02-17 22:53:49 +01:00
parent 0eb7032735
commit b8abba6f55
2 changed files with 24 additions and 3 deletions

View File

@ -198,7 +198,11 @@ func (s *Sender) Send(ctx context.Context, r *pdu.SendReq) (*pdu.SendRes, zfs.St
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
defer guard.Release() defer func(guardp **semaphore.AcquireGuard) {
if *guardp != nil {
(*guardp).Release()
}
}(&guard)
si, err := zfs.ZFSSendDry(ctx, sendArgs) si, err := zfs.ZFSSendDry(ctx, sendArgs)
if err != nil { if err != nil {
@ -255,6 +259,13 @@ func (s *Sender) Send(ctx context.Context, r *pdu.SendReq) (*pdu.SendRes, zfs.St
if err != nil { if err != nil {
return nil, nil, errors.Wrap(err, "zfs send failed") return nil, nil, errors.Wrap(err, "zfs send failed")
} }
// defer releasing guard until streamCopier is closed
streamCopier.SetPostCloseCallback(func(_ error) {
guard.Release()
})
guard = nil
return res, streamCopier, nil return res, streamCopier, nil
} }

View File

@ -351,6 +351,7 @@ func (a ZFSSendArgs) buildCommonSendArgs() ([]string, error) {
type ReadCloserCopier struct { type ReadCloserCopier struct {
recorder readErrRecorder recorder readErrRecorder
postCloseCallback func(closeErr error)
} }
type readErrRecorder struct { type readErrRecorder struct {
@ -402,8 +403,17 @@ func (c *ReadCloserCopier) Read(p []byte) (n int, err error) {
return c.recorder.Read(p) return c.recorder.Read(p)
} }
// caller must ensure that this function is not executing concurrently to Close
func (c *ReadCloserCopier) SetPostCloseCallback(callback func(closeErr error)) {
c.postCloseCallback = callback
}
func (c *ReadCloserCopier) Close() error { func (c *ReadCloserCopier) Close() error {
return c.recorder.ReadCloser.Close() err := c.recorder.Close()
if c.postCloseCallback != nil {
c.postCloseCallback(err)
}
return err
} }
func pipeWithCapacityHint(capacity int) (r, w *os.File, err error) { func pipeWithCapacityHint(capacity int) (r, w *os.File, err error) {