summaryrefslogtreecommitdiff
path: root/support/misc
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@hammerspace.com>2019-05-29 09:43:32 -0400
committerSteve Dickson <steved@redhat.com>2019-06-10 09:50:37 -0400
commit09b0a365d7ce094817159066b2fd1925e99d3ab7 (patch)
tree54b4883d59be59e84c5ad93515620a8d5bcbaa86 /support/misc
parent5fc3bac9e0c30e966cf7d8869b3f1b7ae9b91a08 (diff)
downloadnfs-utils-09b0a365d7ce094817159066b2fd1925e99d3ab7.tar.gz
Add a simple workqueue mechanism
Add a simple workqueue mechanism to allow us to run threads that are subject to chroot(), and have them operate on the knfsd kernel daemon. Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> Signed-off-by: Steve Dickson <steved@redhat.com>
Diffstat (limited to 'support/misc')
-rw-r--r--support/misc/Makefile.am2
-rw-r--r--support/misc/workqueue.c228
2 files changed, 229 insertions, 1 deletions
diff --git a/support/misc/Makefile.am b/support/misc/Makefile.am
index 8936b0d..d0bff8f 100644
--- a/support/misc/Makefile.am
+++ b/support/misc/Makefile.am
@@ -1,6 +1,6 @@
## Process this file with automake to produce Makefile.in
noinst_LIBRARIES = libmisc.a
-libmisc_a_SOURCES = tcpwrapper.c from_local.c mountpoint.c file.c
+libmisc_a_SOURCES = tcpwrapper.c from_local.c mountpoint.c file.c workqueue.c
MAINTAINERCLEANFILES = Makefile.in
diff --git a/support/misc/workqueue.c b/support/misc/workqueue.c
new file mode 100644
index 0000000..b8d0344
--- /dev/null
+++ b/support/misc/workqueue.c
@@ -0,0 +1,228 @@
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "workqueue.h"
+#include "xlog.h"
+
+#if defined(HAVE_SCHED_H) && defined(HAVE_LIBPTHREAD) && defined(HAVE_UNSHARE)
+#include <sched.h>
+#include <pthread.h>
+
+struct xwork_struct {
+ struct xwork_struct *next;
+ void (*fn)(void *);
+ void *data;
+};
+
+struct xwork_queue {
+ struct xwork_struct *head;
+ struct xwork_struct **tail;
+
+ unsigned char shutdown : 1;
+};
+
+static void xwork_queue_init(struct xwork_queue *queue)
+{
+ queue->head = NULL;
+ queue->tail = &queue->head;
+ queue->shutdown = 0;
+}
+
+static void xwork_enqueue(struct xwork_queue *queue,
+ struct xwork_struct *entry)
+{
+ entry->next = NULL;
+ *queue->tail = entry;
+ queue->tail = &entry->next;
+}
+
+static struct xwork_struct *xwork_dequeue(struct xwork_queue *queue)
+{
+ struct xwork_struct *entry = NULL;
+ if (queue->head) {
+ entry = queue->head;
+ queue->head = entry->next;
+ if (!queue->head)
+ queue->tail = &queue->head;
+ }
+ return entry;
+}
+
+struct xthread_work {
+ struct xwork_struct work;
+
+ pthread_cond_t cond;
+};
+
+struct xthread_workqueue {
+ struct xwork_queue queue;
+
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+};
+
+static void xthread_workqueue_init(struct xthread_workqueue *wq)
+{
+ xwork_queue_init(&wq->queue);
+ pthread_mutex_init(&wq->mutex, NULL);
+ pthread_cond_init(&wq->cond, NULL);
+}
+
+static void xthread_workqueue_fini(struct xthread_workqueue *wq)
+{
+ pthread_cond_destroy(&wq->cond);
+ pthread_mutex_destroy(&wq->mutex);
+}
+
+static int xthread_work_enqueue(struct xthread_workqueue *wq,
+ struct xthread_work *work)
+{
+ xwork_enqueue(&wq->queue, &work->work);
+ pthread_cond_signal(&wq->cond);
+ return 0;
+}
+
+static struct xthread_work *xthread_work_dequeue(struct xthread_workqueue *wq)
+{
+ return (struct xthread_work *)xwork_dequeue(&wq->queue);
+}
+
+static void xthread_workqueue_do_work(struct xthread_workqueue *wq)
+{
+ struct xthread_work *work;
+
+ pthread_mutex_lock(&wq->mutex);
+ /* Signal the caller that we're up and running */
+ pthread_cond_signal(&wq->cond);
+ for (;;) {
+ work = xthread_work_dequeue(wq);
+ if (work) {
+ work->work.fn(work->work.data);
+ pthread_cond_signal(&work->cond);
+ continue;
+ }
+ if (wq->queue.shutdown)
+ break;
+ pthread_cond_wait(&wq->cond, &wq->mutex);
+ }
+ pthread_mutex_unlock(&wq->mutex);
+}
+
+void xthread_workqueue_shutdown(struct xthread_workqueue *wq)
+{
+ pthread_mutex_lock(&wq->mutex);
+ wq->queue.shutdown = 1;
+ pthread_cond_signal(&wq->cond);
+ pthread_mutex_unlock(&wq->mutex);
+}
+
+static void xthread_workqueue_free(struct xthread_workqueue *wq)
+{
+ xthread_workqueue_fini(wq);
+ free(wq);
+}
+
+static void xthread_workqueue_cleanup(void *data)
+{
+ xthread_workqueue_free(data);
+}
+
+static void *xthread_workqueue_worker(void *data)
+{
+ pthread_cleanup_push(xthread_workqueue_cleanup, data);
+ xthread_workqueue_do_work(data);
+ pthread_cleanup_pop(1);
+ return NULL;
+}
+
+struct xthread_workqueue *xthread_workqueue_alloc(void)
+{
+ struct xthread_workqueue *ret;
+ pthread_t thread;
+
+ ret = malloc(sizeof(*ret));
+ if (ret) {
+ xthread_workqueue_init(ret);
+
+ pthread_mutex_lock(&ret->mutex);
+ if (pthread_create(&thread, NULL,
+ xthread_workqueue_worker,
+ ret) == 0) {
+ /* Wait for thread to start */
+ pthread_cond_wait(&ret->cond, &ret->mutex);
+ pthread_mutex_unlock(&ret->mutex);
+ return ret;
+ }
+ pthread_mutex_unlock(&ret->mutex);
+ xthread_workqueue_free(ret);
+ ret = NULL;
+ }
+ return NULL;
+}
+
+void xthread_work_run_sync(struct xthread_workqueue *wq,
+ void (*fn)(void *), void *data)
+{
+ struct xthread_work work = {
+ {
+ NULL,
+ fn,
+ data
+ },
+ PTHREAD_COND_INITIALIZER,
+ };
+ pthread_mutex_lock(&wq->mutex);
+ xthread_work_enqueue(wq, &work);
+ pthread_cond_wait(&work.cond, &wq->mutex);
+ pthread_mutex_unlock(&wq->mutex);
+ pthread_cond_destroy(&work.cond);
+}
+
+static void xthread_workqueue_do_chroot(void *data)
+{
+ const char *path = data;
+
+ if (unshare(CLONE_FS) != 0) {
+ xlog_err("unshare() failed: %m");
+ return;
+ }
+ if (chroot(path) != 0)
+ xlog_err("chroot() failed: %m");
+}
+
+void xthread_workqueue_chroot(struct xthread_workqueue *wq,
+ const char *path)
+{
+ xthread_work_run_sync(wq, xthread_workqueue_do_chroot, (void *)path);
+}
+
+#else
+
+struct xthread_workqueue {
+};
+
+static struct xthread_workqueue ret;
+
+struct xthread_workqueue *xthread_workqueue_alloc(void)
+{
+ return &ret;
+}
+
+void xthread_workqueue_shutdown(struct xthread_workqueue *wq)
+{
+}
+
+void xthread_work_run_sync(struct xthread_workqueue *wq,
+ void (*fn)(void *), void *data)
+{
+ fn(data);
+}
+
+void xthread_workqueue_chroot(struct xthread_workqueue *wq,
+ const char *path)
+{
+ xlog_err("Unable to run as chroot");
+}
+
+#endif /* defined(HAVE_SCHED_H) && defined(HAVE_LIBPTHREAD) && defined(HAVE_UNSHARE) */