From e78e29c231481683c7e72450eeeb1b75b1109b2c Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Tue, 6 Aug 2024 22:10:13 +0200 Subject: [PATCH] linux: disable SQPOLL io_uring by default (#4492) The SQPOLL io_uring instance wasn't providing consistent behaviour to users depending on kernel versions, load shape, ... creating issues difficult to track and fix. Don't use this ring by default but allow enabling it by calling `uv_loop_configure()` with `UV_LOOP_ENABLE_IO_URING_SQPOLL`. --- docs/src/fs.rst | 5 ++++- docs/src/loop.rst | 5 +++++ include/uv.h | 4 +++- src/unix/internal.h | 3 ++- src/unix/linux.c | 8 ++++++++ src/unix/loop.c | 8 ++++++++ 6 files changed, 30 insertions(+), 3 deletions(-) diff --git a/docs/src/fs.rst b/docs/src/fs.rst index c039a8e68..32cf126c7 100644 --- a/docs/src/fs.rst +++ b/docs/src/fs.rst @@ -16,7 +16,10 @@ Starting with libuv v1.45.0, some file operations on Linux are handed off to `io_uring ` when possible. Apart from a (sometimes significant) increase in throughput there should be no change in observable behavior. Libuv reverts to using its threadpool when the necessary -kernel features are unavailable or unsuitable. +kernel features are unavailable or unsuitable. Starting with libuv v1.49.0 this +behavior was reverted and Libuv on Linux by default will be using the threadpool +again. In order to enable io_uring the :c:type:`uv_loop_t` instance must be +configured with the :c:type:`UV_LOOP_ENABLE_IO_URING_SQPOLL` option. .. note:: On Windows `uv_fs_*` functions use utf-8 encoding. diff --git a/docs/src/loop.rst b/docs/src/loop.rst index 0f5ddfb3c..dc26e654e 100644 --- a/docs/src/loop.rst +++ b/docs/src/loop.rst @@ -73,8 +73,13 @@ API This option is necessary to use :c:func:`uv_metrics_idle_time`. + - UV_LOOP_ENABLE_IO_URING_SQPOLL: Enable SQPOLL io_uring instance to handle + asynchronous file system operations. + .. versionchanged:: 1.39.0 added the UV_METRICS_IDLE_TIME option. + .. versionchanged:: 1.49.0 added the UV_LOOP_ENABLE_IO_URING_SQPOLL option. + .. c:function:: int uv_loop_close(uv_loop_t* loop) Releases all internal loop resources. Call this function only when the loop diff --git a/include/uv.h b/include/uv.h index 44473fce8..9e450c511 100644 --- a/include/uv.h +++ b/include/uv.h @@ -260,7 +260,9 @@ typedef struct uv_metrics_s uv_metrics_t; typedef enum { UV_LOOP_BLOCK_SIGNAL = 0, - UV_METRICS_IDLE_TIME + UV_METRICS_IDLE_TIME, + UV_LOOP_USE_IO_URING_SQPOLL +#define UV_LOOP_USE_IO_URING_SQPOLL UV_LOOP_USE_IO_URING_SQPOLL } uv_loop_option; typedef enum { diff --git a/src/unix/internal.h b/src/unix/internal.h index a8ff39094..8055730a1 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -157,7 +157,8 @@ typedef struct uv__stream_queued_fds_s uv__stream_queued_fds_t; /* loop flags */ enum { UV_LOOP_BLOCK_SIGPROF = 0x1, - UV_LOOP_REAP_CHILDREN = 0x2 + UV_LOOP_REAP_CHILDREN = 0x2, + UV_LOOP_ENABLE_IO_URING_SQPOLL = 0x4 }; /* flags of excluding ifaddr */ diff --git a/src/unix/linux.c b/src/unix/linux.c index ad07430e3..a5f74e890 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -761,6 +761,14 @@ static struct uv__io_uring_sqe* uv__iou_get_sqe(struct uv__iou* iou, * initialization failed. Anything else is a valid ring file descriptor. */ if (iou->ringfd == -2) { + /* By default, the SQPOLL is not created. Enable only if the loop is + * configured with UV_LOOP_USE_IO_URING_SQPOLL. + */ + if ((loop->flags & UV_LOOP_ENABLE_IO_URING_SQPOLL) == 0) { + iou->ringfd = -1; + return NULL; + } + uv__iou_init(loop->backend_fd, iou, 64, UV__IORING_SETUP_SQPOLL); if (iou->ringfd == -2) iou->ringfd = -1; /* "failed" */ diff --git a/src/unix/loop.c b/src/unix/loop.c index a9468e8e1..179ee999d 100644 --- a/src/unix/loop.c +++ b/src/unix/loop.c @@ -217,6 +217,14 @@ int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) { return 0; } +#if defined(__linux__) + if (option == UV_LOOP_USE_IO_URING_SQPOLL) { + loop->flags |= UV_LOOP_ENABLE_IO_URING_SQPOLL; + return 0; + } +#endif + + if (option != UV_LOOP_BLOCK_SIGNAL) return UV_ENOSYS;