On Thu, Oct 15, 2020 at 06:21:38PM +1100, Dave Chinner wrote: > From: Dave Chinner <dchinner@xxxxxxxxxx> > > This is needed for the kernel buffer cache conversion to be able > to wait on IO synchrnously. It is implemented with pthread mutexes > and conditional variables. > > Signed-off-by: Dave Chinner <dchinner@xxxxxxxxxx> > --- > include/Makefile | 1 + > include/completion.h | 61 ++++++++++++++++++++++++++++++++++++++++++++ > include/libxfs.h | 1 + > libxfs/libxfs_priv.h | 1 + > 4 files changed, 64 insertions(+) > create mode 100644 include/completion.h > > diff --git a/include/Makefile b/include/Makefile > index f7c40a5ce1a1..98031e70fa0d 100644 > --- a/include/Makefile > +++ b/include/Makefile > @@ -12,6 +12,7 @@ LIBHFILES = libxfs.h \ > atomic.h \ > bitops.h \ > cache.h \ > + completion.h \ > hlist.h \ > kmem.h \ > list.h \ > diff --git a/include/completion.h b/include/completion.h > new file mode 100644 > index 000000000000..92194c3f1484 > --- /dev/null > +++ b/include/completion.h > @@ -0,0 +1,61 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (c) 2019 RedHat, Inc. > + * All Rights Reserved. > + */ > +#ifndef __LIBXFS_COMPLETION_H__ > +#define __LIBXFS_COMPLETION_H__ > + > +/* > + * This implements kernel compatible completion semantics. This is slightly > + * different to the way pthread conditional variables work in that completions > + * can be signalled before the waiter tries to wait on the variable. In the > + * pthread case, the completion is ignored and the waiter goes to sleep, whilst > + * the kernel will see that the completion has already been completed and so > + * will not block. This is handled through the addition of the the @signalled > + * flag in the struct completion. Hmm... do any of the existing pthread_cond_t users need these semantics? I suspect the ones in scrub/vfs.c might actually be vulnerable to the signal-before-wait race that this completion structure solves. In any case, seeing as this primitive isn't inherent to the xfs disk format, maybe these new concurrency management things belong in libfrog? --D > + */ > +struct completion { > + pthread_mutex_t lock; > + pthread_cond_t cond; > + bool signalled; /* for kernel completion behaviour */ > + int waiters; > +}; > + > +static inline void > +init_completion(struct completion *w) > +{ > + pthread_mutex_init(&w->lock, NULL); > + pthread_cond_init(&w->cond, NULL); > + w->signalled = false; > +} > + > +static inline void > +complete(struct completion *w) > +{ > + pthread_mutex_lock(&w->lock); > + w->signalled = true; > + pthread_cond_broadcast(&w->cond); > + pthread_mutex_unlock(&w->lock); > +} > + > +/* > + * Support for mulitple waiters requires that we count the number of waiters > + * we have and only clear the signalled variable once all those waiters have > + * been woken. > + */ > +static inline void > +wait_for_completion(struct completion *w) > +{ > + pthread_mutex_lock(&w->lock); > + if (!w->signalled) { > + w->waiters++; > + pthread_cond_wait(&w->cond, &w->lock); > + w->waiters--; > + } > + if (!w->waiters) > + w->signalled = false; > + pthread_mutex_unlock(&w->lock); > +} > + > +#endif /* __LIBXFS_COMPLETION_H__ */ > diff --git a/include/libxfs.h b/include/libxfs.h > index caf4a5139469..d03ec8aeaf5c 100644 > --- a/include/libxfs.h > +++ b/include/libxfs.h > @@ -19,6 +19,7 @@ > #include "libfrog/radix-tree.h" > #include "atomic.h" > #include "spinlock.h" > +#include "completion.h" > > #include "xfs_types.h" > #include "xfs_fs.h" > diff --git a/libxfs/libxfs_priv.h b/libxfs/libxfs_priv.h > index e134f65c5dd1..5cbc4fe69732 100644 > --- a/libxfs/libxfs_priv.h > +++ b/libxfs/libxfs_priv.h > @@ -49,6 +49,7 @@ > #include "libfrog/radix-tree.h" > #include "atomic.h" > #include "spinlock.h" > +#include "completion.h" > > #include "xfs_types.h" > #include "xfs_arch.h" > -- > 2.28.0 >