From e9461686b87496c5d60e7ce8899865f267c3abc1 Mon Sep 17 00:00:00 2001
From: Pavel Karpy
Date: Thu, 20 Apr 2023 18:51:16 +0300
Subject: [PATCH] [#274] wc: Resolve possible deadlock
If operation with WC are _fast enough_ (e.g. `Init` failed and `Close` is
called immediately) there is a race and a deadlock that do not allow finish
(and start, in fact) an initialization routine because of taken `modeMtx`
and also do not allow finish `Close` call because of awaiting initialization
finish. So do stop initialization _before_ any mutex is taken.
Signed-off-by: Pavel Karpy
---
pkg/local_object_storage/writecache/mode.go | 20 +++++++++----------
.../writecache/writecache.go | 3 ---
2 files changed, 10 insertions(+), 13 deletions(-)
diff --git a/pkg/local_object_storage/writecache/mode.go b/pkg/local_object_storage/writecache/mode.go
index 20b0cce2..14f8af49 100644
--- a/pkg/local_object_storage/writecache/mode.go
+++ b/pkg/local_object_storage/writecache/mode.go
@@ -29,9 +29,6 @@ func (c *cache) SetMode(m mode.Mode) error {
))
defer span.End()
- c.modeMtx.Lock()
- defer c.modeMtx.Unlock()
-
return c.setMode(ctx, m)
}
@@ -40,13 +37,6 @@ func (c *cache) setMode(ctx context.Context, m mode.Mode) error {
var err error
turnOffMeta := m.NoMetabase()
- if turnOffMeta && !c.mode.NoMetabase() {
- err = c.flush(ctx, true)
- if err != nil {
- return err
- }
- }
-
if !c.initialized.Load() {
close(c.stopInitCh)
@@ -60,6 +50,16 @@ func (c *cache) setMode(ctx context.Context, m mode.Mode) error {
}()
}
+ c.modeMtx.Lock()
+ defer c.modeMtx.Unlock()
+
+ if turnOffMeta && !c.mode.NoMetabase() {
+ err = c.flush(ctx, true)
+ if err != nil {
+ return err
+ }
+ }
+
if c.db != nil {
if err = c.db.Close(); err != nil {
return fmt.Errorf("can't close write-cache database: %w", err)
diff --git a/pkg/local_object_storage/writecache/writecache.go b/pkg/local_object_storage/writecache/writecache.go
index 0fc2e601..bdcc9bbf 100644
--- a/pkg/local_object_storage/writecache/writecache.go
+++ b/pkg/local_object_storage/writecache/writecache.go
@@ -163,9 +163,6 @@ func (c *cache) Init() error {
// Close closes db connection and stops services. Executes ObjectCounters.FlushAndClose op.
func (c *cache) Close() error {
- c.modeMtx.Lock()
- defer c.modeMtx.Unlock()
-
// Finish all in-progress operations.
if err := c.setMode(context.TODO(), mode.ReadOnly); err != nil {
return err