b51a1f
From 5946a6ec18976c0f52162fe0f47e9b5171af87ec Mon Sep 17 00:00:00 2001
b51a1f
From: Soumya Koduri <skoduri@redhat.com>
b51a1f
Date: Mon, 6 Apr 2020 12:36:44 +0530
b51a1f
Subject: [PATCH 503/511] gfapi: Suspend synctasks instead of blocking them
b51a1f
b51a1f
There are certain conditions which blocks the current
b51a1f
execution thread (like waiting on mutex lock or condition
b51a1f
variable or I/O response). In such cases, if it is a
b51a1f
synctask thread, we should suspend the task instead
b51a1f
of blocking it (like done in SYNCOP using synctask_yield)
b51a1f
b51a1f
This is to avoid deadlock like the one mentioned below -
b51a1f
b51a1f
1) synctaskA sets fs->migration_in_progress to 1 and
b51a1f
   does I/O (LOOKUP)
b51a1f
2) Other synctask threads wait for fs->migration_in_progress
b51a1f
  to be reset to 0 by synctaskA and hence blocked
b51a1f
3) but synctaskA cannot resume as all synctask threads are blocked
b51a1f
   on (2).
b51a1f
b51a1f
Note: this same approach is already used by few other components
b51a1f
like syncbarrier etc.
b51a1f
b51a1f
>Change-Id: If90f870d663bb242c702a5b86ac52eeda67c6f0d
b51a1f
>Fixes: #1146
b51a1f
>Signed-off-by: Soumya Koduri <skoduri@redhat.com>
b51a1f
Upstream patch: https://review.gluster.org/c/glusterfs/+/24276
b51a1f
b51a1f
BUG: 1779238
b51a1f
Change-Id: If90f870d663bb242c702a5b86ac52eeda67c6f0d
b51a1f
Signed-off-by: nik-redhat <nladha@redhat.com>
b51a1f
Reviewed-on: https://code.engineering.redhat.com/gerrit/221081
b51a1f
Tested-by: RHGS Build Bot <nigelb@redhat.com>
b51a1f
Reviewed-by: Soumya Koduri <skoduri@redhat.com>
b51a1f
---
b51a1f
 api/src/glfs-internal.h | 34 ++++++++++++++++++++++++++++++++--
b51a1f
 api/src/glfs-resolve.c  |  9 +++++++++
b51a1f
 api/src/glfs.c          |  9 +++++++++
b51a1f
 3 files changed, 50 insertions(+), 2 deletions(-)
b51a1f
b51a1f
diff --git a/api/src/glfs-internal.h b/api/src/glfs-internal.h
b51a1f
index 55401b2..15cf0ee 100644
b51a1f
--- a/api/src/glfs-internal.h
b51a1f
+++ b/api/src/glfs-internal.h
b51a1f
@@ -16,6 +16,7 @@
b51a1f
 #include <glusterfs/upcall-utils.h>
b51a1f
 #include "glfs-handles.h"
b51a1f
 #include <glusterfs/refcount.h>
b51a1f
+#include <glusterfs/syncop.h>
b51a1f
 
b51a1f
 #define GLFS_SYMLINK_MAX_FOLLOW 2048
b51a1f
 
b51a1f
@@ -207,6 +208,7 @@ struct glfs {
b51a1f
     glfs_upcall_cbk up_cbk; /* upcall cbk function to be registered */
b51a1f
     void *up_data;          /* Opaque data provided by application
b51a1f
                              * during upcall registration */
b51a1f
+    struct list_head waitq; /* waiting synctasks */
b51a1f
 };
b51a1f
 
b51a1f
 /* This enum is used to maintain the state of glfd. In case of async fops
b51a1f
@@ -442,6 +444,34 @@ glfs_process_upcall_event(struct glfs *fs, void *data)
b51a1f
         THIS = glfd->fd->inode->table->xl->ctx->master;                        \
b51a1f
     } while (0)
b51a1f
 
b51a1f
+#define __GLFS_LOCK_WAIT(fs)                                                   \
b51a1f
+    do {                                                                       \
b51a1f
+        struct synctask *task = NULL;                                          \
b51a1f
+                                                                               \
b51a1f
+        task = synctask_get();                                                 \
b51a1f
+                                                                               \
b51a1f
+        if (task) {                                                            \
b51a1f
+            list_add_tail(&task->waitq, &fs->waitq);                           \
b51a1f
+            pthread_mutex_unlock(&fs->mutex);                                  \
b51a1f
+            synctask_yield(task, NULL);                                              \
b51a1f
+            pthread_mutex_lock(&fs->mutex);                                    \
b51a1f
+        } else {                                                               \
b51a1f
+            /* non-synctask */                                                 \
b51a1f
+            pthread_cond_wait(&fs->cond, &fs->mutex);                          \
b51a1f
+        }                                                                      \
b51a1f
+    } while (0)
b51a1f
+
b51a1f
+#define __GLFS_SYNCTASK_WAKE(fs)                                               \
b51a1f
+    do {                                                                       \
b51a1f
+        struct synctask *waittask = NULL;                                      \
b51a1f
+                                                                               \
b51a1f
+        while (!list_empty(&fs->waitq)) {                                      \
b51a1f
+            waittask = list_entry(fs->waitq.next, struct synctask, waitq);     \
b51a1f
+            list_del_init(&waittask->waitq);                                   \
b51a1f
+            synctask_wake(waittask);                                           \
b51a1f
+        }                                                                      \
b51a1f
+    } while (0)
b51a1f
+
b51a1f
 /*
b51a1f
   By default all lock attempts from user context must
b51a1f
   use glfs_lock() and glfs_unlock(). This allows
b51a1f
@@ -466,10 +496,10 @@ glfs_lock(struct glfs *fs, gf_boolean_t wait_for_migration)
b51a1f
     pthread_mutex_lock(&fs->mutex);
b51a1f
 
b51a1f
     while (!fs->init)
b51a1f
-        pthread_cond_wait(&fs->cond, &fs->mutex);
b51a1f
+        __GLFS_LOCK_WAIT(fs);
b51a1f
 
b51a1f
     while (wait_for_migration && fs->migration_in_progress)
b51a1f
-        pthread_cond_wait(&fs->cond, &fs->mutex);
b51a1f
+        __GLFS_LOCK_WAIT(fs);
b51a1f
 
b51a1f
     return 0;
b51a1f
 }
b51a1f
diff --git a/api/src/glfs-resolve.c b/api/src/glfs-resolve.c
b51a1f
index 062b7dc..58b6ace 100644
b51a1f
--- a/api/src/glfs-resolve.c
b51a1f
+++ b/api/src/glfs-resolve.c
b51a1f
@@ -65,6 +65,9 @@ __glfs_first_lookup(struct glfs *fs, xlator_t *subvol)
b51a1f
     fs->migration_in_progress = 0;
b51a1f
     pthread_cond_broadcast(&fs->cond);
b51a1f
 
b51a1f
+    /* wake up other waiting tasks */
b51a1f
+    __GLFS_SYNCTASK_WAKE(fs);
b51a1f
+
b51a1f
     return ret;
b51a1f
 }
b51a1f
 
b51a1f
@@ -154,6 +157,9 @@ __glfs_refresh_inode(struct glfs *fs, xlator_t *subvol, inode_t *inode,
b51a1f
     fs->migration_in_progress = 0;
b51a1f
     pthread_cond_broadcast(&fs->cond);
b51a1f
 
b51a1f
+    /* wake up other waiting tasks */
b51a1f
+    __GLFS_SYNCTASK_WAKE(fs);
b51a1f
+
b51a1f
     return newinode;
b51a1f
 }
b51a1f
 
b51a1f
@@ -841,6 +847,9 @@ __glfs_migrate_fd(struct glfs *fs, xlator_t *newsubvol, struct glfs_fd *glfd)
b51a1f
     fs->migration_in_progress = 0;
b51a1f
     pthread_cond_broadcast(&fs->cond);
b51a1f
 
b51a1f
+    /* wake up other waiting tasks */
b51a1f
+    __GLFS_SYNCTASK_WAKE(fs);
b51a1f
+
b51a1f
     return newfd;
b51a1f
 }
b51a1f
 
b51a1f
diff --git a/api/src/glfs.c b/api/src/glfs.c
b51a1f
index f36616d..ae994fa 100644
b51a1f
--- a/api/src/glfs.c
b51a1f
+++ b/api/src/glfs.c
b51a1f
@@ -740,6 +740,7 @@ glfs_new_fs(const char *volname)
b51a1f
 
b51a1f
     INIT_LIST_HEAD(&fs->openfds);
b51a1f
     INIT_LIST_HEAD(&fs->upcall_list);
b51a1f
+    INIT_LIST_HEAD(&fs->waitq);
b51a1f
 
b51a1f
     PTHREAD_MUTEX_INIT(&fs->mutex, NULL, fs->pthread_flags, GLFS_INIT_MUTEX,
b51a1f
                        err);
b51a1f
@@ -1228,6 +1229,7 @@ pub_glfs_fini(struct glfs *fs)
b51a1f
     call_pool_t *call_pool = NULL;
b51a1f
     int fs_init = 0;
b51a1f
     int err = -1;
b51a1f
+    struct synctask *waittask = NULL;
b51a1f
 
b51a1f
     DECLARE_OLD_THIS;
b51a1f
 
b51a1f
@@ -1249,6 +1251,13 @@ pub_glfs_fini(struct glfs *fs)
b51a1f
 
b51a1f
     call_pool = fs->ctx->pool;
b51a1f
 
b51a1f
+    /* Wake up any suspended synctasks */
b51a1f
+    while (!list_empty(&fs->waitq)) {
b51a1f
+        waittask = list_entry(fs->waitq.next, struct synctask, waitq);
b51a1f
+        list_del_init(&waittask->waitq);
b51a1f
+        synctask_wake(waittask);
b51a1f
+    }
b51a1f
+
b51a1f
     while (countdown--) {
b51a1f
         /* give some time for background frames to finish */
b51a1f
         pthread_mutex_lock(&fs->mutex);
b51a1f
-- 
b51a1f
1.8.3.1
b51a1f