summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2017-10-24 14:53:01 -0500
committerDavid Teigland <teigland@redhat.com>2017-10-27 10:11:17 -0500
commita41ffd52d6bf0c6357d25aade0d6d8ea0ad2431d (patch)
treeac37df32be1ff8c71adf65fee2a83f2f27351e1e
parentfdcc709ed0e5051f471ee64ac51f6c8e2ed941fc (diff)
downloadlvm2-a41ffd52d6bf0c6357d25aade0d6d8ea0ad2431d.tar.gz
io: add low level async io support
The interface consists of: - A context struct, one for the entire command. - An io struct, one per io operation (read). - dev_async_context_setup() creates an aio context. - dev_async_context_destroy() destroys an aio context. - dev_async_alloc_ios() allocates a specified number of io structs, along with an associated buffer for the data. - dev_async_free_ios() frees all the allocated io structs+buffers. - dev_async_io_get() gets an available io struct from those allocated in alloc_ios. If none are available, it will allocate a new io struct if under limit. - dev_async_io_put() puts a used io struct back into the set of unused io structs, making it available for get. - dev_async_read_submit() start an async read io. - dev_async_getevents() collect async io completions.
-rwxr-xr-xconfigure69
-rw-r--r--configure.in22
-rw-r--r--daemons/clvmd/Makefile.in4
-rw-r--r--include/configure.h.in3
-rw-r--r--lib/config/defaults.h2
-rw-r--r--lib/device/dev-io.c316
-rw-r--r--lib/device/device.h49
-rw-r--r--liblvm/Makefile.in4
-rw-r--r--make.tmpl.in1
-rw-r--r--scripts/Makefile.in4
-rw-r--r--tools/Makefile.in4
11 files changed, 478 insertions, 0 deletions
diff --git a/configure b/configure
index fc0a27a56..0b261bcb6 100755
--- a/configure
+++ b/configure
@@ -707,7 +707,9 @@ FSADM
ELDFLAGS
DM_LIB_PATCHLEVEL
DMEVENTD_PATH
+AIO_LIBS
DL_LIBS
+AIO
DEVMAPPER
DEFAULT_USE_LVMLOCKD
DEFAULT_USE_LVMPOLLD
@@ -954,6 +956,7 @@ enable_profiling
enable_testing
enable_valgrind_pool
enable_devmapper
+enable_aio
enable_lvmetad
enable_lvmpolld
enable_lvmlockd_sanlock
@@ -1692,6 +1695,7 @@ Optional Features:
--enable-testing enable testing targets in the makefile
--enable-valgrind-pool enable valgrind awareness of pools
--disable-devmapper disable LVM2 device-mapper interaction
+ --disable-aio disable async i/o
--enable-lvmetad enable the LVM Metadata Daemon
--enable-lvmpolld enable the LVM Polling Daemon
--enable-lvmlockd-sanlock
@@ -3179,6 +3183,7 @@ case "$host_os" in
LDDEPS="$LDDEPS .export.sym"
LIB_SUFFIX=so
DEVMAPPER=yes
+ AIO=yes
BUILD_LVMETAD=no
BUILD_LVMPOLLD=no
LOCKDSANLOCK=no
@@ -3198,6 +3203,7 @@ case "$host_os" in
CLDNOWHOLEARCHIVE=
LIB_SUFFIX=dylib
DEVMAPPER=yes
+ AIO=no
ODIRECT=no
DM_IOCTLS=no
SELINUX=no
@@ -11826,6 +11832,67 @@ $as_echo "#define DEVMAPPER_SUPPORT 1" >>confdefs.h
fi
################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use aio" >&5
+$as_echo_n "checking whether to use aio... " >&6; }
+# Check whether --enable-aio was given.
+if test "${enable_aio+set}" = set; then :
+ enableval=$enable_aio; AIO=$enableval
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $AIO" >&5
+$as_echo "$AIO" >&6; }
+
+if test "$AIO" = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for io_setup in -laio" >&5
+$as_echo_n "checking for io_setup in -laio... " >&6; }
+if ${ac_cv_lib_aio_io_setup+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-laio $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char io_setup ();
+int
+main ()
+{
+return io_setup ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_aio_io_setup=yes
+else
+ ac_cv_lib_aio_io_setup=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_aio_io_setup" >&5
+$as_echo "$ac_cv_lib_aio_io_setup" >&6; }
+if test "x$ac_cv_lib_aio_io_setup" = xyes; then :
+
+$as_echo "#define AIO_SUPPORT 1" >>confdefs.h
+
+ AIO_LIBS="-laio"
+ AIO_SUPPORT=yes
+else
+ AIO_LIBS=
+ AIO_SUPPORT=no
+fi
+
+fi
+
+################################################################################
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build LVMetaD" >&5
$as_echo_n "checking whether to build LVMetaD... " >&6; }
# Check whether --enable-lvmetad was given.
@@ -15777,6 +15844,8 @@ _ACEOF
+
+
################################################################################
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/dmfilemapd/Makefile daemons/lvmdbusd/Makefile daemons/lvmdbusd/path.py daemons/lvmetad/Makefile daemons/lvmpolld/Makefile daemons/lvmlockd/Makefile conf/Makefile conf/example.conf conf/lvmlocal.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile include/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/Makefile lib/cache_segtype/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/com.redhat.lvmdbus1.service scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cluster_activation_red_hat.sh scripts/lvm2_cluster_activation_systemd_red_hat.service scripts/lvm2_clvmd_systemd_red_hat.service scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmdbusd_systemd_red_hat.service scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmpolld_init_red_hat scripts/lvm2_lvmpolld_systemd_red_hat.service scripts/lvm2_lvmpolld_systemd_red_hat.socket scripts/lvm2_lvmlockd_systemd_red_hat.service scripts/lvm2_lvmlocking_systemd_red_hat.service scripts/lvm2_monitoring_init_red_hat scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_tmpfiles_red_hat.conf scripts/lvmdump.sh scripts/Makefile test/Makefile test/api/Makefile test/unit/Makefile tools/Makefile udev/Makefile unit-tests/datastruct/Makefile unit-tests/regex/Makefile unit-tests/mm/Makefile"
diff --git a/configure.in b/configure.in
index 7d4f5b307..e54b936d8 100644
--- a/configure.in
+++ b/configure.in
@@ -39,6 +39,7 @@ case "$host_os" in
LDDEPS="$LDDEPS .export.sym"
LIB_SUFFIX=so
DEVMAPPER=yes
+ AIO=yes
BUILD_LVMETAD=no
BUILD_LVMPOLLD=no
LOCKDSANLOCK=no
@@ -58,6 +59,7 @@ case "$host_os" in
CLDNOWHOLEARCHIVE=
LIB_SUFFIX=dylib
DEVMAPPER=yes
+ AIO=no
ODIRECT=no
DM_IOCTLS=no
SELINUX=no
@@ -1122,6 +1124,24 @@ if test "$DEVMAPPER" = yes; then
fi
################################################################################
+dnl -- Disable aio
+AC_MSG_CHECKING(whether to use aio)
+AC_ARG_ENABLE(aio,
+ AC_HELP_STRING([--disable-aio],
+ [disable async i/o]),
+ AIO=$enableval)
+AC_MSG_RESULT($AIO)
+
+if test "$AIO" = yes; then
+ AC_CHECK_LIB(aio, io_setup,
+ [AC_DEFINE([AIO_SUPPORT], 1, [Define to 1 if aio is available.])
+ AIO_LIBS="-laio"
+ AIO_SUPPORT=yes],
+ [AIO_LIBS=
+ AIO_SUPPORT=no ])
+fi
+
+################################################################################
dnl -- Build lvmetad
AC_MSG_CHECKING(whether to build LVMetaD)
AC_ARG_ENABLE(lvmetad,
@@ -2060,9 +2080,11 @@ AC_SUBST(DEFAULT_USE_LVMETAD)
AC_SUBST(DEFAULT_USE_LVMPOLLD)
AC_SUBST(DEFAULT_USE_LVMLOCKD)
AC_SUBST(DEVMAPPER)
+AC_SUBST(AIO)
AC_SUBST(DLM_CFLAGS)
AC_SUBST(DLM_LIBS)
AC_SUBST(DL_LIBS)
+AC_SUBST(AIO_LIBS)
AC_SUBST(DMEVENTD_PATH)
AC_SUBST(DM_LIB_PATCHLEVEL)
AC_SUBST(ELDFLAGS)
diff --git a/daemons/clvmd/Makefile.in b/daemons/clvmd/Makefile.in
index 7b1b49bf9..397592115 100644
--- a/daemons/clvmd/Makefile.in
+++ b/daemons/clvmd/Makefile.in
@@ -77,6 +77,10 @@ include $(top_builddir)/make.tmpl
LIBS += $(LVMINTERNAL_LIBS) -ldevmapper $(PTHREAD_LIBS)
CFLAGS += -fno-strict-aliasing $(EXTRA_EXEC_CFLAGS)
+ifeq ("@AIO@", "yes")
+ LIBS += $(AIO_LIBS)
+endif
+
INSTALL_TARGETS = \
install_clvmd
diff --git a/include/configure.h.in b/include/configure.h.in
index be2f66031..a4918071f 100644
--- a/include/configure.h.in
+++ b/include/configure.h.in
@@ -1,5 +1,8 @@
/* include/configure.h.in. Generated from configure.in by autoheader. */
+/* Define to 1 if aio is available. */
+#undef AIO_SUPPORT
+
/* Define to 1 to use libblkid detection of signatures when wiping. */
#undef BLKID_WIPING_SUPPORT
diff --git a/lib/config/defaults.h b/lib/config/defaults.h
index d9e19d971..8da8670d1 100644
--- a/lib/config/defaults.h
+++ b/lib/config/defaults.h
@@ -267,4 +267,6 @@
#define DEFAULT_THIN_POOL_AUTOEXTEND_THRESHOLD 100
#define DEFAULT_THIN_POOL_AUTOEXTEND_PERCENT 20
+#define DEFAULT_ASYNC_EVENTS 100
+
#endif /* _LVM_DEFAULTS_H */
diff --git a/lib/device/dev-io.c b/lib/device/dev-io.c
index 519b5c7e1..c320f1ebd 100644
--- a/lib/device/dev-io.c
+++ b/lib/device/dev-io.c
@@ -827,3 +827,319 @@ int dev_set(struct device *dev, uint64_t offset, size_t len, int value)
return (len == 0);
}
+
+#ifdef AIO_SUPPORT
+
+/*
+ * io_setup() wrapper:
+ * async_event_count is the max number of concurrent async
+ * i/os, i.e. the number of devices that can be read at once
+ *
+ * max_io_alloc_count: max number of aio structs to allocate,
+ * each with a buf_len size buffer.
+ *
+ * max_buf_alloc_bytes: max number of bytes to use for buffers
+ * attached to all aio structs; each aio struct gets a
+ * buf_len size buffer.
+ *
+ * When only max_io_alloc_count is set, it is used directly.
+ *
+ * When only max_buf_alloc_bytes is set, the number of aio
+ * structs is determined by this number divided by buf_len.
+ *
+ * When both are set, max_io_alloc_count is reduced, if needed,
+ * to whatever value max_buf_alloc_bytes would allow.
+ *
+ * When both are zero, there is no limit on the number of aio
+ * structs. If allocation fails for an aio struct or its buffer,
+ * the code should revert to synchronous io.
+ */
+
+struct dev_async_context *dev_async_context_setup(unsigned async_event_count,
+ unsigned max_io_alloc_count,
+ unsigned max_buf_alloc_bytes,
+ int buf_len)
+{
+ struct dev_async_context *ac;
+ unsigned nr_events = DEFAULT_ASYNC_EVENTS;
+ int count;
+ int error;
+
+ if (async_event_count)
+ nr_events = async_event_count;
+
+ if (!(ac = malloc(sizeof(struct dev_async_context))))
+ return_0;
+
+ memset(ac, 0, sizeof(struct dev_async_context));
+
+ dm_list_init(&ac->unused_ios);
+
+ error = io_setup(nr_events, &ac->aio_ctx);
+
+ if (error < 0) {
+ log_warn("WARNING: async io setup error %d with %u events.", error, nr_events);
+ free(ac);
+ return_0;
+ }
+
+
+ if (!max_io_alloc_count && !max_buf_alloc_bytes)
+ count = 0;
+ else if (!max_io_alloc_count && max_buf_alloc_bytes)
+ count = max_buf_alloc_bytes / buf_len;
+ else if (max_io_alloc_count && max_buf_alloc_bytes) {
+ if (max_io_alloc_count * buf_len > max_buf_alloc_bytes)
+ count = max_buf_alloc_bytes / buf_len;
+ } else
+ count = max_io_alloc_count;
+
+ ac->max_ios = count;
+ return ac;
+}
+
+void dev_async_context_destroy(struct dev_async_context *ac)
+{
+ io_destroy(ac->aio_ctx);
+ free(ac);
+}
+
+static struct dev_async_io *_async_io_alloc(int buf_len)
+{
+ struct dev_async_io *aio;
+ char *buf;
+ char **p_buf;
+
+ /*
+ * mem pool doesn't seem to work for this, probably because
+ * of the memalign that follows.
+ */
+ if (!(aio = malloc(sizeof(struct dev_async_io))))
+ return_0;
+
+ memset(aio, 0, sizeof(struct dev_async_io));
+
+ buf = NULL;
+ p_buf = &buf;
+
+ if (posix_memalign((void *)p_buf, getpagesize(), buf_len)) {
+ free(aio);
+ return_NULL;
+ }
+
+ memset(buf, 0, buf_len);
+
+ aio->buf = buf;
+ aio->buf_len = buf_len;
+ return aio;
+}
+
+static void _async_io_free(struct dev_async_io *aio)
+{
+ if (aio->buf)
+ free(aio->buf);
+ free(aio);
+}
+
+int dev_async_alloc_ios(struct dev_async_context *ac, int num, int buf_len, int *available)
+{
+ struct dev_async_io *aio;
+ int count;
+ int i;
+
+ /* FIXME: check if num wants more pre allocated? */
+ if (!dm_list_empty(&ac->unused_ios))
+ return 1;
+
+ /*
+ * When no limit is used and no pre-alloc number is set,
+ * then no ios are allocated up front, but the are
+ * allocated as needed in get().
+ */
+ if (!ac->max_ios && !num) {
+ *available = 1;
+ return 1;
+ }
+
+ if (num && !ac->max_ios)
+ count = num;
+ else if (!num && ac->max_ios)
+ count = ac->max_ios;
+ else if (num > ac->max_ios)
+ count = ac->max_ios;
+ else if (num < ac->max_ios)
+ count = num;
+ else
+ count = ac->max_ios;
+
+ for (i = 0; i < count; i++) {
+ if (!(aio = _async_io_alloc(buf_len))) {
+ ac->num_ios = i;
+ *available = i;
+ return 1;
+ }
+ dm_list_add(&ac->unused_ios, &aio->list);
+ }
+
+ ac->num_ios = count;
+ *available = count;
+ return 1;
+}
+
+void dev_async_free_ios(struct dev_async_context *ac)
+{
+ struct dev_async_io *aio, *aio2;
+
+ dm_list_iterate_items_safe(aio, aio2, &ac->unused_ios) {
+ dm_list_del(&aio->list);
+ _async_io_free(aio);
+ }
+}
+
+struct dev_async_io *dev_async_io_get(struct dev_async_context *ac, int buf_len)
+{
+ struct dm_list *aio_item;
+ struct dev_async_io *aio;
+
+ if (!(aio_item = dm_list_first(&ac->unused_ios)))
+ goto alloc_new;
+
+ aio = dm_list_item(aio_item, struct dev_async_io);
+ dm_list_del(&aio->list);
+ return aio;
+
+ alloc_new:
+ /* alloc on demand if there is no max or we have used less than max */
+ if (!ac->max_ios || (ac->num_ios < ac->max_ios)) {
+ if ((aio = _async_io_alloc(buf_len))) {
+ ac->num_ios++;
+ return aio;
+ }
+ }
+
+ return NULL;
+}
+
+void dev_async_io_put(struct dev_async_context *ac, struct dev_async_io *aio)
+{
+ if (!ac)
+ _async_io_free(aio);
+ else {
+ memset(aio->buf, 0, aio->buf_len);
+ aio->dev = NULL;
+ aio->len = 0;
+ aio->done = 0;
+ aio->result = 0;
+ dm_list_add(&ac->unused_ios, &aio->list);
+ }
+}
+
+/* io_submit() wrapper */
+
+int dev_async_read_submit(struct dev_async_context *ac, struct dev_async_io *aio,
+ struct device *dev, uint32_t len, uint64_t offset, int *nospace)
+{
+ struct iocb *iocb = &aio->iocb;
+ int error;
+
+ *nospace = 0;
+
+ if (len > aio->buf_len)
+ return_0;
+
+ aio->len = len;
+
+ iocb->data = aio;
+ iocb->aio_fildes = dev_fd(dev);
+ iocb->aio_lio_opcode = IO_CMD_PREAD;
+ iocb->u.c.buf = aio->buf;
+ iocb->u.c.nbytes = len;
+ iocb->u.c.offset = offset;
+
+ error = io_submit(ac->aio_ctx, 1, &iocb);
+ if (error == -EAGAIN)
+ *nospace = 1;
+ if (error < 0)
+ return 0;
+ return 1;
+}
+
+/* io_getevents() wrapper */
+
+int dev_async_getevents(struct dev_async_context *ac, int wait_count, struct timespec *timeout)
+{
+ int wait_nr;
+ int rv;
+ int i;
+
+ retry:
+ memset(&ac->events, 0, sizeof(ac->events));
+
+ if (wait_count >= MAX_GET_EVENTS)
+ wait_nr = MAX_GET_EVENTS;
+ else
+ wait_nr = wait_count;
+
+ rv = io_getevents(ac->aio_ctx, 1, wait_nr, (struct io_event *)&ac->events, timeout);
+
+ if (rv == -EINTR)
+ goto retry;
+ if (rv < 0)
+ return 0;
+ if (!rv)
+ return 1;
+
+ for (i = 0; i < rv; i++) {
+ struct iocb *iocb = ac->events[i].obj;
+ struct dev_async_io *aio = iocb->data;
+ aio->result = ac->events[i].res;
+ aio->done = 1;
+ }
+
+ return 1;
+}
+
+#else /* AIO_SUPPORT */
+
+struct dev_async_context *dev_async_context_setup(unsigned async_event_count,
+ unsigned max_io_alloc_count,
+ unsigned max_buf_alloc_bytes,
+ int buf_len)
+{
+ return NULL;
+}
+
+void dev_async_context_destroy(struct dev_async_context *ac)
+{
+}
+
+int dev_async_alloc_ios(struct dev_async_context *ac, int num, int buf_len, int *available)
+{
+ return 0;
+}
+
+void dev_async_free_ios(struct dev_async_context *ac)
+{
+}
+
+struct dev_async_io *dev_async_io_get(struct dev_async_context *ac, int buf_len)
+{
+ return NULL;
+}
+
+void dev_async_io_put(struct dev_async_context *ac, struct dev_async_io *aio)
+{
+}
+
+int dev_async_read_submit(struct dev_async_context *ac, struct dev_async_io *aio,
+ struct device *dev, uint32_t len, uint64_t offset, int *nospace)
+{
+ return 0;
+}
+
+int dev_async_getevents(struct dev_async_context *ac, int wait_count, struct timespec *timeout)
+{
+ return 0;
+}
+
+#endif /* AIO_SUPPORT */
diff --git a/lib/device/device.h b/lib/device/device.h
index fa03f1061..328e48421 100644
--- a/lib/device/device.h
+++ b/lib/device/device.h
@@ -19,6 +19,7 @@
#include "uuid.h"
#include <fcntl.h>
+#include <libaio.h>
#define DEV_ACCESSED_W 0x00000001 /* Device written to? */
#define DEV_REGULAR 0x00000002 /* Regular file? */
@@ -91,6 +92,32 @@ struct device_area {
};
/*
+ * We'll collect the results of this many async reads
+ * in one system call. It shouldn't matter much what
+ * number is used here.
+ */
+#define MAX_GET_EVENTS 16
+
+struct dev_async_context {
+ io_context_t aio_ctx;
+ struct io_event events[MAX_GET_EVENTS]; /* for processing completions */
+ struct dm_list unused_ios; /* unused/available aio structcs */
+ int num_ios; /* number of allocated aio structs */
+ int max_ios; /* max number of aio structs to allocate */
+};
+
+struct dev_async_io {
+ struct dm_list list;
+ struct iocb iocb;
+ struct device *dev;
+ char *buf;
+ uint32_t buf_len; /* size of buf */
+ uint32_t len; /* size of submitted io */
+ int done;
+ int result;
+};
+
+/*
* Support for external device info.
*/
const char *dev_ext_name(struct device *dev);
@@ -144,4 +171,26 @@ void dev_destroy_file(struct device *dev);
/* Return a valid device name from the alias list; NULL otherwise */
const char *dev_name_confirmed(struct device *dev, int quiet);
+struct dev_async_context *dev_async_context_setup(unsigned async_event_count,
+ unsigned max_io_alloc_count,
+ unsigned max_buf_alloc_bytes,
+ int buf_len);
+void dev_async_context_destroy(struct dev_async_context *ac);
+
+/* allocate aio structs (with buffers), up to the max specified during context setup */
+int dev_async_alloc_ios(struct dev_async_context *ac, int num, int buf_len, int *available);
+
+/* free aio structs (and buffers) */
+void dev_async_free_ios(struct dev_async_context *ac);
+
+/* get an available aio struct (with buffer) */
+struct dev_async_io *dev_async_io_get(struct dev_async_context *ac, int buf_len);
+
+/* make an aio struct (with buffer) available for use (by another get) */
+void dev_async_io_put(struct dev_async_context *ac, struct dev_async_io *aio);
+
+int dev_async_read_submit(struct dev_async_context *ac, struct dev_async_io *aio,
+ struct device *dev, uint32_t len, uint64_t offset, int *nospace);
+int dev_async_getevents(struct dev_async_context *ac, int wait_count, struct timespec *timeout);
+
#endif
diff --git a/liblvm/Makefile.in b/liblvm/Makefile.in
index 6d0325c60..1d1498bbc 100644
--- a/liblvm/Makefile.in
+++ b/liblvm/Makefile.in
@@ -45,6 +45,10 @@ include $(top_builddir)/make.tmpl
LDFLAGS += -L$(top_builddir)/lib -L$(top_builddir)/daemons/dmeventd
LIBS += $(LVMINTERNAL_LIBS) -ldevmapper
+ifeq ("@AIO@", "yes")
+ LIBS += $(AIO_LIBS)
+endif
+
.PHONY: install_dynamic install_static install_include install_pkgconfig
INSTALL_TYPE = install_dynamic
diff --git a/make.tmpl.in b/make.tmpl.in
index 65362d87c..1040b6358 100644
--- a/make.tmpl.in
+++ b/make.tmpl.in
@@ -64,6 +64,7 @@ LDDEPS += @LDDEPS@
LIB_SUFFIX = @LIB_SUFFIX@
LVMINTERNAL_LIBS = -llvm-internal $(DMEVENT_LIBS) $(DAEMON_LIBS) $(SYSTEMD_LIBS) $(UDEV_LIBS) $(DL_LIBS) $(BLKID_LIBS)
DL_LIBS = @DL_LIBS@
+AIO_LIBS = @AIO_LIBS@
RT_LIBS = @RT_LIBS@
M_LIBS = @M_LIBS@
PTHREAD_LIBS = @PTHREAD_LIBS@
diff --git a/scripts/Makefile.in b/scripts/Makefile.in
index d06766f67..767b89bca 100644
--- a/scripts/Makefile.in
+++ b/scripts/Makefile.in
@@ -31,6 +31,10 @@ endif
LVMLIBS = @LVM2APP_LIB@ -ldevmapper
endif
+ifeq ("@AIO@", "yes")
+ LVMLIBS += $(AIO_LIBS)
+endif
+
LVM_SCRIPTS = lvmdump.sh lvmconf.sh
DM_SCRIPTS =
diff --git a/tools/Makefile.in b/tools/Makefile.in
index de5b628f8..adf9294e0 100644
--- a/tools/Makefile.in
+++ b/tools/Makefile.in
@@ -109,6 +109,10 @@ ifeq ("@CMDLIB@", "yes")
INSTALL_LVM_TARGETS += $(INSTALL_CMDLIB_TARGETS)
endif
+ifeq ("@AIO@", "yes")
+ LVMLIBS += $(AIO_LIBS)
+endif
+
EXPORTED_HEADER = $(srcdir)/lvm2cmd.h
EXPORTED_FN_PREFIX = lvm2