From: Trond Myklebust <trondmy@gmail.com>
To: SteveD@redhat.com
Cc: linux-nfs@vger.kernel.org
Subject: [RFC PATCH v2 2/7] Add a simple workqueue mechanism
Date: Tue, 21 May 2019 08:46:56 -0400 [thread overview]
Message-ID: <20190521124701.61849-3-trond.myklebust@hammerspace.com> (raw)
In-Reply-To: <20190521124701.61849-2-trond.myklebust@hammerspace.com>
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>
---
aclocal/libpthread.m4 | 13 +-
configure.ac | 6 +-
support/include/Makefile.am | 1 +
support/include/workqueue.h | 18 +++
support/misc/Makefile.am | 2 +-
support/misc/workqueue.c | 228 ++++++++++++++++++++++++++++++++++++
utils/mountd/Makefile.am | 3 +-
7 files changed, 262 insertions(+), 9 deletions(-)
create mode 100644 support/include/workqueue.h
create mode 100644 support/misc/workqueue.c
diff --git a/aclocal/libpthread.m4 b/aclocal/libpthread.m4
index e87d2a0c2dc5..55e046e38cd1 100644
--- a/aclocal/libpthread.m4
+++ b/aclocal/libpthread.m4
@@ -3,11 +3,12 @@ dnl
AC_DEFUN([AC_LIBPTHREAD], [
dnl Check for library, but do not add -lpthreads to LIBS
- AC_CHECK_LIB([pthread], [pthread_create], [LIBPTHREAD=-lpthread],
- [AC_MSG_ERROR([libpthread not found.])])
- AC_SUBST(LIBPTHREAD)
-
- AC_CHECK_HEADERS([pthread.h], ,
- [AC_MSG_ERROR([libpthread headers not found.])])
+ AC_CHECK_LIB([pthread], [pthread_create],
+ [AC_DEFINE([HAVE_LIBPTHREAD], [1],
+ [Define to 1 if you have libpthread.])
+ AC_CHECK_HEADERS([pthread.h], [],
+ [AC_MSG_ERROR([libpthread headers not found.])])
+ AC_SUBST([LIBPTHREAD],[-lpthread])],
+ [$1])
])dnl
diff --git a/configure.ac b/configure.ac
index 4d7096193d0b..c6c2d73b06dd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -320,6 +320,10 @@ AC_CHECK_FUNC([getservbyname], ,
AC_CHECK_LIB([crypt], [crypt], [LIBCRYPT="-lcrypt"])
+AC_CHECK_HEADERS([sched.h], [], [])
+AC_CHECK_FUNCS([unshare], [] , [])
+AC_LIBPTHREAD([])
+
if test "$enable_nfsv4" = yes; then
dnl check for libevent libraries and headers
AC_LIBEVENT
@@ -417,7 +421,7 @@ if test "$enable_gss" = yes; then
AC_KERBEROS_V5
dnl Check for pthreads
- AC_LIBPTHREAD
+ AC_LIBPTHREAD([AC_MSG_ERROR([libpthread not found.])])
dnl librpcsecgss already has a dependency on libgssapi,
dnl but we need to make sure we get the right version
diff --git a/support/include/Makefile.am b/support/include/Makefile.am
index 599f500e2b40..df5e47836d29 100644
--- a/support/include/Makefile.am
+++ b/support/include/Makefile.am
@@ -19,6 +19,7 @@ noinst_HEADERS = \
sockaddr.h \
tcpwrapper.h \
v4root.h \
+ workqueue.h \
xio.h \
xlog.h \
xmalloc.h \
diff --git a/support/include/workqueue.h b/support/include/workqueue.h
new file mode 100644
index 000000000000..518be82f1b34
--- /dev/null
+++ b/support/include/workqueue.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2019 Trond Myklebust <trond.myklebust@hammerspace.com>
+ */
+#ifndef WORKQUEUE_H
+#define WORKQUEUE_H
+
+struct xthread_workqueue;
+
+struct xthread_workqueue *xthread_workqueue_alloc(void);
+void xthread_workqueue_shutdown(struct xthread_workqueue *wq);
+
+void xthread_work_run_sync(struct xthread_workqueue *wq,
+ void (*fn)(void *), void *data);
+
+void xthread_workqueue_chroot(struct xthread_workqueue *wq,
+ const char *path);
+
+#endif
diff --git a/support/misc/Makefile.am b/support/misc/Makefile.am
index 8936b0d64e45..d0bff8feb6ae 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 000000000000..b8d03446f2c7
--- /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) */
diff --git a/utils/mountd/Makefile.am b/utils/mountd/Makefile.am
index 73eeb3f35070..18610f18238c 100644
--- a/utils/mountd/Makefile.am
+++ b/utils/mountd/Makefile.am
@@ -19,7 +19,8 @@ mountd_LDADD = ../../support/export/libexport.a \
../../support/nfs/libnfs.la \
../../support/misc/libmisc.a \
$(OPTLIBS) \
- $(LIBBSD) $(LIBWRAP) $(LIBNSL) $(LIBBLKID) $(LIBTIRPC)
+ $(LIBBSD) $(LIBWRAP) $(LIBNSL) $(LIBBLKID) $(LIBTIRPC) \
+ $(LIBPTHREAD)
mountd_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS) \
-I$(top_builddir)/support/include \
-I$(top_srcdir)/support/export
--
2.21.0
next prev parent reply other threads:[~2019-05-21 12:49 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-05-21 12:46 [RFC PATCH v2 0/7] Add a root_dir option to nfs.conf Trond Myklebust
2019-05-21 12:46 ` [RFC PATCH v2 1/7] mountd: Ensure we don't share cache file descriptors among processes Trond Myklebust
2019-05-21 12:46 ` Trond Myklebust [this message]
2019-05-21 12:46 ` [RFC PATCH v2 3/7] Add utilities for resolving nfsd paths and stat()ing them Trond Myklebust
2019-05-21 12:46 ` [RFC PATCH v2 4/7] Add a helper to return the real path given an export entry Trond Myklebust
2019-05-21 12:46 ` [RFC PATCH v2 5/7] Add helpers to read/write to a file through the chrooted thread Trond Myklebust
2019-05-21 12:47 ` [RFC PATCH v2 6/7] Add support for the nfsd rootdir configuration option to rpc.mountd Trond Myklebust
2019-05-21 12:47 ` [RFC PATCH v2 7/7] Add support for the nfsd root directory to exportfs Trond Myklebust
2019-05-21 17:40 ` [RFC PATCH v2 0/7] Add a root_dir option to nfs.conf Chuck Lever
2019-05-21 18:17 ` Trond Myklebust
2019-05-21 18:59 ` Trond Myklebust
2019-05-21 19:06 ` Chuck Lever
2019-05-21 19:58 ` Trond Myklebust
2019-05-28 15:25 ` Steve Dickson
2019-05-28 16:44 ` Trond Myklebust
2019-05-28 16:47 ` Chuck Lever
2019-05-28 16:50 ` Trond Myklebust
2019-05-28 17:40 ` Steve Dickson
2019-05-28 18:19 ` Trond Myklebust
2019-05-28 19:33 ` Steve Dickson
2019-05-28 15:30 ` Chuck Lever
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190521124701.61849-3-trond.myklebust@hammerspace.com \
--to=trondmy@gmail.com \
--cc=SteveD@redhat.com \
--cc=linux-nfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).