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